// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2007 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: AbstractReport.java,v 1.5 2008/04/01 12:51:27 spyromus Exp $
//
package com.salas.bb.reports;
import com.jgoodies.uifextras.util.PopupAdapter;
import com.salas.bb.core.GlobalModel;
import com.salas.bb.domain.DirectFeed;
import com.salas.bb.domain.GuidesSet;
import com.salas.bb.domain.IFeed;
import com.salas.bb.domain.IGuide;
import com.salas.bb.reports.actions.BrowseFeed;
import com.salas.bb.reports.actions.DeleteFeed;
import com.salas.bb.reports.actions.DeleteGuide;
import com.salas.bb.reports.actions.MarkAsRead;
import com.salas.bb.utils.uif.LinkLabel;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.util.Hashtable;
import java.util.Map;
/**
* Abstract report taking care of all little details.
*/
abstract class AbstractReport extends JPanel implements IReport
{
/** Feed only. Post-to-blog action. */
public static final String ACTION_POST_TO_BLOG = "post to blog";
/** Guide and Feed. Mark as read. */
public static final String ACTION_MARK_AS_READ = "mark as read";
/** Guide and Feed. Mark as unread. */
public static final String ACTION_MARK_AS_UNREAD = "mark as unread";
/** Guide and Feed. Delete. */
public static final String ACTION_DELETE = "delete";
/** Feed. Open in browser. */
public static final String ACTION_BROWSE = "browse";
/** Flags if the data is already initialized. */
private volatile boolean initialized;
/** Flags if the layout is already performed. */
private volatile boolean laidOut;
/** Callback reports can use to report clicks. */
protected IClickCallback clickCallback;
/**
* Sets a callback a report can use to report clicks on entities.
*
* @param callback callback.
*/
public void setClickCallback(IClickCallback callback)
{
clickCallback = callback;
}
/**
* Initializes data for the view.
*
* @param provider report data provider.
*/
public final synchronized void initializeData(IReportDataProvider provider)
{
if (initialized) return;
doInitializeData(provider);
initialized = true;
}
/**
* Returns <code>TRUE</code> when data is initialized.
*
* @return <code>TRUE</code> when data is initialized.
*/
public boolean isDataInitialized()
{
return initialized;
}
/**
* Initializes data for the view.
*
* @param provider report data provider.
*/
protected abstract void doInitializeData(IReportDataProvider provider);
/**
* Prepares the view for the display. Should be called after the initializeData() method.
*
* @throws IllegalStateException if called when data is still not initialized.
*/
public final synchronized void layoutView()
{
if (!initialized) throw new IllegalStateException("Not initialized by initializeData()");
if (laidOut) return;
doLayoutView();
laidOut = true;
}
/**
* Prepares the view for the display. Should be called after the initializeData() method.
*/
protected abstract void doLayoutView();
/**
* Invoked when a users presses the reset button. If the report knows what to do, it can be done. Otherwise the
* report data should be cleared and the initializeData() call expected.
*/
public synchronized void reset()
{
initialized = false;
laidOut = false;
}
@Override
public String toString()
{
return getReportName();
}
/**
* Returns the report page component.
*
* @return component.
*/
public JComponent getReportPage()
{
return this;
}
/**
* Returns the map of action names to actions for a given guide.
*
* @param guide guide.
*
* @return actions.
*/
protected Map<String, Action> getGuideActionsMap(IGuide guide)
{
Map<String, Action> actions = new Hashtable<String, Action>();
actions.put(ACTION_MARK_AS_READ, MarkAsRead.createForGuide(guide, true));
actions.put(ACTION_MARK_AS_UNREAD, MarkAsRead.createForGuide(guide, false));
actions.put(ACTION_DELETE, new DeleteGuide(guide));
return actions;
}
/**
* Returns the map of action names to actions for a given feed.
*
* @param feed feed.
*
* @return actions.
*/
protected Map<String, Action> getFeedActionsMap(IFeed feed)
{
Map<String, Action> actions = new Hashtable<String, Action>();
actions.put(ACTION_MARK_AS_READ, MarkAsRead.createForFeed(feed, true));
actions.put(ACTION_MARK_AS_UNREAD, MarkAsRead.createForFeed(feed, false));
actions.put(ACTION_DELETE, new DeleteFeed(feed, null));
if (feed instanceof DirectFeed)
{
actions.put(ACTION_BROWSE, new BrowseFeed(feed));
}
return actions;
}
/**
* Returns a guide by its ID or <code>NULL</code> if not found.
*
* @param id guide ID.
*
* @return guide by its ID or <code>NULL</code> if not found.
*/
protected IGuide getGuideById(long id)
{
if (id < 0) return null;
GuidesSet set = GlobalModel.SINGLETON.getGuidesSet();
return set.findGuideByID(id);
}
/**
* Returns a feed by its ID or <code>NULL</code> if not found.
*
* @param id feed ID.
*
* @return feed by its ID or <code>NULL</code> if not found.
*/
protected IFeed getFeedById(long id)
{
if (id < 0) return null;
GuidesSet set = GlobalModel.SINGLETON.getGuidesSet();
return set.findFeedByID(id);
}
/**
* Creates a clickable label for guide.
*
* @param guide guide.
*
* @return lable.
*/
protected JLabel createGuideLabel(IGuide guide)
{
LinkLabel label = LinkLabel.create(guide.getTitle(), new GuideClickAction(guide, guide.getID()));
label.addMouseListener(new GuidePopupAdapter(guide, -1));
return label;
}
/**
* Creates a clickable label for guide.
*
* @param id id.
* @param title title.
*
* @return lable.
*/
protected JLabel createGuideLabel(long id, String title)
{
LinkLabel label = LinkLabel.create(title, new GuideClickAction(null, id));
label.addMouseListener(new GuidePopupAdapter(null, id));
return label;
}
/**
* Creates a clickable label for feeds.
*
* @param feed feed.
*
* @return lable.
*/
protected JLabel createFeedLabel(IFeed feed)
{
LinkLabel label = LinkLabel.create(feed.getTitle(), new FeedClickAction(feed, feed.getID()));
label.addMouseListener(new FeedPopupAdapter(feed, -1));
return label;
}
/**
* Creates a clickable label for feeds.
*
* @param id id.
* @param title title.
*
* @return lable.
*/
protected JLabel createFeedLabel(long id, String title)
{
LinkLabel label = LinkLabel.create(title, new FeedClickAction(null, id));
label.addMouseListener(new FeedPopupAdapter(null, id));
return label;
}
/** Feed click action that reports the event to the click callback. */
private class FeedClickAction extends AbstractAction
{
/** Feed ID. */
private final long id;
/** Feed to select. */
private final IFeed feed;
/**
* Creates an action. You can specify either of options. Feed takes prio.
*
* @param feed feed to select.
* @param id feed id to select.
*/
private FeedClickAction(IFeed feed, long id)
{
this.feed = feed;
this.id = id;
}
/**
* Invoked when an action occurs.
*
* @param e event.
*/
public void actionPerformed(ActionEvent e)
{
if (feed != null)
{
clickCallback.feedClicked(feed);
} else if (id != -1)
{
clickCallback.feedClicked(id);
}
}
}
/** Guide click action that reports the event to the click callback. */
protected class GuideClickAction extends AbstractAction
{
/** Guide ID. */
private final long id;
/** Guide to select. */
private final IGuide guide;
/**
* Creates an action. You can specify either of options. Guide takes prio.
*
* @param guide guide to select.
* @param id guide id to select.
*/
protected GuideClickAction(IGuide guide, long id)
{
this.guide = guide;
this.id = id;
}
/**
* Invoked when an action occurs.
*
* @param e event.
*/
public void actionPerformed(ActionEvent e)
{
if (guide != null)
{
clickCallback.guideClicked(guide);
} else if (id != -1)
{
clickCallback.guideClicked(id);
}
}
}
/**
* Guide popup adapter shows the popup menu when the gesture is detected.
*/
protected class GuidePopupAdapter extends PopupAdapter
{
private IGuide guide;
private long id;
/**
* Creates a popup adapter.
*
* @param guide guide.
* @param id guide ID.
*/
public GuidePopupAdapter(IGuide guide, long id)
{
this.guide = guide;
this.id = id;
}
/**
* Builds a menu for the guide link label.
*
* @param event event.
*
* @return menu.
*/
protected JPopupMenu buildPopupMenu(MouseEvent event)
{
JPopupMenu menu = new JPopupMenu();
if (guide == null) guide = getGuideById(id);
if (guide == null || guide.getID() == -1)
{
menu.add("Guide is gone");
} else
{
Map<String, Action> actions = getActions();
for (Action action : actions.values()) menu.add(action);
}
return menu;
}
/**
* Returns the map of actions.
*
* @return actions.
*/
protected Map<String, Action> getActions()
{
return getGuideActionsMap(guide);
}
}
/**
* Feed popup adapter shows the popup menu when the gesture is detected.
*/
protected class FeedPopupAdapter extends PopupAdapter
{
private IFeed feed;
private long id;
/**
* Creates a popup adapter.
*
* @param feed feed.
* @param id feed ID.
*/
public FeedPopupAdapter(IFeed feed, long id)
{
this.feed = feed;
this.id = id;
}
/**
* Builds a menu for the feed link label.
*
* @param event event.
*
* @return menu.
*/
protected JPopupMenu buildPopupMenu(MouseEvent event)
{
JPopupMenu menu = new JPopupMenu();
if (feed == null) feed = getFeedById(id);
if (feed == null || feed.getID() == -1)
{
menu.add("Feed is gone");
} else
{
Map<String, Action> actions = getFeedActionsMap(feed);
for (Action action : actions.values()) menu.add(action);
}
return menu;
}
}
}