// BlogBridge -- RSS feed reader, manager, and web based service // Copyright (C) 2002-2006 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: ActivityIndicatorView.java,v 1.32 2008/04/07 18:26:04 spyromus Exp $ // package com.salas.bb.views; import com.jgoodies.uif.util.ResourceUtils; import com.salas.bb.utils.ConnectionState; import com.salas.bb.utils.ResourceID; import com.salas.bb.utils.StringUtils; import com.salas.bb.utils.i18n.Strings; import com.salas.bb.utils.uif.ActivityIndicatorBox; import javax.swing.*; import java.awt.*; import java.awt.event.MouseListener; import java.text.MessageFormat; import java.util.List; import java.util.TimerTask; import java.util.Vector; /** * Singleton object that is used to give user feedback of activity in BlogBridge. Note the 'model' * is so simple that for now it's built right in. */ public final class ActivityIndicatorView extends JPanel { private static ActivityIndicatorView INSTANCE; private static final int BLINK_PERIOD = 400; // millis private NetworkActivityIndicator indNetwork; private ActivityIndicatorBox indDisk; private List ticketsWebStats = new Vector(); private List ticketsDisk = new Vector(); private List ticketsCommon = new Vector(); /** * Creates indicators view. * * @param connectionState connection state to get connection information from. * @param connectionMouseListener mouse listener for network monitor icon. */ public ActivityIndicatorView(ConnectionState connectionState, MouseListener connectionMouseListener) { indDisk = new ActivityIndicatorBox( ResourceUtils.getIcon(ResourceID.ICON_ACTIVITY_DISK_ACTIVE), ResourceUtils.getIcon(ResourceID.ICON_ACTIVITY_DISK_PASSIVE) ); indNetwork = new NetworkActivityIndicator( connectionState, ResourceUtils.getIcon(ResourceID.ICON_CONNECTED), ResourceUtils.getIcon(ResourceID.ICON_DISCONNECTED), ResourceUtils.getIcon(ResourceID.ICON_ACTIVITY_NETWORK_ACTIVE), ResourceUtils.getIcon(ResourceID.ICON_ACTIVITY_NETWORK_PASSIVE) ); indNetwork.addMouseListener(connectionMouseListener); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); add(indDisk); add(indNetwork); java.util.Timer blinker = new java.util.Timer(true); blinker.scheduleAtFixedRate(new Blinker(), 0, BLINK_PERIOD); INSTANCE = this; } /** * Indicate the start of Discovery processing. * * @param link link which is under discovery. * * @return ticket. */ public static synchronized ActivityTicket startDiscovery(String link) { return INSTANCE.startActivity(ActivityTicket.TYPE_NETWORK, MessageFormat.format(Strings.message("activity.discovering"), new Object[] { link })); } /** * Indicates the start of polling a Feed. * * @param feed title of feed. * * @return task ticket. */ public static synchronized ActivityTicket startPolling(String feed) { return INSTANCE.startActivity(ActivityTicket.TYPE_NETWORK, MessageFormat.format(Strings.message("activity.polling"), new Object[] { feed })); } /** * Indicate the start of opening database. * * @return task ticket. */ public static synchronized ActivityTicket startOpeningDatabase() { return INSTANCE.startActivity(ActivityTicket.TYPE_DISK, Strings.message("activity.opening.database")); } /** * Starts displaying activity of a given type with specified message. * * @param type type of activity. * @param title message. * * @return activity ticket. */ private ActivityTicket startActivity(final int type, String title) { ActivityTicket ticket; ticket = new ActivityTicket(type, title); List tickets = getTicketsByType(type); if (tickets.add(ticket)) updateBox(type); return ticket; } /** * Finishes activity represented by a specified ticket. * * @param ticket activity ticket. */ public static synchronized void finishActivity(ActivityTicket ticket) { final int type = ticket.getType(); List tickets = INSTANCE.getTicketsByType(type); if (tickets.remove(ticket)) INSTANCE.updateBox(type); } /** * Updates the view of indication box of a givn type. * * @param aType type of activity. */ private void updateBox(final int aType) { List ticketsL = getTicketsByType(aType); final String[] tasks = new String[ticketsL.size()]; for (int i = 0; i < ticketsL.size(); i++) { ActivityTicket ticket = (ActivityTicket)ticketsL.get(i); tasks[i] = ticket.getDisplayInfo(); } SwingUtilities.invokeLater(new Runnable() { public void run() { if (aType == ActivityTicket.TYPE_NETWORK) { indNetwork.setTasks(tasks); } else { indDisk.setTasksList(tasks); } } }); } /** * Returns array of tickets for the activity of the given type. * * @param type type of activity. * * @return list of tickets. */ private List getTicketsByType(int type) { List tickets; switch(type) { case ActivityTicket.TYPE_NETWORK: tickets = ticketsWebStats; break; case ActivityTicket.TYPE_DISK: tickets = ticketsDisk; break; default: tickets = ticketsCommon; break; } return tickets; } /** * Returns number of tasks of specified type of activity currently running. * * @param aType type of activity. * * @return number of tasks. */ static int getNumberOfTasks(int aType) { return INSTANCE.getTicketsByType(aType).size(); } /** * Simple timer task which is intended to kick indication boxes * each blink tick. If indication box is in active state it will * change icon the the one, which corresponds to the specified * state to emulate blink effect. */ private class Blinker extends TimerTask { private final Blink active = new Blink(true); private final Blink passive = new Blink(false); private int count = 0; public void run() { boolean activeState = count++ % 2 == 0; SwingUtilities.invokeLater(activeState ? active : passive); } } /** * Blinker events. */ private class Blink implements Runnable { private final boolean activeState; public Blink(boolean aActiveState) { activeState = aActiveState; } public void run() { indDisk.blink(activeState); indNetwork.blink(); } } /** * Network acitivity indicator component. */ private static class NetworkActivityIndicator extends JLabel { private static final String OFFLINE = Strings.message("activity.offline"); private static final String ONLINE = Strings.message("activity.online"); private final ConnectionState conState; private final Icon connected; private final Icon disconnected; private final Icon active; private final Icon inactive; private String tasksList; /** * Creates component. * * @param conState connection state listener. * @param connected connected icon. * @param disconnected disconnected icon. * @param active active state icon. * @param inactive inactive state icon. */ public NetworkActivityIndicator(ConnectionState conState, Icon connected, Icon disconnected, Icon active, Icon inactive) { this.conState = conState; this.connected = connected; this.disconnected = disconnected; this.active = active; this.inactive = inactive; setHorizontalAlignment(SwingConstants.CENTER); Dimension size = new Dimension(0, 0); size = findMaxSize(size, connected); size = findMaxSize(size, disconnected); size = findMaxSize(size, active); size = findMaxSize(size, inactive); setMinimumSize(size); setMaximumSize(size); setPreferredSize(size); } /** * Finds maximum size among given and the icon. * * @param size size. * @param icon icon. * * @return max size. */ private static Dimension findMaxSize(Dimension size, Icon icon) { size.width = Math.max(size.width, icon.getIconWidth()); size.height = Math.max(size.height, icon.getIconHeight()); return size; } /** * Updates icon and tooltip; */ private void updateIconAndTooltip() { Icon icon; String tooltip; if (!conState.isOnline()) { icon = disconnected; tooltip = OFFLINE; } else { if (tasksList == null) { icon = connected; tooltip = ONLINE; } else { long time = System.currentTimeMillis(); boolean activeIcon = (time / BLINK_PERIOD) % 2 == 0; icon = activeIcon ? active : inactive; tooltip = tasksList; } } setIcon(icon); setToolTipText(tooltip); } /** * Sets new list of tasks. * * @param tasks tasks. */ public void setTasks(String[] tasks) { tasksList = tasks == null || tasks.length == 0 ? null : "<html>" + StringUtils.join(tasks, "<br>"); updateIconAndTooltip(); } /** * Orders to make a blink. */ public void blink() { updateIconAndTooltip(); } } }