package net.sf.thingamablog.gui.app; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Event; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Date; import java.util.Enumeration; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.ScrollPaneConstants; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.event.HyperlinkEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import net.atlanticbb.tantlinger.i18n.I18n; import net.atlanticbb.tantlinger.io.IOUtils; import net.atlanticbb.tantlinger.ui.UIUtils; import net.atlanticbb.tantlinger.ui.text.TextEditPopupManager; import net.sf.thingamablog.SwingWorker; import net.sf.thingamablog.TBGlobals; import net.sf.thingamablog.backend.HSQLDatabaseBackend; import net.sf.thingamablog.blog.ArchiveRange; import net.sf.thingamablog.blog.BackendException; import net.sf.thingamablog.blog.BlogEntry; import net.sf.thingamablog.blog.PingService; import net.sf.thingamablog.blog.TBWeblog; import net.sf.thingamablog.blog.Template; import net.sf.thingamablog.blog.Weblog; import net.sf.thingamablog.blog.WeblogList; import net.sf.thingamablog.feed.Feed; import net.sf.thingamablog.feed.FeedBackendException; import net.sf.thingamablog.feed.FeedFolder; import net.sf.thingamablog.feed.FeedItem; import net.sf.thingamablog.feed.UpdateProgress; import net.sf.thingamablog.gui.CustomFileFilter; import net.sf.thingamablog.gui.GUILoginPrompt; import net.sf.thingamablog.gui.ImageViewerDialog; import net.sf.thingamablog.gui.JSplash; import net.sf.thingamablog.gui.LabelledItemPanel; import net.sf.thingamablog.gui.TBAbout; import net.sf.thingamablog.gui.TBHelpAction; import net.sf.thingamablog.gui.UpdatableAction; import net.sf.thingamablog.gui.ViewerPane; import net.sf.thingamablog.gui.editor.EntryEditor; import net.sf.thingamablog.gui.editor.HTMLEditor; import net.sf.thingamablog.gui.properties.TBWizardDialog; import net.sf.thingamablog.gui.properties.WeblogPropertiesDialogFactory; import net.sf.thingamablog.gui.table.JSortTable; import net.sf.thingamablog.transport.LoginFactory; import net.sf.thingamablog.xml.OPMLImportExport; import net.sf.thingamablog.xml.RSSImportExport; import net.sf.thingamablog.xml.TBPersistFactory; import org.jdesktop.jdic.desktop.Desktop; import com.l2fprod.common.swing.JDirectoryChooser; /** * @author Bob Tantlinger * * * */ public class ThingamablogFrame extends JFrame { /** * */ private static final long serialVersionUID = 1L; private static final I18n i18n = I18n.getInstance("net.sf.thingamablog.gui.app"); //$NON-NLS-1$ private static Logger logger = Logger.getLogger("net.sf.thingamablog.gui.app"); //$NON-NLS-1$ private final JFrame FRAME = this; private static final Image ICON = UIUtils.getIcon(UIUtils.X16, "tamb.png").getImage(); //$NON-NLS-1$ private Dimension editorSize = new Dimension(640, 480); //private boolean isEditorWordWrap = true; //publish type constants //private static int PUB_CURRENT = 0; private static int PUB_CHANGED = 1; private static int PUB_ALL = 2; private static int PING_ONLY = 3; private static final int ITEM_VIEW = -1; private static final int ENTRY_VIEW = -2; private int tableView = ENTRY_VIEW; //private int curLayoutStyle = TBGlobals.getLayoutStyle(); private JPanel contentPanel; private JPanel blogTreePanel; private JPanel feedTreePanel; private JSplitPane tableViewerDivider; private JSplitPane hSplitPane; private JSplitPane feedSplitPane; private JPanel viewerPanel; private CardLayout viewerPanelLayout = new CardLayout(); private HTMLOptionsPane htmlOptionsPane; private final String HTML_VIEW = "HTML_VIEW"; //$NON-NLS-1$ private final String TABLE_VIEW = "TABLE_VIEW"; //$NON-NLS-1$ private JTree blogTree; private JTree feedTree; private WeblogTreeModel weblogTreeModel; private FeedTreeModel feedTreeModel; private ViewerPane viewerPane; private TBViewerPaneModel viewerPaneModel = new TBViewerPaneModel(); private JSortTable table; private TBTableColumnModel tableColumnModel = new TBTableColumnModel(); private WeblogTableModel blogTableModel = new WeblogTableModel(); private FeedTableModel feedTableModel = new FeedTableModel(); private boolean sortAscending; //keeps track of the menu sort order //private JMenu sortMenuItem; //menu item that contains the sort menu private JMenu sortMenu; //menu to sort the table cols private HSQLDatabaseBackend backend; private JPopupMenu blogTreePopup = null; private JPopupMenu feedTreePopup = null; private JPopupMenu tablePopup = null; //private JPopupMenu viewerPopup = null; private StatusBar statusBar; private WeblogList weblogList = new WeblogList(); private UpdateMonitor updateMonitor = new UpdateMonitor(); //toolbar button for starting/cancelling feed updates private AbstractButton updateButton = new JButton(); private Action openDBAction; private Action newDBAction; private UpdateAllFeedsAction updateAllFeedsAction; private Action updateCurFeedAction; private Action updateFolderAction; private Action renameFeedFolderAction; private Action deleteFromFeedTreeAction; private Action markCurFeedReadAction; private Action markCurFeedUnreadAction; private Action markSelItemsReadAction; private Action markSelItemsUnreadAction; private Action newFeedFolderAction; private Action newFeedAction; private Action feedPropertiesAction; private Action importFeedFolderAction; private Action exportFeedFolderAction; private Action refreshBlogTreeAction = new RefreshBlogTreeAction(); private Action openFolderAction; private Action newEntryAction; private Action newEntryFromItemAction; private Action editEntryAction; private Action deleteEntriesAction; private Action weblogPropertiesAction; private Action editTemplateAction; private Action exportWeblogToRSSAction; private Action importEntriesFromFeedAction; private Action exportTemplatesAction; //private Action importLegacyWeblogAction; private Action newWeblogAction; private Action deleteWeblogAction; private Action importFileAction; private Action newWebFolderAction; private Action renameFileAction; private Action deleteFileAction; private Action openFileAction; private Action nextAction; private Action prevAction; private Action nextUnreadAction; private Action searchAction; private Action findEntriesAction; private Action findItemsAction; private Action publishAction; private Action publishAllAction; private Action weblogPingAction; private Action importFromEmailAction; private Action viewWeblogAction; protected Action showTasksAction; private Vector actions = new Vector(20, 5); private FeedTreeMoveHandler moveHandler; private FeedFolder feedRoot = new FeedFolder(i18n.str("my_subscriptions")); //$NON-NLS-1$ private Feed lastSelFeed; private Weblog curSelWeblog; private Weblog curViewWeblog; private TBSearchDialog searchDialog; private File curDB; private boolean isDBOpen; private boolean isAppOpen = false; private javax.swing.Timer feedUpdateTimer; private javax.swing.Timer mailCheckTimer; private TaskDialog taskDialog; public ThingamablogFrame() { // give the user something to look at while we're loading the app if(TBGlobals.isStartWithSplash()) { JSplash ss = new JSplash(this, UIUtils.MISC + "splash.gif", 6000); //$NON-NLS-1$ ss.setVisible(true); } Runtime.getRuntime().addShutdownHook(new MyShutdownHook()); tableColumnModel.loadColumnData(); setIconImage(ICON); initActions(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { closeApp(true); } }); //init components contentPanel = new JPanel(new BorderLayout()); blogTreePanel = new JPanel(new BorderLayout()); feedTreePanel = new JPanel(new BorderLayout()); tableViewerDivider = new JSplitPane(JSplitPane.VERTICAL_SPLIT); hSplitPane = new JSplitPane(); feedSplitPane = new JSplitPane(); viewerPane = new ViewerPane(); viewerPane.setModel(viewerPaneModel); statusBar = new StatusBar(this); table = new JSortTable(); table.setColumnModel(tableColumnModel); table.setModel(blogTableModel); tableView = ENTRY_VIEW; table.getSelectionModel().addListSelectionListener(new TableSelectionHandler()); table.addMouseListener(new PopupMenuListener()); table.setColumnSelectionAllowed(false); table.setShowGrid(false); table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); table.setIntercellSpacing(new Dimension(0, 0)); table.addMouseListener(new TableClickHandler()); FocusListener focusListener = new TreeFocusListener(); weblogTreeModel = new WeblogTreeModel(weblogList); blogTree = new JTree(weblogTreeModel) { /** * */ private static final long serialVersionUID = 1L; public String getToolTipText(MouseEvent event) { Point point = event.getPoint(); TreePath path = getPathForLocation(point.x, point.y); if(path == null) { return null; } if(path.getLastPathComponent() instanceof Weblog) { Weblog b = (Weblog)path.getLastPathComponent(); String tttext = "<html>" + b.getTitle(); //$NON-NLS-1$ if(b.isPublishFailed()) tttext += "<p><b>" + i18n.str("publish_failed_tooltip") + "</p></b>"; //$NON-NLS-1$ if(b.isMailCheckFailed()) tttext += "<p><b>" + i18n.str("mail_check_failed_tooltip") + "</p></b>"; //$NON-NLS-1$ tttext += "</html>"; //$NON-NLS-1$ return tttext; } return super.getToolTipText(event); } }; ToolTipManager toolTipManager = ToolTipManager.sharedInstance(); toolTipManager.setInitialDelay(1000); toolTipManager.registerComponent(blogTree); blogTree.setCellRenderer(new WeblogTreeCellRenderer()); blogTree.addTreeSelectionListener(new TreeSelectionHandler()); blogTree.addMouseListener(new PopupMenuListener()); blogTree.addMouseListener(new BlogTreeClickHandler()); blogTreePanel.add(new JScrollPane(blogTree)); blogTree.addFocusListener(focusListener); feedTreeModel = new FeedTreeModel(feedRoot); feedTree = new JTree(feedTreeModel); feedTree.setCellRenderer(new FeedTreeCellRenderer()); feedTree.addTreeSelectionListener(new TreeSelectionHandler()); feedTree.addMouseListener(new PopupMenuListener()); moveHandler = new FeedTreeMoveHandler(feedTree, this); JToolBar feedToolBar = new JToolBar(SwingConstants.HORIZONTAL); feedToolBar.setFloatable(false); feedToolBar.putClientProperty("JToolBar.isRollover", Boolean.TRUE); //$NON-NLS-1$ UIUtils.addToolBarButton(feedToolBar, newFeedFolderAction); UIUtils.addToolBarButton(feedToolBar, newFeedAction); UIUtils.addToolBarButton(feedToolBar, deleteFromFeedTreeAction); JPanel feedUpperPanel = new JPanel(new BorderLayout()); JLabel feedUpperPanelLabel = new JLabel(i18n.str("news_feeds")); //$NON-NLS-1$ feedUpperPanelLabel.setIcon(UIUtils.getIcon(UIUtils.X16, "feed_icon.png")); //$NON-NLS-1$ feedUpperPanelLabel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0)); feedUpperPanel.add(feedUpperPanelLabel, BorderLayout.CENTER); feedUpperPanel.add(feedToolBar, BorderLayout.EAST); feedTreePanel.add(feedUpperPanel, BorderLayout.NORTH); feedTreePanel.add(new JScrollPane(feedTree), BorderLayout.CENTER); feedTree.addFocusListener(focusListener); /*viewerPane.getJEditorPane().addMouseListener(new PopupMenuListener()); viewerPopup = new JPopupMenu(); viewerPopup.add(viewerPane.getCopyAction()); viewerPopup.add(viewerPane.getSelectAllAction());*/ //Backackground has to be set to the table color JScrollPane scroller = new JScrollPane(table); scroller.getViewport().setBackground(table.getBackground()); scroller.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); //setAutoResizeMode() has to be called after the table is added table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); tableViewerDivider.setTopComponent(scroller); tableViewerDivider.setBottomComponent(viewerPane); htmlOptionsPane = new HTMLOptionsPane(); viewerPanel = new JPanel(viewerPanelLayout); viewerPanel.add(tableViewerDivider, TABLE_VIEW); viewerPanel.add(htmlOptionsPane, HTML_VIEW); viewerPanelLayout.show(viewerPanel, HTML_VIEW); layoutContentPanel(TBGlobals.getLayoutStyle()); getContentPane().add(createToolBar(), BorderLayout.NORTH); getContentPane().add(contentPanel, BorderLayout.CENTER); getContentPane().add(statusBar, BorderLayout.SOUTH); setJMenuBar(createMenuBar()); //searchDialog = new TBSearchDialog(this, weblogList, feedRoot); TODO //searchDialog.addActionListener(new FindHandler()); loadProperties(); updateActions(); feedUpdateTimer = new javax.swing.Timer( TBGlobals.getFeedUpdateInterval(), new TimerHandler()); mailCheckTimer = new javax.swing.Timer(10000, new ActionListener() { public void actionPerformed(ActionEvent e) { //System.err.println("firing timer"); if(!isCheckingEmail) { Weblog b = getBlogMostOverdueForEmailCheck(); //System.err.println(b); if(b != null) { importEntriesFromEmail(b); } } } }); if(TBGlobals.isStartWithLastDatabase() && TBGlobals.getLastOpenedDatabase() != null) { openDB(new File(TBGlobals.getLastOpenedDatabase())); } else blogTree.setSelectionRow(0); isAppOpen = true; } private void layoutContentPanel(int style) { contentPanel.removeAll(); if(style == TBGlobals.THREE_COL) { feedSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT); //feedSplitPane.setLeftComponent(tableViewerDivider); feedSplitPane.setLeftComponent(viewerPanel); feedSplitPane.setRightComponent(feedTreePanel); hSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT); hSplitPane.setLeftComponent(blogTreePanel); hSplitPane.setRightComponent(feedSplitPane); hSplitPane.setDividerLocation(200); feedSplitPane.setDividerLocation(getWidth() - 300); } else { feedSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); feedSplitPane.setTopComponent(blogTreePanel); feedSplitPane.setBottomComponent(feedTreePanel); feedSplitPane.setOneTouchExpandable(true); feedSplitPane.setDividerLocation(contentPanel.getHeight() / 2); JPanel leftPanel = new JPanel(new BorderLayout()); leftPanel.add(feedSplitPane); hSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT); hSplitPane.setLeftComponent(leftPanel); //hSplitPane.setRightComponent(tableViewerDivider); hSplitPane.setRightComponent(viewerPanel); hSplitPane.setDividerLocation(200); } feedSplitPane.setOneTouchExpandable(true); hSplitPane.setOneTouchExpandable(true); contentPanel.add(hSplitPane); hSplitPane.resetToPreferredSizes(); repaint(); taskDialog = new TaskDialog(FRAME); } /** * Overriden from super class to check if this is the first run */ public void setVisible(boolean b) { super.setVisible(b); if(b) checkIfFirstRun(); } private void checkIfFirstRun() { File f = new File(TBGlobals.PROP_FILE); //check if the properties file exists. //If it doesn't then this is likely the first run if(f.exists()) //not the first run so just return return; //This is the first run String msg = i18n.str("first_run_prompt"); //$NON-NLS-1$ int r = JOptionPane.showConfirmDialog( FRAME, msg, i18n.str("confirm"), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$ if(r == JOptionPane.YES_OPTION) createNewDatabase(); } private void createNewDatabase() { JDirectoryChooser fc = new JDirectoryChooser(); fc.setAccessory(new JLabel("<html>" + i18n.str("new_database_prompt") + "</html>")); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fc.setDialogTitle(i18n.str("new_database_title")); //$NON-NLS-1$ int r = fc.showDialog(FRAME, i18n.str("ok")); //$NON-NLS-1$ if(r == JFileChooser.CANCEL_OPTION) return; File dir = fc.getSelectedFile(); System.out.println(dir); if(dir == null || dir.isFile() || !dir.exists()) { dir = fc.getCurrentDirectory(); } File xml = new File(dir, TBGlobals.USER_XML_FILENAME); if(xml.exists()) { JOptionPane.showMessageDialog(FRAME, i18n.str("db_exists_prompt"), i18n.str("warning"), //$NON-NLS-1$ //$NON-NLS-2$ JOptionPane.WARNING_MESSAGE); return; } File tmplXML = new File(TBGlobals.DEFAULT_TMPL_DIR, TBGlobals.USER_XML_FILENAME); try { IOUtils.copy(tmplXML, xml); } catch(IOException e) { UIUtils.showError(FRAME, e); } openDB(dir); } private void openDB(final File dir) { final File userXML = new File(dir, TBGlobals.USER_XML_FILENAME); SwingWorker worker = new SwingWorker() { public Object construct() { try { isDBOpen = false; if(backend != null) backend.shutdown(); else backend = new HSQLDatabaseBackend(); curDB = dir; backend.connectToDB(curDB); //String xmlPath = curDB.getAbsolutePath() + // TBGlobals.SEP + TBGlobals.USER_XML_FILENAME; String xmlPath = userXML.getAbsolutePath(); feedRoot = new FeedFolder( i18n.str("my_subscriptions")); //$NON-NLS-1$ weblogList = new WeblogList(); System.out.println("LOADING DATA"); //$NON-NLS-1$ TBPersistFactory.loadData(xmlPath, weblogList, feedRoot, backend, backend); System.out.println("DONE LOADING DATA"); //$NON-NLS-1$ isDBOpen = true; } catch(Exception ex) { logger.log(Level.WARNING, ex.getMessage(), ex); ex.printStackTrace(); return ex; } return new Boolean(isDBOpen); } public void finished() { Object obj = get(); if(obj instanceof Exception) { Exception exc = (Exception)obj; UIUtils.showError(FRAME, i18n.str("error"), exc); //$NON-NLS-1$ } else if(obj == null || obj.toString().equals(false + "")) //$NON-NLS-1$ { UIUtils.showError(FRAME, i18n.str("unable_to_open_database")); //$NON-NLS-1$ //return; } feedTreeModel = new FeedTreeModel(feedRoot); weblogTreeModel = new WeblogTreeModel(weblogList); for(int i = 0; i < weblogList.getWeblogCount(); i++) { taskDialog.addWeblog(weblogList.getWeblogAt(i)); } blogTree.setModel(weblogTreeModel); feedTree.setModel(feedTreeModel); blogTree.expandRow(0); //Select previously selected weblog String key = TBGlobals.getProperty("LAST_SEL_BLOG"); //$NON-NLS-1$ Weblog foundBlog = null; for(int i = 0; i < weblogList.getWeblogCount(); i++) { if(weblogList.getWeblogAt(i).getKey().equals(key)) { foundBlog = weblogList.getWeblogAt(i); break; } } if(foundBlog != null) { selectWeblog(foundBlog); int r[] = blogTree.getSelectionRows(); blogTree.expandRow(r[0]); blogTree.setSelectionRow(r[0] + 1); } else blogTree.setSelectionRow(0);//select root node (My Sites) //blogTree.expandRow(1); //blogTree.setSelectionRow(2); if(searchDialog != null) { searchDialog.setWeblogList(weblogList); searchDialog.setRootFeedFolder(feedRoot); } if(TBGlobals.isStartWithLastDatabase()) { TBGlobals.setLastOpenedDatabase(curDB.getAbsolutePath()); } //isDBOpen = true; updateActions(); FRAME.getGlassPane().setVisible(false); FRAME.getGlassPane().setCursor(Cursor.getDefaultCursor()); if(TBGlobals.isAutoFeedUpdate()) { feedUpdateTimer.start(); } mailCheckTimer.start(); } }; isDBOpen = false; if(userXML.exists()) { getGlassPane().setVisible(true); getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); blogTree.clearSelection(); feedTree.clearSelection(); feedUpdateTimer.stop(); mailCheckTimer.stop(); taskDialog.removeAllWeblogs(); worker.start(); } } private void initActions() { openDBAction = new OpenDatabaseAction(); actions.add(openDBAction); newDBAction = new NewDatabaseAction(); actions.add(newDBAction); updateAllFeedsAction = new UpdateAllFeedsAction(); actions.add(updateAllFeedsAction); updateCurFeedAction = new UpdateCurrentFeedAction(); actions.add(updateCurFeedAction); updateFolderAction = new UpdateFolderAction(); actions.add(updateFolderAction); renameFeedFolderAction = new RenameFeedFolderAction(); actions.add(renameFeedFolderAction); deleteFromFeedTreeAction = new DeleteFromFeedTreeAction(); actions.add(deleteFromFeedTreeAction); markCurFeedReadAction = new MarkCurrentFeedAction(true); actions.add(markCurFeedReadAction); markCurFeedUnreadAction = new MarkCurrentFeedAction(false); actions.add(markCurFeedUnreadAction); markSelItemsReadAction = new MarkSelectedItemsAction(true); actions.add(markSelItemsReadAction); markSelItemsUnreadAction = new MarkSelectedItemsAction(false); actions.add(markSelItemsUnreadAction); newFeedFolderAction = new NewFeedFolderAction(); actions.add(newFeedFolderAction); newFeedAction = new NewFeedAction(); actions.add(newFeedAction); feedPropertiesAction = new FeedPropertiesAction(); actions.add(feedPropertiesAction); importFeedFolderAction = new ImportFeedFolderAction(); actions.add(importFeedFolderAction); exportFeedFolderAction = new ExportFeedFolderAction(); actions.add(exportFeedFolderAction); openFolderAction = new OpenFolderAction(); actions.add(openFolderAction); newEntryAction = new NewEntryAction(); actions.add(newEntryAction); newEntryFromItemAction = new NewEntryFromItemAction(); actions.add(newEntryFromItemAction); editEntryAction = new EditEntryAction(); actions.add(editEntryAction); deleteEntriesAction = new DeleteEntriesAction(); actions.add(deleteEntriesAction); exportWeblogToRSSAction = new ExportWeblogToRSSAction(); actions.add(exportWeblogToRSSAction); importEntriesFromFeedAction = new ImportEntriesFromFeedAction(); actions.add(importEntriesFromFeedAction); exportTemplatesAction = new ExportTemplatesAction(); actions.add(exportTemplatesAction); //importLegacyWeblogAction = new ImportLegacyWeblogAction(); //actions.add(importLegacyWeblogAction); showTasksAction = new ShowTaskDialogAction(); actions.add(showTasksAction); publishAction = new PublishAction(); actions.add(publishAction); publishAllAction = new PublishAllAction(); actions.add(publishAllAction); weblogPingAction = new WeblogPingAction(); actions.add(weblogPingAction); viewWeblogAction = new ViewWeblogAction(); actions.add(viewWeblogAction); importFromEmailAction = new ImportFromEmailAction(); actions.add(importFromEmailAction); weblogPropertiesAction = new WeblogPropertiesAction(); actions.add(weblogPropertiesAction); newWeblogAction = new NewWeblogAction(); actions.add(newWeblogAction); deleteWeblogAction = new DeleteWeblogAction(); actions.add(deleteWeblogAction); editTemplateAction = new EditTemplateAction(); actions.add(editTemplateAction); nextAction = new NextAction(); actions.add(nextAction); prevAction = new PreviousAction(); actions.add(prevAction); nextUnreadAction = new NextUnreadAction(); actions.add(nextUnreadAction); searchAction = new SearchAction(); actions.add(searchAction); findEntriesAction = new SearchAction(TBSearchDialog.WEBLOG_TAB); actions.add(findEntriesAction); findItemsAction = new SearchAction(TBSearchDialog.FEED_TAB); actions.add(findItemsAction); importFileAction = new ImportFileAction(); actions.add(importFileAction); newWebFolderAction = new NewWebFolderAction(); actions.add(newWebFolderAction); deleteFileAction = new DeleteFileAction(); actions.add(deleteFileAction); renameFileAction = new RenameFileAction(); actions.add(renameFileAction); openFileAction = new OpenFileAction(); actions.add(openFileAction); actions.trimToSize(); } private void updateActions() { Enumeration eEnum = actions.elements(); //disable all actions if a DB isn't open if(curDB == null || !isDBOpen) { while(eEnum.hasMoreElements()) { Action a = (Action)eEnum.nextElement(); a.setEnabled(false); } } else { while(eEnum.hasMoreElements()) { Action a = (Action)eEnum.nextElement(); if(a instanceof UpdatableAction) ((UpdatableAction)a).update(); else a.setEnabled(true); } } //Always enabled newDBAction.setEnabled(true); openDBAction.setEnabled(true); } private JToolBar createToolBar() { JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); toolBar.putClientProperty("JToolBar.isRollover", Boolean.TRUE); //$NON-NLS-1$ UIUtils.addToolBarButton(toolBar, newEntryAction); UIUtils.addToolBarButton(toolBar, deleteEntriesAction); toolBar.addSeparator(); UIUtils.addToolBarButton(toolBar, searchAction); toolBar.addSeparator(); //Got to use an instance var for the button, so we can access it later //update button changes its state when updating updateButton = UIUtils.addToolBarButton(toolBar, updateAllFeedsAction); toolBar.addSeparator(); UIUtils.addToolBarButton(toolBar, publishAction); UIUtils.addToolBarButton(toolBar, publishAllAction); UIUtils.addToolBarButton(toolBar, importFromEmailAction); UIUtils.addToolBarButton(toolBar, weblogPingAction); toolBar.addSeparator(); UIUtils.addToolBarButton(toolBar, viewWeblogAction); toolBar.addSeparator(); UIUtils.addToolBarButton(toolBar, weblogPropertiesAction); toolBar.addSeparator(); UIUtils.addToolBarButton(toolBar, nextAction); UIUtils.addToolBarButton(toolBar, prevAction); return toolBar; } private JMenuBar createMenuBar() { JMenuBar mb = new JMenuBar(); //create the file menu JMenu fileMenu = new JMenu(i18n.str("file")); //$NON-NLS-1$ fileMenu.setMnemonic(i18n.mnem("file")); //$NON-NLS-1$ fileMenu.add(newWeblogAction); fileMenu.add(newEntryAction); //fileMenu.add(newFeedAction); fileMenu.addSeparator(); fileMenu.add(openDBAction); fileMenu.add(newDBAction); fileMenu.addSeparator(); fileMenu.add(new InstallTemplatePackAction()); fileMenu.addSeparator(); JMenu importMenu = new JMenu(i18n.str("import")); //$NON-NLS-1$ importMenu.setMnemonic(i18n.mnem("import")); //$NON-NLS-1$ //importMenu.add(importLegacyWeblogAction); importMenu.add(importEntriesFromFeedAction); importMenu.add(importFeedFolderAction); fileMenu.add(importMenu); JMenu exportMenu = new JMenu(i18n.str("export")); //$NON-NLS-1$ exportMenu.setMnemonic(i18n.mnem("export")); //$NON-NLS-1$ exportMenu.add(exportWeblogToRSSAction); exportMenu.add(exportFeedFolderAction); fileMenu.add(exportMenu); JMenuItem exitItem = new JMenuItem(i18n.str("exit")); //$NON-NLS-1$ exitItem.setMnemonic(i18n.mnem("exit")); //$NON-NLS-1$ exitItem.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e){closeApp(true);}}); fileMenu.addSeparator(); fileMenu.add(exitItem); mb.add(fileMenu); //edit menu JMenu editMenu = new JMenu(i18n.str("edit")); //$NON-NLS-1$ editMenu.setMnemonic(i18n.mnem("edit")); //$NON-NLS-1$ editMenu.add(TextEditPopupManager.getInstance().getAction(TextEditPopupManager.COPY)); editMenu.add(TextEditPopupManager.getInstance().getAction(TextEditPopupManager.SELECT_ALL)); editMenu.addSeparator(); editMenu.add(deleteEntriesAction); editMenu.add(editEntryAction); editMenu.addSeparator(); editMenu.add(findEntriesAction); editMenu.add(findItemsAction); mb.add(editMenu); //view menu JMenu viewMenu = new JMenu(i18n.str("view")); //$NON-NLS-1$ viewMenu.setMnemonic(i18n.mnem("view")); //$NON-NLS-1$ sortMenu = new JMenu(i18n.str("sort_by"));//updated whenever the view type changes //$NON-NLS-1$ sortMenu.setMnemonic(i18n.mnem("sort")); //$NON-NLS-1$ viewMenu.add(sortMenu); viewMenu.addSeparator(); viewMenu.add(nextAction); viewMenu.add(prevAction); viewMenu.addSeparator(); viewMenu.add(nextUnreadAction); viewMenu.add(showTasksAction); viewMenu.addSeparator(); viewMenu.add(viewWeblogAction); mb.add(viewMenu); //Weblogs menu JMenu weblogsMenu = new JMenu(i18n.str("weblog")); //$NON-NLS-1$ weblogsMenu.setMnemonic(i18n.mnem("weblog")); //$NON-NLS-1$ weblogsMenu.add(newEntryAction); weblogsMenu.addSeparator(); weblogsMenu.add(publishAction); weblogsMenu.add(publishAllAction); weblogsMenu.add(importFromEmailAction); weblogsMenu.add(weblogPingAction); weblogsMenu.addSeparator(); weblogsMenu.add(editTemplateAction); weblogsMenu.addSeparator(); weblogsMenu.add(newWebFolderAction); weblogsMenu.add(importFileAction); weblogsMenu.addSeparator(); weblogsMenu.add(weblogPropertiesAction); mb.add(weblogsMenu); //Feed menu JMenu feedMenu = new JMenu(i18n.str("news")); //$NON-NLS-1$ feedMenu.setMnemonic(i18n.mnem("news")); //$NON-NLS-1$ feedMenu.add(newFeedAction); feedMenu.addSeparator(); feedMenu.add(updateAllFeedsAction); feedMenu.add(updateFolderAction); feedMenu.add(updateCurFeedAction); feedMenu.addSeparator(); feedMenu.add(markCurFeedReadAction); feedMenu.add(markCurFeedUnreadAction); feedMenu.addSeparator(); feedMenu.add(newEntryFromItemAction); feedMenu.addSeparator(); feedMenu.add(feedPropertiesAction); mb.add(feedMenu); //Configure menu JMenu configMenu = new JMenu(i18n.str("configure")); //$NON-NLS-1$ configMenu.setMnemonic(i18n.mnem("configure")); //$NON-NLS-1$ JMenuItem optsItem = new JMenuItem(i18n.str("options_")); //$NON-NLS-1$ optsItem.setMnemonic(i18n.mnem("options_")); //$NON-NLS-1$ optsItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int layout = TBGlobals.getLayoutStyle(); TBOptionsDialog d = new TBOptionsDialog(FRAME); d.setLocationRelativeTo(FRAME); d.setVisible(true); if(!d.hasUserCancelled()) { d.saveOptions(); //do layout if the style changed if(layout != TBGlobals.getLayoutStyle()) layoutContentPanel(TBGlobals.getLayoutStyle()); feedUpdateTimer.stop(); if(TBGlobals.isAutoFeedUpdate()) { feedUpdateTimer.setInitialDelay(TBGlobals.getFeedUpdateInterval()); feedUpdateTimer.setDelay(TBGlobals.getFeedUpdateInterval()); feedUpdateTimer.start(); } } } }); optsItem.setIcon(UIUtils.getIcon(UIUtils.X16, "config.png")); //$NON-NLS-1$ configMenu.add(optsItem); mb.add(configMenu); JMenu helpMenu = new JMenu(i18n.str("help")); //$NON-NLS-1$ helpMenu.setMnemonic(i18n.mnem("help")); //$NON-NLS-1$ Action helpContents = new TBHelpAction( i18n.str("help_contents_"), "index"); //$NON-NLS-1$ //$NON-NLS-2$ helpContents.putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "help.png")); //$NON-NLS-1$ helpContents.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); helpContents.putValue(Action.MNEMONIC_KEY, new Integer(i18n.mnem("help_contents_"))); //$NON-NLS-1$ Action tutorial = new TBHelpAction( i18n.str("tutorial_"), "ch02.index"); //$NON-NLS-1$ //$NON-NLS-2$ /*JMenuItem donateItem = new JMenuItem(i18n.str("donate") + "..."); donateItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try{ Browser.displayURL( "http://sourceforge.net/donate/index.php?group_id=86787"); }catch(Exception ex){} } });*/ helpMenu.add(helpContents); helpMenu.add(tutorial); helpMenu.addSeparator(); helpMenu.add(new HomePageAction()); //helpMenu.add(donateItem); helpMenu.addSeparator(); JMenuItem aboutItem = new JMenuItem(i18n.str("about_")); //$NON-NLS-1$ aboutItem.setMnemonic(i18n.mnem("about_")); //$NON-NLS-1$ aboutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { TBAbout.showAboutBox(FRAME); } }); helpMenu.add(aboutItem); mb.add(helpMenu); return mb; } private void loadProperties() { int w = 800, h = 600; int h_div = 150, feed_div = 150, tv_div = 250; boolean maximized = false; int itemSortCol = 0; int entrySortCol = 0; try { maximized = TBGlobals.getProperty("MAXIMIZED").toString().equals(true + ""); //$NON-NLS-1$ //$NON-NLS-2$ w = Integer.parseInt(TBGlobals.getProperty("WIDTH")); //$NON-NLS-1$ h = Integer.parseInt(TBGlobals.getProperty("HEIGHT")); //$NON-NLS-1$ h_div = Integer.parseInt(TBGlobals.getProperty("H_DIV")); //$NON-NLS-1$ feed_div = Integer.parseInt(TBGlobals.getProperty("FEED_DIV")); //$NON-NLS-1$ tv_div = Integer.parseInt(TBGlobals.getProperty("TABLE_VIEWER_DIV")); //$NON-NLS-1$ itemSortCol = Integer.parseInt(TBGlobals.getProperty("ITEM_SORT_COL")); //$NON-NLS-1$ entrySortCol = Integer.parseInt(TBGlobals.getProperty("ENTRY_SORT_COL")); //$NON-NLS-1$ int ed_w = Integer.parseInt(TBGlobals.getProperty("EDITOR_WIDTH")); //$NON-NLS-1$ int ed_h = Integer.parseInt(TBGlobals.getProperty("EDITOR_HEIGHT")); //$NON-NLS-1$ editorSize = new Dimension(ed_w, ed_h); } catch(Exception ex){} if(maximized) { setSize(800, 600); setExtendedState(getExtendedState() | MAXIMIZED_BOTH); } else setSize(w, h); hSplitPane.setDividerLocation(h_div); tableViewerDivider.setDividerLocation(tv_div); feedSplitPane.setDividerLocation(feed_div); String tf = TBGlobals.getProperty("ITEM_SORT_ASC"); //$NON-NLS-1$ boolean itemSortAsc = tf != null && tf.equals("true"); //$NON-NLS-1$ feedTableModel.sortColumn(itemSortCol, itemSortAsc); tf = TBGlobals.getProperty("ENTRY_SORT_ASC"); //$NON-NLS-1$ boolean entrySortAsc = tf != null && tf.equals("true"); //$NON-NLS-1$ blogTableModel.sortColumn(entrySortCol, entrySortAsc); /* tf = TBGlobals.getProperty("EDITOR_WORDWRAP"); //$NON-NLS-1$ if(tf == null)//default is true isEditorWordWrap = true; else isEditorWordWrap = tf.equals("true"); //$NON-NLS-1$ */ //load the template for the "post from item" format FeedItemFormatter.loadTemplate(); } private void saveProperties() { TBGlobals.putProperty("EDITOR_WIDTH", editorSize.width + ""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("EDITOR_HEIGHT", editorSize.height + ""); //$NON-NLS-1$ //$NON-NLS-2$ //TBGlobals.putProperty("EDITOR_WORDWRAP", isEditorWordWrap + ""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("MAXIMIZED", (getExtendedState() == MAXIMIZED_BOTH) + ""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("WIDTH", getWidth() + ""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("HEIGHT", getHeight() + ""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("H_DIV", hSplitPane.getDividerLocation()+""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("FEED_DIV", feedSplitPane.getDividerLocation()+""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("TABLE_VIEWER_DIV", //$NON-NLS-1$ tableViewerDivider.getDividerLocation()+""); //$NON-NLS-1$ TBGlobals.putProperty( "ENTRY_SORT_COL", blogTableModel.getSortedColumn() + ""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty( "ENTRY_SORT_ASC", blogTableModel.isSortedColumnAscending() + ""); //$NON-NLS-1$ //$NON-NLS-2$ TBGlobals.putProperty("ITEM_SORT_COL", //$NON-NLS-1$ feedTableModel.getSortedColumn() + ""); //$NON-NLS-1$ TBGlobals.putProperty("ITEM_SORT_ASC", //$NON-NLS-1$ feedTableModel.isSortedColumnAscending() + ""); //$NON-NLS-1$ String key = ""; //$NON-NLS-1$ if(curSelWeblog != null) key = curSelWeblog.getKey(); TBGlobals.putProperty("LAST_SEL_BLOG", key); //$NON-NLS-1$ TBGlobals.saveProperties(); tableColumnModel.saveColumnData(); } private void scrollToTableRow(int r) { Rectangle rect = table.getCellRect(r, 0, true); table.scrollRectToVisible(rect); } private void updateTableCellRenderer() { TableColumnModel colModel = table.getColumnModel(); int cols = colModel.getColumnCount(); for(int i = 0; i < cols; i++) { TBTableCellRenderer ren = new TBTableCellRenderer(); TableColumn tCol = colModel.getColumn(i); if(tableView == ENTRY_VIEW && curSelWeblog != null) { ren.setExpireDate(curSelWeblog.getArchiveBaseDate()); } tCol.setCellRenderer(ren); } } private void refreshTable() { int row = table.getSelectedRow(); table.clearSelection(); if(table.getModel() == feedTableModel) { TreePath selPath = feedTree.getSelectionPath(); if(selPath != null) { feedTree.clearSelection(); feedTree.setSelectionPath(selPath); } } else if(table.getModel() == blogTableModel) { long ids[] = new long[blogTableModel.getRowCount()]; for(int r = 0; r < ids.length; r++) { ids[r] = blogTableModel.getEntryIDAtRow(r); } blogTableModel.setRowCount(0); Vector v = new Vector(ids.length, 1); for(int i = 0; i < ids.length; i++) { try { BlogEntry e = curViewWeblog.getEntry(ids[i]); if(e == null)continue; v.add(e); } catch(Exception ex){} } BlogEntry entries[] = new BlogEntry[v.size()]; for(int i = 0; i < entries.length; i++) entries[i] = (BlogEntry)v.elementAt(i); blogTableModel.setBlogEntries(entries); } if(row > -1 && row < table.getRowCount()) table.setRowSelectionInterval(row, row); } private void refreshTree(JTree tree) { TreePath selPath = tree.getSelectionPath(); TreeModel model = tree.getModel(); Enumeration eEnum = tree.getExpandedDescendants(new TreePath(model.getRoot())); if(model instanceof WeblogTreeModel) ((WeblogTreeModel)model).setData(weblogList); else if(model instanceof FeedTreeModel) ((FeedTreeModel)model).refresh(); tree.repaint(); while(eEnum.hasMoreElements()) { tree.expandPath((TreePath)eEnum.nextElement()); } tree.setSelectionPath(selPath); } /** * Changes the current model of the table based on the view type * @param type The view type */ private void setTableView(int type) { table.clearSelection(); viewerPaneModel.setModelData(null); //viewerPane.setModel(null); if(type == ENTRY_VIEW) { curViewWeblog = curSelWeblog; tableView = ENTRY_VIEW; table.setModel(blogTableModel); table.sort(blogTableModel.getSortedColumn(), blogTableModel.isSortedColumnAscending()); } else if(type == ITEM_VIEW) { tableView = ITEM_VIEW; table.setModel(feedTableModel); table.sort(feedTableModel.getSortedColumn(), feedTableModel.isSortedColumnAscending()); } updateTableCellRenderer(); updateSortMenu(); if(!table.isSortedColumnAscending() && table.getRowCount() > 0) { scrollToTableRow(0); } else if(table.isSortedColumnAscending() && table.getRowCount() > 0) { scrollToTableRow(table.getRowCount() - 1); } } private void showWeblogConfigDialog() { //if(blogTree.getLastSelectedPathComponent() instanceof Weblog) if(curSelWeblog != null && !curSelWeblog.isPublishing()) { boolean cancelled = WeblogPropertiesDialogFactory.showPropertiesDialog(curSelWeblog, FRAME); if(!cancelled) { //update the table tree for any changes that have occured refreshTree(blogTree); refreshTable(); saveCurrentData(); } } } private void showNewWeblogWizard() { if(!isDBOpen) { JOptionPane.showMessageDialog(FRAME, i18n.str("no_database_is_open")); //$NON-NLS-1$ return; } TBWizardDialog wiz = new TBWizardDialog(FRAME, curDB, backend); wiz.setLocationRelativeTo(FRAME); wiz.setVisible(true); if(!wiz.hasUserCancelled()) { Weblog w = wiz.getWeblog(); weblogList.addWeblog(w); taskDialog.addWeblog(w); weblogTreeModel.setData(weblogList); if(searchDialog != null) searchDialog.setWeblogList(weblogList); //updateActions(); saveCurrentData(); selectWeblog(wiz.getWeblog()); } } private void selectWeblog(Weblog blog) { blogTree.expandRow(0); int rc = blogTree.getRowCount(); for(int i = 0; i < rc; i++) { TreePath p = blogTree.getPathForRow(i); if(p.getLastPathComponent() == blog) blogTree.setSelectionRow(i); } } /** * Creates a JMenu that can sort the table columns * */ private void updateSortMenu() { sortMenu.removeAll(); if(tableView == ENTRY_VIEW) { sortMenu.add(new SortTableAction(WeblogTableModel.TITLE.toString(), WeblogTableModel.TITLE_COL)); sortMenu.add(new SortTableAction(WeblogTableModel.POST_DATE.toString(), WeblogTableModel.DATE_COL)); sortMenu.add(new SortTableAction(WeblogTableModel.AUTHOR.toString(), WeblogTableModel.AUTHOR_COL)); sortMenu.add(new SortTableAction(WeblogTableModel.ID.toString(), WeblogTableModel.ID_COL)); } else if(tableView == ITEM_VIEW) { sortMenu.add(new SortTableAction(i18n.str("read"), FeedTableModel.READ_COL)); //$NON-NLS-1$ sortMenu.add(new SortTableAction(FeedTableModel.ITEM.toString(), FeedTableModel.ITEM_COL)); sortMenu.add(new SortTableAction(FeedTableModel.DATE.toString(), FeedTableModel.DATE_COL)); } final JRadioButtonMenuItem ascItem = new JRadioButtonMenuItem(i18n.str("ascending")); //$NON-NLS-1$ final JRadioButtonMenuItem descItem = new JRadioButtonMenuItem(i18n.str("descending")); //$NON-NLS-1$ ActionListener sortOrderListener = new ActionListener() { public void actionPerformed(ActionEvent e) { if(e.getSource() == ascItem) { sortAscending = ascItem.isSelected(); descItem.setSelected(!ascItem.isSelected()); } else if(e.getSource() == descItem) { sortAscending = descItem.isSelected(); ascItem.setSelected(!descItem.isSelected()); } } }; ascItem.setSelected(sortAscending); ascItem.addActionListener(sortOrderListener); descItem.setSelected(!sortAscending); descItem.addActionListener(sortOrderListener); sortMenu.addSeparator(); sortMenu.add(ascItem); sortMenu.add(descItem); } /** * Updates a folder and all its subfolders * @param f the folder to update * @param progress the update progress */ private void updateFolder(final FeedFolder f) { if(updateMonitor.isUpdateStarted()) { System.out.println("Update in progress"); //$NON-NLS-1$ return; } Thread updater = new Thread() { public void run() { f.updateFeeds(true, updateMonitor); SwingUtilities.invokeLater(new Runnable() { public void run() { updateAllFeedsAction.setAbortable(false); moveHandler.setEnabled(true); updateMonitor.reset(); if(TBGlobals.isAutoFeedUpdate()) feedUpdateTimer.start(); } }); System.out.println("update thread exiting");//$NON-NLS-1$ } }; moveHandler.setEnabled(false); updateAllFeedsAction.setAbortable(true); feedUpdateTimer.stop(); updater.start(); } private void updateFeed(final Feed f) { Thread updater = new Thread() { public void run() { try { f.update(); } catch(Exception ioe) { logger.log(Level.WARNING, ioe.getMessage(),ioe); UIUtils.showError(FRAME, i18n.str("feed_update_error_prompt"), ioe); //$NON-NLS-1$ } finally { //call update finish to re-enable feed actions updateMonitor.updateFinish(); SwingUtilities.invokeLater(new Runnable() { public void run(){ refreshTable(); statusBar.setRefreshingText(""); //$NON-NLS-1$ statusBar.getJProgressBar().setIndeterminate(false); } }); } } }; //calling updateStart here to disable feed actions updateMonitor.updateStart(1); statusBar.setRefreshingText(f.getTitle()); statusBar.getJProgressBar().setIndeterminate(true); updater.start(); } private boolean isCheckingEmail, isPublishing; private Weblog getBlogMostOverdueForEmailCheck() { Weblog oldest = null; for(int i = 0; i < weblogList.getWeblogCount(); i++) { Weblog temp = weblogList.getWeblogAt(i); if(temp.isOutdated() && !temp.isCheckingEmail()) { if(oldest == null || temp.getLastEmailCheck() == null || oldest.getLastEmailCheck().after(temp.getLastEmailCheck())) oldest = temp; } } return oldest; } protected void showTaskDialog() { if(!taskDialog.isVisible()) { taskDialog.setLocationRelativeTo(FRAME); taskDialog.setVisible(true); } } private void importEntriesFromEmail(final Weblog blog) { final LogPanel d = taskDialog.getLogPanel(blog);//logPanel; if(d == null || blog.isPublishing() || blog.isCheckingEmail()) return; Thread runner = new Thread() { public void run() { boolean hadEntries = false; try { d.reset(); hadEntries = blog.importEntriesFromEmail(d); } catch(Exception ex) { logger.log(Level.WARNING, ex.getMessage(), ex); ex.printStackTrace(); } finally { final boolean shouldPub = hadEntries; Runnable r = new Runnable() { public void run() { if(shouldPub) refreshTable(); updateActions(); if(!isPublishing) statusBar.getJProgressBar().setIndeterminate(false); blogTree.repaint(); if(shouldPub) publishWeblog(blog, PUB_CHANGED); } }; isCheckingEmail = false; SwingUtilities.invokeLater(r); } } }; if(blog.isImportFromEmailEnabled()) { isCheckingEmail = true; if(LoginFactory.emailLogin(blog, new GUILoginPrompt(FRAME))) { runner.start(); statusBar.getJProgressBar().setIndeterminate(true); taskDialog.showDetails(blog); this.updateActions(); } else { //user probably canceled email login isCheckingEmail = false; blog.setLastEmailCheck(new Date()); } } } private void publishWeblog(final Weblog blog, final int pubType) { /*final PublishDialog d = new PublishDialog( FRAME, i18n.str("publishing") + ": " + blog.getTitle(), false); //$NON-NLS-1$ */ final LogPanel d = taskDialog.getLogPanel(blog);//logPanel; if(d == null || blog.isPublishing() || blog.isCheckingEmail()) return; Thread runner = new Thread() { public void run() { try { d.reset(); //publish changed pages and send pings if(pubType == PUB_CHANGED) { blog.publish(d); //was the publish aborted and are there services to ping? if(!d.isAborted() && hasServicesToPing(blog) && !d.isDisplayingFailedMessage() && TBGlobals.isPingAfterPublish()) blog.sendPings(d); } else if(pubType == PUB_ALL)//publish everything { blog.publishAll(d); } else if(pubType == PING_ONLY) { blog.sendPings(d); } System.out.println("Publish thread exiting"); //$NON-NLS-1$ } catch(Exception ex) { logger.log(Level.WARNING, ex.getMessage(), ex); ex.printStackTrace(); } finally { Runnable r = new Runnable() { public void run() { updateActions(); if(!isCheckingEmail) statusBar.getJProgressBar().setIndeterminate(false); blogTree.repaint(); } }; isPublishing = false; SwingUtilities.invokeLater(r); } } }; /*if(blog.isPublishing()) return;*/ boolean okToPublish = false; if(pubType == PING_ONLY) okToPublish = hasServicesToPing(blog); else okToPublish = LoginFactory.publishLogin(blog, new GUILoginPrompt(FRAME)); //okToPublish = LoginFactory.login(curSelWeblog, new GUILoginPrompt(FRAME)); if(okToPublish) { /*d.setLocationRelativeTo(FRAME); d.setVisible(true);*/ isPublishing = true; runner.start(); taskDialog.showDetails(blog); statusBar.getJProgressBar().setIndeterminate(true); this.updateActions(); } } private boolean hasServicesToPing(Weblog b) { PingService ps[] = b.getPingServices(); for(int i = 0; i < ps.length; i++) { if(ps[i].isEnabled()) return true; } return false; } private boolean isWebFolderSelected() { if(blogTree.isSelectionEmpty()) return false; Object o = blogTree.getLastSelectedPathComponent(); if(o instanceof File) { File f = (File)o; return f.isDirectory(); } TreePath pPath = blogTree.getSelectionPath().getParentPath(); if(pPath == null) return false; Object parent = pPath.getLastPathComponent(); if(o.toString().equals(WeblogTreeModel.WEB_SITE) && parent instanceof Weblog) { return true; } return false; } private void openWebFile(File file) { if(file.isDirectory()) return; if(TBGlobals.isTextFile(file)) { HTMLEditor ed = new HTMLEditor(file); //ed.load(); //ed.setSize(640, 480); ed.setVisible(true); } else if(TBGlobals.isImageFile(file)) { ImageViewerDialog d = new ImageViewerDialog(FRAME, file); d.setSize(440, 280); d.setLocationRelativeTo(FRAME); d.setVisible(true); } } private BlogEntry createEntryFromItem(FeedItem item) { BlogEntry entry = new BlogEntry(); entry.setTitle(item.getTitle()); //String desc = item.getDescription(); //desc += "\n<br>\n<a href=\"" + //$NON-NLS-1$ // item.getLink() + "\">" + item.getLink() + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$ String desc = FeedItemFormatter.format(item); entry.setText(desc); return entry; } private void saveCurrentData() { try { if(curDB != null && isDBOpen) TBPersistFactory.save(weblogList, feedRoot, curDB.getAbsolutePath() + TBGlobals.SEP + TBGlobals.USER_XML_FILENAME); } catch(Exception ex) { logger.log(Level.WARNING, ex.getMessage(), ex); ex.printStackTrace(); } saveProperties(); } private void closeApp(boolean needExit) { saveCurrentData(); setVisible(false); try { backend.shutdown(); isDBOpen = false; } catch(Exception ex) { if(backend != null) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } isAppOpen = false; if (needExit) { System.exit(0); } } private void showEditor(BlogEntry be, int editMode) { Weblog blog = null; if(editMode == EntryEditor.NEW_ENTRY_MODE || tableView == ITEM_VIEW) blog = curSelWeblog; else if(editMode == EntryEditor.UPDATE_ENTRY_MODE) { blog = curViewWeblog; } if(blog == null) { try { blog = weblogList.getWeblogAt(0); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); return; } } try { EntryEditor ed = new EntryEditor(be, blog, weblogList, editMode); ed.addWindowListener(new PostListener()); ed.setSize(editorSize); //ed.setWordWrap(isEditorWordWrap); //ed.setIconImage(ICON); ed.setVisible(true); } catch(BackendException ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } /** * * Handles table double clicks and starts an EntryEditor for BlogEntries * and/or feedItems */ private class TableClickHandler extends MouseAdapter { public void mouseClicked(MouseEvent e) { if(e.getClickCount() == 2 /*&& lastSelWeblog != null */) //double click { int r = table.getSelectedRow(); if(tableView == ENTRY_VIEW) { long id = blogTableModel.getEntryIDAtRow(r); try { BlogEntry be = curViewWeblog.getEntry(id); showEditor(be, EntryEditor.UPDATE_ENTRY_MODE); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } else if(tableView == ITEM_VIEW) { long id = feedTableModel.getItemIDAtRow(r); try { FeedItem fi = backend.getItem(id); BlogEntry be = createEntryFromItem(fi); showEditor(be, EntryEditor.NEW_ENTRY_MODE); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } } } private class BlogTreeClickHandler extends MouseAdapter { public void mouseClicked(MouseEvent e) { if(e.getClickCount() == 2) //double click { Object node = blogTree.getLastSelectedPathComponent(); int row = blogTree.getClosestRowForLocation(e.getX(), e.getY()); if(row != -1 && blogTree.getPathForRow(row).getLastPathComponent().equals(node)) { if(node instanceof Template) { Template t = (Template)blogTree.getLastSelectedPathComponent(); HTMLEditor ed = new HTMLEditor(t); //ed.setSize(640, 480); ed.setVisible(true); //ed.load(); } else if(node instanceof File) { File file = (File)node; openWebFile(file); } } } } } //************************************************* //Listens for focus changes between the two trees //If a tree gains focus on a node that is already selected, //this listener takes the place of the tree selection listener //which would not fire a selection event under that circumstance //************************************************* private class TreeFocusListener implements FocusListener { private TreePath blogTreeSelPath = null; private TreePath feedTreeSelPath = null; public void focusGained(FocusEvent e) { if(e.isTemporary()) return; try { if(e.getSource() == blogTree && blogTreeSelPath != null) { TreePath curSelPath = blogTree.getSelectionPath(); boolean needsChanged = !htmlOptionsPane.isShowing() && tableView != ENTRY_VIEW; needsChanged = needsChanged && curSelPath.equals(blogTreeSelPath); if(curSelPath != null && needsChanged) { blogTreeSelected(blogTreeSelPath); } } else if(e.getSource() == feedTree && feedTreeSelPath != null) { TreePath curSelPath = feedTree.getSelectionPath(); if(curSelPath != null && curSelPath.equals(feedTreeSelPath)) { feedTreeSelected(feedTreeSelPath); } } } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } public void focusLost(FocusEvent e) { if(e.getSource() == blogTree) { blogTreeSelPath = blogTree.getSelectionPath(); } else if(e.getSource() == feedTree) { feedTreeSelPath = feedTree.getSelectionPath(); } } } private class TreeSelectionHandler implements TreeSelectionListener { public void valueChanged(TreeSelectionEvent e) { if(!e.isAddedPath())//is it a deselection? { updateActions(); return; } TreePath path = e.getPath(); try { //which tree was selected? if(e.getSource() == blogTree) { //feedTree.clearSelection(); //System.err.println(e.getPath().getLastPathComponent()); blogTreeSelected(path); } else if(e.getSource() == feedTree) { //blogTree.clearSelection(); feedTreeSelected(path); } statusBar.setViewingCount(table.getRowCount()); updateActions(); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } private void initHTMLView(Object obj) { htmlOptionsPane.clearOptions(); if(obj instanceof Weblog) { htmlOptionsPane.setTitle(((Weblog)obj).getTitle()); htmlOptionsPane.setImageURL( ClassLoader.getSystemResource(UIUtils.MISC + "tamb96.png")); //$NON-NLS-1$ htmlOptionsPane.addHeading(i18n.str("weblog_management")); //$NON-NLS-1$ htmlOptionsPane.addOption(new NewEntryLink()); htmlOptionsPane.addOption(new ReadEntriesLink()); htmlOptionsPane.addOption(new ConfigureWeblogLink()); htmlOptionsPane.addHeading(i18n.str("publishing")); //$NON-NLS-1$ htmlOptionsPane.addOption(new PublishLink()); htmlOptionsPane.addOption(new PublishAllLink()); htmlOptionsPane.addOption(new PingLink()); } else if(obj == WeblogTreeModel.ROOT) { htmlOptionsPane.setTitle(WeblogTreeModel.ROOT.toString()); htmlOptionsPane.setImageURL( ClassLoader.getSystemResource(UIUtils.MISC + "webpages.png")); //$NON-NLS-1$ htmlOptionsPane.addOption(new NewWeblogLink()); if(weblogList.getWeblogCount() > 0) { htmlOptionsPane.addHeading(i18n.str("weblogs")); //$NON-NLS-1$ for(int i = 0; i < weblogList.getWeblogCount(); i++) { htmlOptionsPane.addOption(new WeblogLink(weblogList.getWeblogAt(i))); } } } htmlOptionsPane.refresh(); } private void blogTreeSelected(TreePath path) throws BackendException { if(path.getLastPathComponent() == WeblogTreeModel.ROOT) { blogTreePopup = new JPopupMenu(); blogTreePopup.add(newWeblogAction); initHTMLView(WeblogTreeModel.ROOT); viewerPanelLayout.show(viewerPanel, HTML_VIEW); return;//nothing to do } //get the blog for the path. For a WeblogTreeModel a blog should always //be at element 1 try { curSelWeblog = (Weblog)path.getPathComponent(1); statusBar.setItem(curSelWeblog); } catch(ClassCastException cce) { cce.printStackTrace(); logger.log(Level.WARNING, cce.getMessage(), cce); return;//something's wrong with this WeblogTreeModel } //do something for the selection type if(path.getLastPathComponent() instanceof Weblog) { blogTreePopup = createBlogSelectedPopup(); Weblog w = (Weblog)path.getLastPathComponent(); initHTMLView(w); viewerPanelLayout.show(viewerPanel, HTML_VIEW); return; } if(path.getLastPathComponent() instanceof Template) { blogTreePopup = new JPopupMenu(); blogTreePopup.add(editTemplateAction); } //Either Curent, Drafts, Expired, or a category is selected else if(path.getLastPathComponent() instanceof String) { BlogEntry be[] = new BlogEntry[0]; String str = path.getLastPathComponent().toString(); blogTreePopup = null;//no popup for this type //Current or Drafts or Expired is selected if(path.getParentPath().getLastPathComponent() instanceof Weblog) { if(str.equals(WeblogTreeModel.CURRENT)) { be = curSelWeblog.getCurrentEntries(); } else if(str.equals(WeblogTreeModel.DRAFTS)) { be = curSelWeblog.getDraftEntries(); } else if(str.equals(WeblogTreeModel.EXPIRED)) { be = curSelWeblog.getExpiredEntries(); } }//category is selected else if(path.getParentPath().getLastPathComponent().toString().equals(WeblogTreeModel.CATS)) { String cat = path.getLastPathComponent().toString(); be = curSelWeblog.getEntriesFromCategory(cat); } blogTableModel.setBlogEntries(be); tablePopup = createBlogTablePopup(); //table.setModel(blogTableModel); setTableView(ENTRY_VIEW); viewerPanelLayout.show(viewerPanel, TABLE_VIEW); }//archive is selected else if(path.getLastPathComponent() instanceof ArchiveRange) { ArchiveRange ar = (ArchiveRange)path.getLastPathComponent(); blogTableModel.setBlogEntries(curSelWeblog.getEntriesFromArchive(ar)); //table.setModel(blogTableModel); setTableView(ENTRY_VIEW); tablePopup = createBlogTablePopup(); blogTreePopup = null; viewerPanelLayout.show(viewerPanel, TABLE_VIEW); } //root of Web Files folder is selected else if(path.getParentPath().getLastPathComponent() instanceof Weblog && path.getLastPathComponent().toString().equals(WeblogTreeModel.WEB_SITE)) { blogTreePopup = new JPopupMenu(); blogTreePopup.add(openFolderAction); blogTreePopup.addSeparator(); blogTreePopup.add(newWebFolderAction); blogTreePopup.add(importFileAction); blogTreePopup.addSeparator(); blogTreePopup.add(refreshBlogTreeAction); }//subfolder of Web Files folder is selected else if(path.getLastPathComponent() instanceof File) { File f = (File)path.getLastPathComponent(); if(f.isDirectory()) { blogTreePopup = createDirectorySelectedPopup(); } else { blogTreePopup = createFileSelectedPopup(); } } else { blogTreePopup = null; } //viewerPanelLayout.show(viewerPanel, TABLE_VIEW); } private void feedTreeSelected(TreePath path) throws FeedBackendException { if(path.getLastPathComponent() instanceof Feed) { lastSelFeed = (Feed)path.getLastPathComponent(); feedTableModel.setItems(lastSelFeed.getItems()); //table.setModel(feedTableModel); setTableView(ITEM_VIEW); feedTreePopup = createFeedSelectedPopup(); tablePopup = createFeedTablePopup(); //String s = lastSelFeed.getTitle(); //if(lastSelFeed.isLastUpdateFailed()) // s += " (" + lastSelFeed.getLastUpdateFailedReason() + ")"; //statusBar.setText(s); statusBar.setItem(lastSelFeed); viewerPanelLayout.show(viewerPanel, TABLE_VIEW); } else if(path.getLastPathComponent() instanceof FeedFolder) { feedTreePopup = createFeedFolderSelectedPopup(); } } //these methods create popups for various selection types private JPopupMenu createFeedSelectedPopup() { JPopupMenu p = new JPopupMenu(); p.add(updateCurFeedAction); p.addSeparator(); p.add(markCurFeedReadAction); p.add(markCurFeedUnreadAction); p.addSeparator(); p.add(deleteFromFeedTreeAction); p.addSeparator(); p.add(feedPropertiesAction); return p; } private JPopupMenu createFeedFolderSelectedPopup() { JPopupMenu p = new JPopupMenu(); p.add(updateFolderAction); p.addSeparator(); p.add(newFeedFolderAction); p.add(newFeedAction); p.addSeparator(); p.add(deleteFromFeedTreeAction); p.add(renameFeedFolderAction); p.addSeparator(); p.add(importFeedFolderAction); p.add(exportFeedFolderAction); return p; } private JPopupMenu createFeedTablePopup() { JPopupMenu p = new JPopupMenu(); p.add(updateCurFeedAction); p.addSeparator(); p.add(newEntryFromItemAction); p.addSeparator(); p.add(new MarkSelectedItemsAction(true)); p.add(new MarkSelectedItemsAction(false)); return p; } private JPopupMenu createBlogTablePopup() { JPopupMenu p = new JPopupMenu(); //add through Utils.createMenuItem to remove icon etc p.add(editEntryAction); p.add(deleteEntriesAction); return p; } private JPopupMenu createBlogSelectedPopup() { JPopupMenu p = new JPopupMenu(); p.add(newEntryAction); p.addSeparator(); p.add(publishAction); p.add(publishAllAction); p.add(importFromEmailAction); p.add(weblogPingAction); p.addSeparator(); p.add(viewWeblogAction); p.addSeparator(); p.add(weblogPropertiesAction); p.addSeparator(); p.add(deleteWeblogAction); p.addSeparator(); p.add(importEntriesFromFeedAction); p.add(exportWeblogToRSSAction); p.add(exportTemplatesAction); return p; } private JPopupMenu createDirectorySelectedPopup() { JPopupMenu p = new JPopupMenu(); p.add(openFolderAction); p.addSeparator(); p.add(newWebFolderAction); p.add(importFileAction); p.addSeparator(); p.add(deleteFileAction); p.add(renameFileAction); p.addSeparator(); p.add(refreshBlogTreeAction); return p; } private JPopupMenu createFileSelectedPopup() { JPopupMenu p = new JPopupMenu(); p.add(openFileAction); p.addSeparator(); p.add(deleteFileAction); p.add(renameFileAction); return p; } private class TableSelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { if(!e.getValueIsAdjusting()) { int row = table.getSelectedRow(); try { loadViewer(row); updateActions(); } catch(Exception ex){} } } private void loadViewer(int row) throws BackendException, FeedBackendException { if(row > -1) { //after a search the entries/items won't get loaded into //the viewer because they won't belong to lastSelWeblog/lastSelFeed viewerPaneModel.setWeblog(curViewWeblog); if(tableView == ENTRY_VIEW) { Long n = (Long)blogTableModel.getValueAt(row, WeblogTableModel.ID_COL); BlogEntry entry = curViewWeblog.getEntry(n.longValue()); //viewerPane.setModel(new TBViewerPaneModel(entry)); viewerPaneModel.setModelData(entry); } else if(tableView == ITEM_VIEW) { long id = feedTableModel.getItemIDAtRow(row); //Since all feeds have the same backend, we can //get/update items from the HSQLDBBackend FeedItem item = backend.getItem(id); if(!item.isRead()) { item.setRead(true); feedTableModel.setItemAtRowRead(row, true); backend.updateItem(item); feedTree.repaint(); } //viewerPane.setModel(new TBViewerPaneModel(item)); viewerPaneModel.setModelData(item); } } } } private class PopupMenuListener extends MouseAdapter { public void mousePressed(MouseEvent e) { selectNode(e); checkForPopupTrigger(e); } public void mouseReleased(MouseEvent e) { checkForPopupTrigger(e); } private void checkForPopupTrigger(MouseEvent e) { if(e.isPopupTrigger()) { Component c = e.getComponent(); if(c == blogTree && blogTreePopup != null) showTreePopup(blogTree, blogTreePopup, e); else if(c == feedTree && feedTreePopup != null) showTreePopup(feedTree, feedTreePopup, e); else if(c == table && tablePopup != null) tablePopup.show(c, e.getX(), e.getY()); //else if(c == viewerPane.getJEditorPane() && viewerPopup != null) // viewerPopup.show(c, e.getX(), e.getY()); } } //selects the node, thereby firing a selection event //which should init the popup menu if needed private void selectNode(MouseEvent e) { if(e.getSource() instanceof JTree) { JTree t = (JTree)e.getSource(); int row = t.getRowForLocation(e.getX(), e.getY()); if(row > -1) t.setSelectionRow(row); } } private void showTreePopup(JTree tree, JPopupMenu popup, MouseEvent e) { if(!tree.isSelectionEmpty()) { TreePath p = tree.getLeadSelectionPath(); Rectangle rec = tree.getRowBounds(tree.getRowForPath(p)); if(rec.contains(e.getX(), e.getY())) popup.show(tree, e.getX(), e.getY()); } } } //******************** // Actions //******************** //*********************************** //Action to create a new weblog entry //*********************************** private class NewEntryAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public NewEntryAction() { super(i18n.str("new_entry_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("new_entry_"))); //$NON-NLS-1$ putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E, Event.CTRL_MASK)); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "edit1.png")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "edit1.png")); } public void update() { setEnabled(weblogList.getWeblogCount() > 0); } public void actionPerformed(ActionEvent e) { showEditor(new BlogEntry(), EntryEditor.NEW_ENTRY_MODE); } } //**************************************************** //Action to create a new weblog entry from a feed item //**************************************************** private class NewEntryFromItemAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public NewEntryFromItemAction() { super(i18n.str("post_to_weblog_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("post_to_weblog_"))); //$NON-NLS-1$ } public void update() { setEnabled(tableView == ITEM_VIEW && table.getSelectedRowCount() > 0 && weblogList.getWeblogCount() > 0); } public void actionPerformed(ActionEvent e) { int r = table.getSelectedRow(); if(lastSelFeed == null || r == -1 || tableView != ITEM_VIEW) return; long id = feedTableModel.getItemIDAtRow(r); try { FeedItem item = lastSelFeed.getBackend().getItem(id); BlogEntry entry = createEntryFromItem(item); showEditor(entry, EntryEditor.NEW_ENTRY_MODE); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } private class MarkSelectedItemsAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; private boolean readOrUnread; public MarkSelectedItemsAction(boolean read) { super(null); if(read) { putValue(NAME, i18n.str("mark_items_read")); //$NON-NLS-1$ } else { putValue(NAME, i18n.str("mark_items_unread")); //$NON-NLS-1$ } readOrUnread = read; } public void update() { setEnabled(tableView == ITEM_VIEW && table.getSelectedRowCount() > 0); } public void actionPerformed(ActionEvent e) { int r[] = table.getSelectedRows(); if(lastSelFeed == null || r.length == 0 || tableView != ITEM_VIEW) return; for(int i = 0; i < r.length; i++) { long id = feedTableModel.getItemIDAtRow(r[i]); try { table.clearSelection(); FeedItem item = lastSelFeed.getBackend().getItem(id); item.setRead(readOrUnread); lastSelFeed.updateItem(item); refreshTable(); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } //mainPane.refreshView(); } } private class MarkCurrentFeedAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; private boolean read; public MarkCurrentFeedAction(boolean read) { this.read = read; if(read) { putValue(NAME, i18n.str("mark_feed_read")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("mark_feed_read"))); //$NON-NLS-1$ } else { putValue(NAME, i18n.str("mark_feed_unread"));//$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("mark_feed_unread"))); //$NON-NLS-1$ } } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof Feed; setEnabled(sel && !updateMonitor.isUpdateStarted() && tableView == ITEM_VIEW); } public void actionPerformed(ActionEvent e) { if(lastSelFeed != null && tableView == ITEM_VIEW) { try { table.clearSelection(); lastSelFeed.markAllItemsRead(read); refreshTable(); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } //mainPane.selectObjectInTree(f); //mainPane.repaint(); } } } //************************************************** //Actions for editing the feed tree //************************************************** private class ImportFeedFolderAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ImportFeedFolderAction() { super(i18n.str("import_feeds_from_opml_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("import_feeds_from_opml_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "import.png")); //$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof FeedFolder; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { if(feedTree.getLastSelectedPathComponent() instanceof FeedFolder) { FeedFolder parent = (FeedFolder)feedTree.getLastSelectedPathComponent(); JFileChooser fc = new JFileChooser(); CustomFileFilter cff = new CustomFileFilter(); cff.addExtension("opml"); //$NON-NLS-1$ cff.addExtension("xml"); //$NON-NLS-1$ fc.setFileFilter(cff); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setDialogTitle(i18n.str("import_from_opml")); //$NON-NLS-1$ int r = fc.showOpenDialog(ThingamablogFrame.this); fc.setApproveButtonText(i18n.str("import")); //$NON-NLS-1$ if(r == JFileChooser.CANCEL_OPTION) return; if(fc.getSelectedFile() == null) return; File sel = fc.getSelectedFile(); try { OPMLImportExport.importFromOPML(parent, sel.getAbsolutePath(), backend); refreshTree(feedTree); } catch(Exception ex) { UIUtils.showError(FRAME, i18n.str("error_importing_opml_prompt")); //$NON-NLS-1$ ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } } private class ExportFeedFolderAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ExportFeedFolderAction() { super(i18n.str("export_feeds_to_opml_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("export_feeds_to_opml_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "export.png")); //$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof FeedFolder; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { if(feedTree.getLastSelectedPathComponent() instanceof FeedFolder) { FeedFolder parent = (FeedFolder)feedTree.getLastSelectedPathComponent(); JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); CustomFileFilter cff = new CustomFileFilter(); cff.addExtension("opml"); //$NON-NLS-1$ fc.setFileFilter(cff); fc.setDialogTitle(i18n.str("export_to_opml_")); //$NON-NLS-1$ fc.setSelectedFile(new File(TBGlobals.USER_HOME, parent.getName() + ".opml")); //$NON-NLS-1$ int r = fc.showSaveDialog(FRAME); fc.setApproveButtonText(i18n.str("export")); //$NON-NLS-1$ if(r == JFileChooser.CANCEL_OPTION) return; if(fc.getSelectedFile() == null) return; File sel = fc.getSelectedFile(); if(sel == null) return; if(sel.exists()) { int yn = JOptionPane.showConfirmDialog(FRAME, i18n.str("overwrite_existing_file_prompt"), //$NON-NLS-1$ i18n.str("confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$ if(yn == JOptionPane.NO_OPTION) return; } try { OPMLImportExport.exportFolderToOPML(parent, sel.getAbsolutePath()); } catch(Exception ex) { UIUtils.showError(FRAME, i18n.str("error_exporting_folder_prompt")); //$NON-NLS-1$ ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } } //********************************************** //Actions for importing/exporting weblog entries //********************************************** /*private class ImportLegacyWeblogAction extends UpdatableAction { public ImportLegacyWeblogAction() { super(i18n.str("import_09x_weblog_")); //$NON-NLS-1$ Messages.setMnemonic("ThingamablogFrame.Import_09x_Weblog", this); } public void update() { setEnabled(isDBOpen && curDB != null); } public void actionPerformed(ActionEvent e) { JDialog d = new ImportLegacyWeblogDialog(FRAME, curDB, weblogList, backend); d.setLocationRelativeTo(FRAME); d.setVisible(true); refreshTree(blogTree); } }*/ private class ImportEntriesFromFeedAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ImportEntriesFromFeedAction() { super(i18n.str("import_entries_from_feed_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("import_entries_from_feed_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "import.png")); //$NON-NLS-1$ } public void update() { setEnabled(blogTree.getLastSelectedPathComponent() instanceof Weblog); } public void actionPerformed(ActionEvent e) { if(blogTree.getLastSelectedPathComponent() instanceof Weblog) { Weblog w = (Weblog)blogTree.getLastSelectedPathComponent(); JDialog d = new ImportEntriesDialog(FRAME, w); d.setLocationRelativeTo(FRAME); d.setVisible(true); } } } private class ExportTemplatesAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ExportTemplatesAction() { super(i18n.str("export_templates_")); //$NON-NLS-1$ //Messages.setMnemonic("ThingamablogFrame.Export_Weblog_to_Feed", this); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "export.png")); //$NON-NLS-1$ } public void update() { setEnabled(blogTree.getLastSelectedPathComponent() instanceof TBWeblog); } public void actionPerformed(ActionEvent e) { if(blogTree.getLastSelectedPathComponent() instanceof TBWeblog) { TBWeblog w = (TBWeblog)blogTree.getLastSelectedPathComponent(); ExportTemplatePackDialog d = new ExportTemplatePackDialog(FRAME, w); d.setLocationRelativeTo(FRAME); d.setVisible(true); } } } private class ExportWeblogToRSSAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ExportWeblogToRSSAction() { super(i18n.str("export_weblog_to_feed_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("export_weblog_to_feed_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "export.png"));//$NON-NLS-1$ } public void update() { setEnabled(blogTree.getLastSelectedPathComponent() instanceof Weblog); } public void actionPerformed(ActionEvent e) { if(blogTree.getLastSelectedPathComponent() instanceof Weblog) { Weblog w = (Weblog)blogTree.getLastSelectedPathComponent(); JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); CustomFileFilter cff = new CustomFileFilter(); cff.addExtension("xml"); //$NON-NLS-1$ fc.setFileFilter(cff); fc.setDialogTitle(i18n.str("export_to_feed")); //$NON-NLS-1$ fc.setSelectedFile(new File(TBGlobals.USER_HOME, w.getTitle() + ".xml")); //$NON-NLS-1$ int r = fc.showSaveDialog(FRAME); fc.setApproveButtonText(i18n.str("export")); //$NON-NLS-1$ if(r == JFileChooser.CANCEL_OPTION) return; if(fc.getSelectedFile() == null) return; File sel = fc.getSelectedFile(); if(sel == null) return; if(sel.exists()) { int yn = JOptionPane.showConfirmDialog(FRAME, i18n.str("overwrite_existing_file_prompt"), //$NON-NLS-1$ i18n.str("confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); //$NON-NLS-1$ if(yn == JOptionPane.NO_OPTION) return; } try { RSSImportExport.exportWeblogToFeed(w, sel); } catch(Exception ex) { UIUtils.showError(FRAME, i18n.str("error_exporting_folder_prompt")); //$NON-NLS-1$ ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } } private class NewFeedFolderAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public NewFeedFolderAction() { super(i18n.str("new_feed_folder_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("new_feed_folder_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "new_folder.png")); //$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof FeedFolder; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { if(feedTree.getLastSelectedPathComponent() instanceof FeedFolder) { FeedFolder parent = (FeedFolder)feedTree.getLastSelectedPathComponent(); Object s = JOptionPane.showInputDialog(FRAME, i18n.str("folder_name"), i18n.str("new_folder"), //$NON-NLS-1$ //$NON-NLS-2$ JOptionPane.QUESTION_MESSAGE, null, null, i18n.str("new_folder")); //$NON-NLS-1$ if(s != null && !s.toString().equals("")) //$NON-NLS-1$ { FeedFolder child = new FeedFolder(s.toString()); parent.addFolder(child); refreshTree(feedTree); //tmodel.refresh(); } } } } private class NewFeedAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public NewFeedAction() { super(i18n.str("new_feed_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("new_feed_"))); //$NON-NLS-1$ putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, Event.CTRL_MASK)); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "add.png"));//$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof FeedFolder; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { if(feedTree.getLastSelectedPathComponent() instanceof FeedFolder) { FeedFolder parent = (FeedFolder)feedTree.getLastSelectedPathComponent(); JTextField tf = new JTextField(25); TextEditPopupManager pm = TextEditPopupManager.getInstance(); pm.registerJTextComponent(tf); LabelledItemPanel lip = new LabelledItemPanel(); lip.addItem("Feed URL:", tf); //$NON-NLS-1$ tf.requestFocus(); int s = JOptionPane.showConfirmDialog(FRAME, lip, i18n.str("feed_url"), //$NON-NLS-1$ JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if(s == JOptionPane.OK_OPTION && !tf.getText().equals("")) //$NON-NLS-1$ { Feed child = new Feed(tf.getText()); child.setTitle(i18n.str("new_feed_title")); //$NON-NLS-1$ child.setBackend(backend); parent.addFeed(child); refreshTree(feedTree); saveCurrentData(); updateFeed(child); } } } } private class RenameFeedFolderAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public RenameFeedFolderAction() { super(i18n.str("rename_"));//$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof FeedFolder && feedTree.getLastSelectedPathComponent() != feedRoot; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { Object obj = feedTree.getLastSelectedPathComponent(); if(obj instanceof FeedFolder) { FeedFolder folder = (FeedFolder)obj; Object o = JOptionPane.showInputDialog( FRAME, i18n.str("rename_folder"), i18n.str("rename_title"), //$NON-NLS-1$ //$NON-NLS-2$ JOptionPane.QUESTION_MESSAGE, null, null, folder.getName()); if(o != null && !o.toString().equals("")) //$NON-NLS-1$ { folder.setName(o.toString()); refreshTree(feedTree); } } } } private class DeleteFromFeedTreeAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public DeleteFromFeedTreeAction() { super(i18n.str("delete_")); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "remove.png")); //$NON-NLS-1$ } public void update() { boolean sel = !feedTree.isSelectionEmpty(); setEnabled(sel && feedTree.getLastSelectedPathComponent() != feedRoot && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { Object obj = feedTree.getLastSelectedPathComponent(); if(obj instanceof FeedFolder && obj != feedRoot) { FeedFolder folder = (FeedFolder)obj; FeedFolder parent = folder.getParent(); if(parent == null || !isOkToDelete(folder.getName())) return; try { folder.deleteContents(); parent.removeFolder(folder); refreshTree(feedTree); feedTree.clearSelection(); saveCurrentData(); } catch(FeedBackendException ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } else if(obj instanceof Feed) { Feed feed = (Feed)obj; if(!isOkToDelete(feed.getTitle())) return; try { TreePath pPath = feedTree.getSelectionPath().getParentPath(); FeedFolder parent = (FeedFolder)pPath.getLastPathComponent(); feed.removeAllItems(); parent.removeFeed(feed); refreshTree(feedTree); feedTree.clearSelection(); saveCurrentData(); } catch(ClassCastException cce) { cce.printStackTrace(); } catch(FeedBackendException fbe) { fbe.printStackTrace(); logger.log(Level.WARNING, fbe.getMessage(), fbe); } } updateActions(); } private boolean isOkToDelete(String s) { int r = JOptionPane.showConfirmDialog(FRAME, i18n.str("delete_title") + " '" + s + "'?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ i18n.str("confirm"), JOptionPane.YES_NO_OPTION,//$NON-NLS-1$ JOptionPane.QUESTION_MESSAGE); return r == JOptionPane.YES_OPTION; } } private class FeedPropertiesAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public FeedPropertiesAction() { super(i18n.str("feed_properties_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("feed_properties_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "config.png")); //$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof Feed; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { if(lastSelFeed != null) { FeedPropertiesDialog d = new FeedPropertiesDialog(FRAME, lastSelFeed); d.setLocationRelativeTo(FRAME); d.setVisible(true); } } } //*************************************************** //Actions for updating RSS Feeds //*************************************************** private class UpdateAllFeedsAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; private boolean updating; public UpdateAllFeedsAction() { setAbortable(false); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_U, Event.CTRL_MASK)); putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "refresh.png")); } public void actionPerformed(ActionEvent e) { if(!updating) { updateFolder(feedRoot); } else { updateMonitor.abortUpdate(); setEnabled(false); } } public void setAbortable(boolean b) { updating = b; if(updating) { putValue(NAME, i18n.str("cancel_update")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("cancel_update"))); //$NON-NLS-1$ putValue(SHORT_DESCRIPTION, getValue(NAME)); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "cancel.png")); //$NON-NLS-1$ updateButton.setText(null); updateButton.setIcon( UIUtils.getIcon(UIUtils.X24, "cancel.png")); //$NON-NLS-1$ } else { putValue(NAME, i18n.str("update_all_news")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("update_all_news"))); //$NON-NLS-1$ putValue(SHORT_DESCRIPTION, getValue(NAME)); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "refresh.png")); //$NON-NLS-1$ updateButton.setText(null); updateButton.setIcon( UIUtils.getIcon(UIUtils.X24, "refresh.png")); //$NON-NLS-1$ setEnabled(true); } } } private class UpdateFolderAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public UpdateFolderAction() { super(i18n.str("update_folder")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("update_folder"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "update_folder.png")); //$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof FeedFolder; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { if(feedTree.getLastSelectedPathComponent() instanceof FeedFolder) { FeedFolder folder = (FeedFolder)feedTree.getLastSelectedPathComponent(); updateFolder(folder); } } } private class UpdateCurrentFeedAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public UpdateCurrentFeedAction() { super(i18n.str("update_feed")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("update_feed"))); //$NON-NLS-1$ } public void update() { boolean sel = feedTree.getLastSelectedPathComponent() instanceof Feed; setEnabled(sel && !updateMonitor.isUpdateStarted()); } public void actionPerformed(ActionEvent e) { final Feed f = lastSelFeed; if(f == null || updateMonitor.isUpdateStarted()) return; updateFeed(f); } } //*************************************** //Edit and delete Blog Entries //*************************************** private class EditEntryAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public EditEntryAction() { super(i18n.str("edit_selected_entry_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("edit_selected_entry_"))); //$NON-NLS-1$ putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_T, Event.CTRL_MASK)); putValue(SHORT_DESCRIPTION, getValue(NAME)); } public void update() { setEnabled(tableView == ENTRY_VIEW && table.getSelectedRowCount() > 0 && table.isShowing()); } public void actionPerformed(ActionEvent e) { if(tableView != ENTRY_VIEW || curSelWeblog == null) return; int r = table.getSelectedRow(); if(r < 0)return; long id = blogTableModel.getEntryIDAtRow(r); try { BlogEntry be = curViewWeblog.getEntry(id); showEditor(be, EntryEditor.UPDATE_ENTRY_MODE); refreshTable(); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } private class DeleteEntriesAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public DeleteEntriesAction() { super(i18n.str("delete_selected_entries_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("delete_selected_entries_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "delete.png")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "delete.png")); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); putValue(SHORT_DESCRIPTION, getValue(NAME)); } public void update() { setEnabled(tableView == ENTRY_VIEW && table.getSelectedRowCount() > 0 && table.isShowing()); } public void actionPerformed(ActionEvent e) { if(tableView != ENTRY_VIEW || curSelWeblog == null) return; int yn = JOptionPane.showConfirmDialog(ThingamablogFrame.this, i18n.str("delete_entries_prompt"), i18n.str("confirm"), //$NON-NLS-1$ //$NON-NLS-2$ JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if(yn == JOptionPane.NO_OPTION) return; int r[] = table.getSelectedRows(); long ids[] = new long[r.length]; for(int i = 0; i < ids.length; i++) ids[i] = blogTableModel.getEntryIDAtRow(r[i]); try { for(int i = 0; i < ids.length; i++) { BlogEntry be = curViewWeblog.getEntry(ids[i]); curViewWeblog.removeEntry(be); } refreshTable(); refreshTree(blogTree); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } //************************************************ //classes for publishing weblogs //************************************************ private class PublishAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public PublishAction() { super(i18n.str("publish")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("publish"))); //$NON-NLS-1$ putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK)); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "upload.png")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "upload.png")); } public void update() { TreePath tp = blogTree.getSelectionPath(); boolean rootSel = tp != null && tp.getLastPathComponent().equals(WeblogTreeModel.ROOT); setEnabled(curSelWeblog != null && (!curSelWeblog.isCheckingEmail()) && (!curSelWeblog.isPublishing()) && !rootSel); if(isEnabled()) putValue(Action.SHORT_DESCRIPTION, getValue(NAME) + " [" + curSelWeblog.getTitle() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } public void actionPerformed(ActionEvent e) { //if(blogTree.getLastSelectedPathComponent() instanceof Weblog) if(curSelWeblog != null) { publishWeblog(curSelWeblog, PUB_CHANGED); } } } private class PublishAllAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public PublishAllAction() { super(i18n.str("publish_entire_weblog")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("publish_entire_weblog"))); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "pub_all.png")); putValue(SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "pub_all.png")); } public void update() { TreePath tp = blogTree.getSelectionPath(); boolean rootSel = tp != null && tp.getLastPathComponent().equals(WeblogTreeModel.ROOT); setEnabled(curSelWeblog != null && (!curSelWeblog.isCheckingEmail()) && (!curSelWeblog.isPublishing()) && !rootSel); if(isEnabled()) putValue(Action.SHORT_DESCRIPTION, getValue(NAME) + " [" + curSelWeblog.getTitle() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } public void actionPerformed(ActionEvent e) { if(curSelWeblog != null) { publishWeblog(curSelWeblog, PUB_ALL); } } } private class ImportFromEmailAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ImportFromEmailAction() { super(i18n.str("import_entries_from_email")); //Messages.setMnemonic("ThingamablogFrame.Publish", this); //putValue(ACCELERATOR_KEY, // KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK)); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "email.png")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "email.png")); } public void update() { TreePath tp = blogTree.getSelectionPath(); boolean rootSel = tp != null && tp.getLastPathComponent().equals(WeblogTreeModel.ROOT); setEnabled(curSelWeblog != null && curSelWeblog.isImportFromEmailEnabled() && (!curSelWeblog.isCheckingEmail()) && (!curSelWeblog.isPublishing()) && !rootSel); if(isEnabled()) putValue(Action.SHORT_DESCRIPTION, getValue(NAME) + " [" + curSelWeblog.getTitle() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } public void actionPerformed(ActionEvent e) { //if(blogTree.getLastSelectedPathComponent() instanceof Weblog) if(curSelWeblog != null) { ///publishWeblog(curSelWeblog, PUB_CHANGED); importEntriesFromEmail(curSelWeblog); } } } //*************************************** //Action to ping the services of a weblog //**************************************** private class WeblogPingAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public WeblogPingAction() { super(i18n.str("ping_services")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("ping_services"))); //$NON-NLS-1$ putValue(SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "ping.png")); putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "ping.png")); } public void update() { TreePath tp = blogTree.getSelectionPath(); boolean rootSel = tp != null && tp.getLastPathComponent().equals(WeblogTreeModel.ROOT); setEnabled(curSelWeblog != null && !curSelWeblog.isPublishing() && !rootSel && hasServicesToPing(curSelWeblog)); if(isEnabled()) putValue(Action.SHORT_DESCRIPTION, getValue(NAME) + " [" + curSelWeblog.getTitle() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } public void actionPerformed(ActionEvent e) { if(curSelWeblog != null) { publishWeblog(curSelWeblog, PING_ONLY); } } } //****************************************** //Action to view the front page of a weblog //****************************************** private class ViewWeblogAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ViewWeblogAction() { super(i18n.str("view_weblog_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("view_weblog_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "browser.png")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "browser.png")); } public void update() { TreePath tp = blogTree.getSelectionPath(); boolean rootSel = tp != null && tp.getLastPathComponent().equals(WeblogTreeModel.ROOT); setEnabled(curSelWeblog != null && !rootSel); if(isEnabled()) putValue(SHORT_DESCRIPTION, getValue(NAME) + " [" + curSelWeblog.getTitle() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } public void actionPerformed(ActionEvent e) { if(curSelWeblog != null) { try { //Browser.displayURL(curSelWeblog.getFrontPageUrl()); Desktop.browse(new URL(curSelWeblog.getFrontPageUrl())); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } } //************************************************* //Action to open the properties dialog for a Weblog //************************************************* private class WeblogPropertiesAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public WeblogPropertiesAction() { super(i18n.str("configure_weblog_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("configure_weblog_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "config.png")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "config.png")); } public void update() { TreePath tp = blogTree.getSelectionPath(); boolean rootSel = tp != null && tp.getLastPathComponent().equals(WeblogTreeModel.ROOT); setEnabled(curSelWeblog != null && !curSelWeblog.isPublishing() && !rootSel); if(isEnabled()) putValue(SHORT_DESCRIPTION, getValue(NAME) + " [" + curSelWeblog.getTitle() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } public void actionPerformed(ActionEvent e) { showWeblogConfigDialog(); } } //******************************************************* //Actions that show the search dialog and handle a search //******************************************************* private class SearchAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; private boolean isSwitchTab; private int searchTab; public SearchAction() { super(i18n.str("find")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "find.png")); putValue(SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "find.png")); } /** * A search Action that opens the search dialog with the specified tab * @param tab Should be either * TBSearchDialog.FEED_TAB or TBSearchDialog.WEBLOG_TAB */ public SearchAction(int tab) { super(); if(tab == TBSearchDialog.WEBLOG_TAB) { searchTab = tab; putValue(NAME, i18n.str("find_entries_"));//$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("find_entries_"))); //$NON-NLS-1$ putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.CTRL_MASK)); } else { searchTab = TBSearchDialog.FEED_TAB; putValue(NAME, i18n.str("find_items_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("find_items_"))); //$NON-NLS-1$ } putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "find.png")); putValue(SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "find.png")); isSwitchTab = true; } public void actionPerformed(ActionEvent e) { if(searchDialog != null && searchDialog.isVisible()) return; searchDialog = new TBSearchDialog(FRAME, weblogList, feedRoot); searchDialog.addActionListener(new FindHandler()); //if(searchDialog != null && !searchDialog.isVisible()) { searchDialog.setLocationRelativeTo(FRAME); if(isSwitchTab) searchDialog.setCurrentSearchTab(searchTab); searchDialog.setVisible(true); } } } //handle a search when the Find button on the search dialog is pressed private class FindHandler implements ActionListener { public void actionPerformed(ActionEvent e) { if(searchDialog == null) return; //searching should probably get executed in a thread //but for the current implementation the HSQLBackend is pretty fast //so we'll go with this for now... try { if(searchDialog.getCurrentSearchTab() == TBSearchDialog.FEED_TAB) { FeedItem items[] = searchDialog.performFeedSearch(); feedTree.clearSelection(); feedTableModel.setItems(items); setTableView(ITEM_VIEW); } else //must be the weblog tab { BlogEntry be[] = searchDialog.performWeblogSearch(); blogTree.clearSelection(); blogTableModel.setBlogEntries(be); setTableView(ENTRY_VIEW); curSelWeblog = searchDialog.getSelectedWeblog(); curViewWeblog = curSelWeblog; } statusBar.setViewingCount(table.getRowCount()); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } //************************************************ //Action for creating a new Weblog from the wizard //************************************************ private class NewWeblogAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; public NewWeblogAction() { super(i18n.str("new_weblog_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("new_weblog_"))); //$NON-NLS-1$ putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK)); putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "blog_glow.png")); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "blog_glow.png")); } public void actionPerformed(ActionEvent e) { showNewWeblogWizard(); } } //************************************************* //Action for deleting the currently selected weblog //************************************************* private class DeleteWeblogAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public DeleteWeblogAction() { super(i18n.str("delete_weblog_")); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "remove.png")); //$NON-NLS-1$ } public void update() { setEnabled(blogTree.getLastSelectedPathComponent() instanceof Weblog); } public void actionPerformed(ActionEvent e) { if(blogTree.getLastSelectedPathComponent() instanceof Weblog) { Weblog blog = (Weblog)blogTree.getLastSelectedPathComponent(); int yn = JOptionPane.showConfirmDialog(ThingamablogFrame.this, i18n.str("delete_weblog_prompt") + " [" + blog.getTitle() + "]", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ i18n.str("confirm"), //$NON-NLS-1$ JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if(yn == JOptionPane.NO_OPTION) return; try { weblogList.deleteWeblog(blog); taskDialog.removeWeblog(blog); weblogTreeModel.setData(weblogList); //clear the table blogTableModel.setBlogEntries(new BlogEntry[0]); if(searchDialog != null) searchDialog.setWeblogList(weblogList); //updateActions(); saveCurrentData(); blogTree.setSelectionRow(0); //select root note (My Sites) } catch(BackendException ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } } //******************************************* //Actions for creating/opening databases //******************************************* private class NewDatabaseAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; public NewDatabaseAction() { super(i18n.str("new_database_"));//$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("new_database_"))); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { createNewDatabase(); } } private class OpenDatabaseAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; public OpenDatabaseAction() { super(i18n.str("open_database_"));//$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("open_database_"))); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { JFileChooser fc = new JFileChooser(); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setDialogTitle(i18n.str("open_database_title")); //$NON-NLS-1$ fc.setFileFilter(new javax.swing.filechooser.FileFilter() { public boolean accept(File f) { return f.isDirectory() || f.getName().equalsIgnoreCase(TBGlobals.USER_XML_FILENAME); } public String getDescription() { return TBGlobals.USER_XML_FILENAME; } }); int r = fc.showOpenDialog(FRAME); if(r == JFileChooser.CANCEL_OPTION) return; File f = fc.getSelectedFile(); if(f == null) { UIUtils.showError(FRAME, i18n.str("invalid_file")); //$NON-NLS-1$ return; } File dir = f.getParentFile(); openDB(dir); } } //********************************************************* //Actions for manipulating the Web Files folder of a weblog //********************************************************* //Action for importing a file into a Web Files folder private class ImportFileAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; private File lastDir = null; public ImportFileAction() { super(i18n.str("import_file_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("import_file_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "import.png")); //$NON-NLS-1$ } public void update() { setEnabled(isWebFolderSelected()); } public void actionPerformed(ActionEvent e) { if(blogTree.isSelectionEmpty()) return; Object obj = blogTree.getLastSelectedPathComponent(); Object parent = blogTree.getSelectionPath().getParentPath().getLastPathComponent(); //is the Web Files root dir selected? if(obj.toString().equals(WeblogTreeModel.WEB_SITE) && parent instanceof Weblog) obj = ((Weblog)parent).getWebFilesDirectory(); if(obj instanceof File) { File f = (File)obj; if(!f.isDirectory()) return; JFileChooser fc = new JFileChooser(); if(lastDir != null) fc.setCurrentDirectory(lastDir); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(true); fc.setDialogTitle(i18n.str("import_file_title")); //$NON-NLS-1$ int r = fc.showOpenDialog(ThingamablogFrame.this); if(r == JFileChooser.CANCEL_OPTION) return; lastDir = fc.getCurrentDirectory(); File sel[] = fc.getSelectedFiles(); if(sel == null) { UIUtils.showError(ThingamablogFrame.this, i18n.str("invalid_file")); //$NON-NLS-1$ return; } for(int i = 0; i < sel.length; i++) { File outFile = new File(f, sel[i].getName()); //check if the file already exists and prompt for overwrite if(outFile.exists()) { int yn = JOptionPane.showConfirmDialog(FRAME, i18n.str("overwrite") + "[" + outFile.getName() + "]", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ i18n.str("confirm"), //$NON-NLS-1$ JOptionPane.YES_NO_OPTION); if(yn == JOptionPane.NO_OPTION) continue; } try { IOUtils.copy(sel[i], outFile); } catch(IOException ex) { UIUtils.showError(FRAME, ex); } //Utils.copyFile(sel[i].getAbsolutePath(), outFile.getAbsolutePath()); } refreshTree(blogTree); } } } private class NewWebFolderAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public NewWebFolderAction() { super(i18n.str("new_web_folder_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("new_web_folder_"))); //$NON-NLS-1$ putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "new_folder.png")); //$NON-NLS-1$ } public void update() { setEnabled(isWebFolderSelected()); } public void actionPerformed(ActionEvent e) { if(blogTree.isSelectionEmpty()) return; Object obj = blogTree.getLastSelectedPathComponent(); Object parent = blogTree.getSelectionPath().getParentPath().getLastPathComponent(); //is the Web Files root dir selected? if(obj.toString().equals(WeblogTreeModel.WEB_SITE) && parent instanceof Weblog) obj = ((Weblog)parent).getWebFilesDirectory(); if(obj instanceof File) { File f = (File)obj; if(!f.isDirectory()) return; Object o = JOptionPane.showInputDialog( FRAME, i18n.str("enter_folder_name_prompt"), i18n.str("new_folder"), //$NON-NLS-1$ //$NON-NLS-2$ JOptionPane.QUESTION_MESSAGE, null, null, i18n.str("new_folder")); //$NON-NLS-1$ if(o != null) { File newFolder = new File(f, o.toString()); if(newFolder.mkdir()) { refreshTree(blogTree); } else { UIUtils.showError(FRAME, i18n.str("unable_to_create_folder_prompt")); //$NON-NLS-1$ } } } } } //This Action deletes a File or Directory private class DeleteFileAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public DeleteFileAction() { super(i18n.str("delete_")); //$NON-NLS-1$ } public void update() { boolean fileSel = blogTree.getLastSelectedPathComponent() instanceof File; setEnabled(isWebFolderSelected() || fileSel); } public void actionPerformed(ActionEvent e) { TreePath selPath = blogTree.getSelectionPath().getParentPath(); if(selPath.getLastPathComponent() instanceof Weblog) return; if(blogTree.getLastSelectedPathComponent() instanceof File) { File f = (File)blogTree.getLastSelectedPathComponent(); //don't delete the root directory if(f.getAbsolutePath().equals( curSelWeblog.getWebFilesDirectory().getAbsolutePath())) return; int yn = JOptionPane.showConfirmDialog(ThingamablogFrame.this, i18n.str("delete_title") + " '" + f.getName() + "' ?", i18n.str("confirm"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if(yn == JOptionPane.NO_OPTION) return; if(f.isDirectory()) deleteDir(f); else f.delete(); refreshTree(blogTree); } } //recursivly delete a directory private void deleteDir(File file) { if(file.isDirectory()) { File contents[] = file.listFiles(); for (int i = 0; i < contents.length; i++) deleteDir(contents[i]); } file.delete(); } } //Action to rename a file or directory private class RenameFileAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public RenameFileAction() { super(i18n.str("rename_")); //$NON-NLS-1$ } public void update() { boolean fileSel = blogTree.getLastSelectedPathComponent() instanceof File; setEnabled(isWebFolderSelected() || fileSel); } public void actionPerformed(ActionEvent e) { TreePath selPath = blogTree.getSelectionPath().getParentPath(); if(selPath.getLastPathComponent() instanceof Weblog) return; if(blogTree.getLastSelectedPathComponent() instanceof File) { File f = (File)blogTree.getLastSelectedPathComponent(); //don't rename the root directory if(f.getAbsolutePath().equals( curSelWeblog.getWebFilesDirectory().getAbsolutePath())) return; Object o = JOptionPane.showInputDialog( FRAME, i18n.str("rename_title"), i18n.str("rename_title"), //$NON-NLS-1$ //$NON-NLS-2$ JOptionPane.QUESTION_MESSAGE, null, null, f.getName()); if(o != null) { if(f.renameTo(new File(f.getParent(), o.toString()))) { refreshTree(blogTree); if(f.isDirectory()) curSelWeblog.markWebDirectoryUpdated(f); } else { UIUtils.showError(FRAME, i18n.str("unable_to_rename_file_prompt")); //$NON-NLS-1$ } } } } } private class OpenFileAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public OpenFileAction() { super(i18n.str("open_")); //$NON-NLS-1$ } public void update() { TreePath p = blogTree.getSelectionPath(); if(p != null && p.getLastPathComponent() instanceof File) { File f = (File)p.getLastPathComponent(); if(f.isFile()) { setEnabled(TBGlobals.isImageFile(f) || TBGlobals.isTextFile(f)); } } else setEnabled(false); } public void actionPerformed(ActionEvent e) { TreePath p = blogTree.getSelectionPath(); if(p != null && p.getLastPathComponent() instanceof File) { File f = (File)p.getLastPathComponent(); if(f.isFile()) openWebFile(f); } } } //******************************** //Action for editing a template //******************************** private class EditTemplateAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public EditTemplateAction() { super(i18n.str("edit_template_")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("edit_template_"))); //$NON-NLS-1$ } public void update() { TreePath p = blogTree.getSelectionPath(); setEnabled(p != null && p.getLastPathComponent() instanceof Template); } public void actionPerformed(ActionEvent e) { TreePath p = blogTree.getSelectionPath(); if(p != null && p.getLastPathComponent() instanceof Template) { Template t = (Template)blogTree.getLastSelectedPathComponent(); HTMLEditor ed = new HTMLEditor(t); //ed.setSize(640, 480); ed.setVisible(true); //ed.load(); } } } //*************************************************** //Action for sorting the table on the column argument //*************************************************** private class SortTableAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; private int column; public SortTableAction(String label, int tableCol) { super(label); column = tableCol; } public void actionPerformed(ActionEvent e) { if(column >= 0 && column < table.getColumnCount()) { table.sort(column, sortAscending); table.repaint(); } } } //******************************************* //Actions to view the next/previous table row //******************************************* private class NextAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public NextAction() { super(i18n.str("next")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("next"))); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "down.png")); } public void update() { setEnabled(table.getRowCount() > 0 && table.isShowing()); } public void actionPerformed(ActionEvent e) { int selRow = table.getSelectedRow() + 1; if(table.getRowCount() > 0 && selRow >= table.getRowCount()) { table.setRowSelectionInterval(0, 0); scrollToTableRow(selRow); } else if(selRow < table.getRowCount()) { table.setRowSelectionInterval(selRow, selRow); scrollToTableRow(selRow); } } } private class PreviousAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public PreviousAction() { super(i18n.str("previous")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("previous"))); //$NON-NLS-1$ putValue("LARGE_ICON", UIUtils.getIcon(UIUtils.X24, "up.png")); } public void update() { setEnabled(table.getRowCount() > 0 && table.isShowing()); } public void actionPerformed(ActionEvent e) { int selRow = table.getSelectedRow() - 1; if(selRow < 0 && table.getRowCount() > 0) { int r = table.getRowCount() - 1; table.setRowSelectionInterval(r, r); scrollToTableRow(r); } else if(selRow >= 0) { table.setRowSelectionInterval(selRow, selRow); scrollToTableRow(selRow); } } } private class NextUnreadAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public NextUnreadAction() { super(i18n.str("next_unread_item")); //$NON-NLS-1$ putValue(MNEMONIC_KEY, new Integer(i18n.mnem("next_unread_item"))); //$NON-NLS-1$ } public void update() { setEnabled(tableView == ITEM_VIEW && table.getRowCount() > 0); } public void actionPerformed(ActionEvent e) { if(!(table.getModel() instanceof FeedTableModel)) return; int selRow = table.getSelectedRow() + 1; FeedTableModel tm = (FeedTableModel)table.getModel(); while(selRow < table.getRowCount() && tm.isItemAtRowRead(selRow)) { selRow++; } if(selRow < table.getRowCount()) { table.setRowSelectionInterval(selRow, selRow); Rectangle rect = table.getCellRect(selRow, 0, true); table.scrollRectToVisible(rect); } } } //************************************* //Help menu actions //************************************* private class HomePageAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; public HomePageAction() { super(i18n.str("website_")); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { try { //Browser.displayURL(TBGlobals.APP_URL); Desktop.browse(new URL(TBGlobals.APP_URL)); } catch(Exception ex) { ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } } } //************************************************* //class for updating progress/tree on Feed updates //************************************************* private class UpdateMonitor implements UpdateProgress { private boolean isUpdateStarted; private boolean isAborted; public void reset() { isAborted = false; updateFinish(); } public void updateStart(int numOfFeeds) { isUpdateStarted = true; isAborted = false; final int n = numOfFeeds; SwingUtilities.invokeLater(new Runnable() { public void run() { statusBar.getJProgressBar().setMaximum(n); statusBar.getJProgressBar().setValue(0); updateActions(); } }); } public boolean isUpdateStarted() { return isUpdateStarted; } public void feedUpdating(Feed feed) { final Feed f = feed; SwingUtilities.invokeLater(new Runnable() { public void run() { statusBar.setRefreshingText(f.getTitle()); } }); } public int feedUpdated() { final int n = statusBar.getJProgressBar().getValue() + 1; SwingUtilities.invokeLater(new Runnable() { public void run() { statusBar.getJProgressBar().setValue(n); feedTree.repaint();//repaint the tree } }); return n; } public int getUpdateSize() { return statusBar.getJProgressBar().getMaximum(); } public void updateFinish() { SwingUtilities.invokeLater(new Runnable() { public void run() { statusBar.setRefreshingText(""); //$NON-NLS-1$ statusBar.getJProgressBar().setValue(0); updateActions(); } }); isUpdateStarted = false; } public void abortUpdate() { isAborted = true; } public boolean isAborted() { return isAborted; } } //********************************** //Handles posts from entry editors //********************************** private class PostListener extends WindowAdapter { public void windowClosed(WindowEvent e) { Window w = e.getWindow(); /*if(!(w instanceof EntryEditor)) return; EntryEditor editor = (EntryEditor)w;*/ if(!(w instanceof EntryEditor)) return; EntryEditor editor = (EntryEditor)w; editorSize = editor.getSize(); //isEditorWordWrap = editor.isWordWrap(); if(editor.hasUserCancelled()) return; BlogEntry be = editor.getEntry(); int mode = editor.getMode(); boolean shouldPublish = editor.hasUserClickedPublish(); Weblog edBlog = editor.getSelectedWeblog(); try { if(mode == EntryEditor.UPDATE_ENTRY_MODE) { edBlog.updateEntry(be); } else if(mode == EntryEditor.NEW_ENTRY_MODE) { edBlog.addEntry(be); } } catch(Exception ex) { UIUtils.showError(FRAME, i18n.str("error_saving_entry_prompt")); //$NON-NLS-1$ ex.printStackTrace(); logger.log(Level.WARNING, ex.getMessage(), ex); } finally { refreshTree(blogTree); refreshTable(); } if(shouldPublish) publishWeblog(edBlog, PUB_CHANGED); } } private class TimerHandler implements ActionListener { public void actionPerformed(ActionEvent e) { /*if(isDBOpen && !updateMonitor.isUpdateStarted()) updateFolder(feedRoot);*/ } } //******************************************************************** //Link actions - execute when a link is clickedo nthe HTMLOptionsPane //******************************************************************** private class NewEntryLink implements HTMLOptionLink { public String getLinkText() { return i18n.str("compose_entry"); //$NON-NLS-1$ } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.X32 + "edit1.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) showEditor(new BlogEntry(), EntryEditor.NEW_ENTRY_MODE); } } private class ReadEntriesLink implements HTMLOptionLink { public String getLinkText() { return i18n.str("read_previous"); //$NON-NLS-1$ } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.MISC + "read_previous32.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { if(!(blogTree.getLastSelectedPathComponent() instanceof Weblog)) selectWeblog(curViewWeblog); //just move down to the current entries in the tree int rows[] = blogTree.getSelectionRows(); blogTree.expandRow(rows[0]); blogTree.setSelectionRow(rows[0] + 1); } } } private class ConfigureWeblogLink implements HTMLOptionLink { public String getLinkText() { return i18n.str("configure_weblog_settings"); //$NON-NLS-1$ } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.X32 + "config.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) showWeblogConfigDialog(); } } private class PublishLink implements HTMLOptionLink { public String getLinkText() { return i18n.str("publish_weblog"); //$NON-NLS-1$ } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.X32 + "upload.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) publishWeblog(curSelWeblog, PUB_CHANGED); } } private class PublishAllLink implements HTMLOptionLink { public String getLinkText() { return i18n.str("republish"); //$NON-NLS-1$ } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.X32 + "pub_all.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) publishWeblog(curSelWeblog, PUB_ALL); } } private class PingLink implements HTMLOptionLink { public String getLinkText() { return i18n.str("ping_services"); //$NON-NLS-1$ } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.X32 + "ping.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) publishWeblog(curSelWeblog, PING_ONLY); } } private class WeblogLink implements HTMLOptionLink { private Weblog blog; public WeblogLink(Weblog w) { blog = w; } public String getLinkText() { return blog.getTitle(); } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.X32 + "blog.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(!(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)) return; selectWeblog(blog); } } private class NewWeblogLink implements HTMLOptionLink { public String getLinkText() { return i18n.str("create_weblog"); //$NON-NLS-1$ } public URL getImageURL() { return ClassLoader.getSystemResource(UIUtils.X48 + "pencil.png"); //$NON-NLS-1$ } public void hyperlinkUpdate(HyperlinkEvent e) { if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) showNewWeblogWizard(); } } private class MyShutdownHook extends Thread { public void run() { if (isAppOpen) { closeApp(false); } if(curDB != null && isDBOpen) { System.err.println("Shutdown Hook"); //$NON-NLS-1$ try{ backend.shutdown(); }catch(Exception ex){} } } } private class OpenFolderAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public OpenFolderAction() { super(i18n.str("open_")); //$NON-NLS-1$ //Messages.setMnemonic("ThingamablogFrame.Next", this); } public void update() { Object o = blogTree.getLastSelectedPathComponent(); if(o instanceof File) { File f = (File)o; if(f.isDirectory()) { setEnabled(true); return; } } setEnabled(isWebFolderSelected()); } public void actionPerformed(ActionEvent e) { Object o = blogTree.getLastSelectedPathComponent(); File f; if(o instanceof File) { f = (File)o; } else if(isWebFolderSelected()) { f = curSelWeblog.getWebFilesDirectory(); } else return; if(f.isDirectory()) { try { Desktop.open(f); } catch(Exception ex) { ex.printStackTrace(); } } } } private class RefreshBlogTreeAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; public RefreshBlogTreeAction() { super(i18n.str("refresh")); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { refreshTree(blogTree); } } private class ShowTaskDialogAction extends UpdatableAction { /** * */ private static final long serialVersionUID = 1L; public ShowTaskDialogAction() { super(i18n.str("tasks_")); //$NON-NLS-1$ this.putValue(Action.SMALL_ICON, UIUtils.getIcon(UIUtils.X16, "cogs.png")); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { showTaskDialog(); } /* (non-Javadoc) * @see net.sf.thingamablog.gui.UpdatableAction#update() */ public void update() { setEnabled(isDBOpen); } } private class InstallTemplatePackAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; public InstallTemplatePackAction() { super(i18n.str("install_template_pack_")); //$NON-NLS-1$ } public void actionPerformed(ActionEvent e) { JDialog d = new InstallTemplateDialog(FRAME); d.setLocationRelativeTo(FRAME); d.setVisible(true); } } }