// 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: BasicGuideDialog.java,v 1.54 2008/04/03 08:53:25 spyromus Exp $
//
package com.salas.bb.dialogs.guide;
import com.jgoodies.binding.adapter.BoundedRangeAdapter;
import com.jgoodies.binding.value.ValueHolder;
import com.jgoodies.forms.factories.ButtonBarFactory;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.uif.AbstractDialog;
import com.jgoodies.uif.util.ResourceUtils;
import com.salas.bb.core.GlobalController;
import com.salas.bb.core.actions.guide.AbstractReadingListDialog;
import com.salas.bb.dialogs.CollectionItemsSelectionDialog;
import com.salas.bb.domain.GuidesSet;
import com.salas.bb.domain.IGuide;
import com.salas.bb.domain.ReadingList;
import com.salas.bb.domain.utils.GuideIcons;
import com.salas.bb.utils.CommonUtils;
import com.salas.bb.utils.StringUtils;
import com.salas.bb.utils.TimeRange;
import com.salas.bb.utils.i18n.Strings;
import com.salas.bb.utils.uif.*;
import com.salas.bb.utils.uif.table.TooltipTableCellRenderer;
import com.salas.bb.views.mainframe.StarsSelectionComponent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Basic stage for both (add / edit) guide dialogs.
*/
public abstract class BasicGuideDialog extends AbstractDialog
{
private static final String SERVICE_LINK = "http://www.blogbridge.com/";
/** Width of dialog box in pixels. */
private static final int DIALOG_WIDTH = 500;
private final boolean publishingAvailable;
private int publishingLimit;
private boolean publishingLimitReached;
private final JTable tblReadingLists;
private final ReadingListsTableModel readingListsModel;
private final JButton btnAddReadingList;
private final JButton btnRemoveList;
protected JTextField tfTitle = new JTextField();
protected String originalTitle = null;
protected Collection presentTitles;
protected ComboBoxModel model;
protected IconListCellRenderer renderer;
protected JCheckBox chPublishingEnabled;
protected JLabel lbPublishingTitle;
protected JLabel lbPublishingTags;
protected JLabel lbPublishingURL;
protected JLabel lbPublishingPublic;
protected LinkLabel lnkPublishingURL;
protected JLabel lbLastPublishingDate;
protected JLabel tfLastPublishingDate;
protected JTextField tfPublishingTitle;
protected JTextField tfPublishingTags;
protected JCheckBox chPublishingPublic;
protected JLabel lbPublishingRating;
protected StarsSelectionComponent sscPublishingRating;
protected ValueHolder vhPublishingRating;
protected JButton btnCopyToClipboard;
protected JCheckBox chAllowNotifications;
protected JCheckBox chMobile;
protected GuidesSet guidesSet;
/**
* Creates dialog.
*
* @param aFrame parent frame.
* @param aTitle dialog title.
* @param aPublishingAvailable <code>TRUE</code> if publishing is available.
* @param aPublishingLimit the number of guides the user can have published.
* @param aPublishingLimitReached <code>TRUE</code> if the limit is reached.
*/
public BasicGuideDialog(Frame aFrame, String aTitle, boolean aPublishingAvailable,
int aPublishingLimit, boolean aPublishingLimitReached)
{
super(aFrame, aTitle);
publishingAvailable = aPublishingAvailable;
publishingLimit = aPublishingLimit;
publishingLimitReached = aPublishingLimitReached;
presentTitles = Collections.EMPTY_SET;
model = new GuideIcons.ComboBoxModel();
renderer = new IconListCellRenderer();
readingListsModel = new ReadingListsTableModel();
tblReadingLists = new JTable(readingListsModel);
tblReadingLists.setDefaultRenderer(String.class, new ReadingListsTableCellRenderer(readingListsModel));
UifUtilities.setTableColWidth(tblReadingLists, 2, 90);
btnAddReadingList = new JButton(null, ResourceUtils.getIcon("add.icon"));
btnAddReadingList.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
onAddReadingList();
}
});
btnRemoveList = new JButton(null, ResourceUtils.getIcon("delete.icon"));
btnRemoveList.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
onRemoveReadingList();
}
});
// Publishing components
chPublishingEnabled = ComponentsFactory.createCheckBox(Strings.message("guide.dialog.enable.publishing"));
lbPublishingPublic = new JLabel(Strings.message("guide.dialog.public.visibility"));
chPublishingPublic = new JCheckBox();
lbPublishingTitle = ComponentsFactory.createLabel(Strings.message("guide.dialog.reading.list.title"));
lbPublishingTags = ComponentsFactory.createLabel(Strings.message("guide.dialog.tags"));
lbPublishingURL = new JLabel(Strings.message("guide.dialog.publicationurl"));
lnkPublishingURL = new LinkLabel(Strings.message("guide.dialog.not.published.yet"));
lbLastPublishingDate = new JLabel(Strings.message("guide.dialog.last.update.date"));
tfLastPublishingDate = new JLabel(Strings.message("guide.dialog.never.updated"));
tfPublishingTitle = new JTextField();
lbPublishingTitle.setLabelFor(tfPublishingTitle);
tfPublishingTags = new JTextField();
lbPublishingTags.setLabelFor(tfPublishingTags);
chMobile = ComponentsFactory.createCheckBox(Strings.message("guide.dialog.mobile"));
vhPublishingRating = new ValueHolder(1);
sscPublishingRating = new StarsSelectionComponent(new BoundedRangeAdapter(vhPublishingRating, 0, 1, 5));
lbPublishingRating = new JLabel(Strings.message("guide.dialog.rating"));
btnCopyToClipboard = new JButton(Strings.message("guide.dialog.copy"));
btnCopyToClipboard.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
CommonUtils.copyTextToClipboard(lnkPublishingURL.getText());
}
});
onPublishingEnabled();
chPublishingEnabled.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
onPublishingEnabled();
}
});
chAllowNotifications = ComponentsFactory.createCheckBox(Strings.message("guide.dialog.allow.notifications"));
}
/**
* Enabled / disable publishing controls depending on the state of the
* "Enable Publishing" mark.
*/
private void onPublishingEnabled()
{
boolean enabled = chPublishingEnabled.isSelected();
lbPublishingPublic.setEnabled(enabled);
chPublishingPublic.setEnabled(enabled);
lbLastPublishingDate.setEnabled(enabled);
tfLastPublishingDate.setEnabled(enabled);
lbPublishingTags.setEnabled(enabled);
lbPublishingTitle.setEnabled(enabled);
lbPublishingURL.setEnabled(enabled);
lnkPublishingURL.setEnabled(enabled);
btnCopyToClipboard.setEnabled(enabled);
tfPublishingTags.setEnabled(enabled);
tfPublishingTitle.setEnabled(enabled);
lbPublishingRating.setEnabled(enabled);
sscPublishingRating.setEnabled(enabled);
if (enabled && StringUtils.isEmpty(getPublishingTitle()))
{
tfPublishingTitle.setText(getGuideTitle());
}
}
/**
* Invoked when adding new reading list is required.
*/
private void onAddReadingList()
{
if (GlobalController.SINGLETON.checkForNewSubscription()) return;
URL[] newListURLs = queryForURL();
if (newListURLs != null)
{
for (URL url : newListURLs) readingListsModel.addList(url);
}
}
private URL[] queryForURL()
{
NewReadingListDialog dialog = new NewReadingListDialog(this);
dialog.open();
String urlsS = !dialog.hasBeenCanceled() ? dialog.getURLs() : null;
return StringUtils.strToURLs(urlsS);
}
/**
* Invoked when removing selected reading list is required.
*/
private void onRemoveReadingList()
{
int[] rows = tblReadingLists.getSelectedRows();
boolean haveFeeds = false;
for (int i = 0; !haveFeeds && i < rows.length; i++)
{
int row = rows[i];
haveFeeds = readingListsModel.getLists()[row].getFeeds().length > 0;
}
boolean delete = true;
if (haveFeeds)
{
String msg = rows.length == 1
? Strings.message("guide.dialog.readinglists.has.feeds")
: Strings.message("guide.dialog.readinglists.have.feeds");
delete = JOptionPane.showConfirmDialog(this, msg, Strings.message("guide.dialog.delete.readinglist"),
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
}
if (delete) readingListsModel.removeRows(rows);
}
/**
* Returns title entered by user.
*
* @return title.
*/
public String getGuideTitle()
{
return tfTitle.getText();
}
/**
* Returns <code>TRUE</code> if mobility is on.
*
* @return <code>TRUE</code> if mobility is on.
*/
public boolean isMobile()
{
return chMobile.isSelected();
}
/**
* Returns <code>TRUE</code> if publishing is enabled.
*
* @return <code>TRUE</code> when publishing is enabled.
*/
public boolean isPublishingEnabled()
{
return chPublishingEnabled.isSelected();
}
/**
* Returns the title of the reading list the user is going to publish.
*
* @return the title.
*/
public String getPublishingTitle()
{
return tfPublishingTitle.getText().trim();
}
/**
* Returns the tags of the reading list the user is going to publish.
*
* @return the tags.
*/
public String getPublishingTags()
{
return tfPublishingTags.getText().trim();
}
/**
* Returns the state of public publishing flag.
*
* @return the state of the flag.
*/
public boolean isPublishingPublic()
{
return chPublishingPublic.isSelected();
}
/**
* Returns minimum rating of feed to be published.
*
* @return minimum rating.
*/
public int getPublishingRating()
{
return (Integer)vhPublishingRating.getValue();
}
/**
* Returns resource key of selected icon.
*
* @return resource key.
*/
public abstract String getIconKey();
/**
* Registers the list of titles which are not allowed.
*
* @param presTitles titles which are not allowed for entry.
*/
protected void setPresentTitles(Collection presTitles)
{
this.presentTitles = presTitles;
}
/**
* Returns <code>TRUE</code> when guide notifications are allowed.
*
* @return <code>TRUE</code> when guide notifications are allowed.
*/
public boolean isNotificationsAllowed()
{
return chAllowNotifications.isSelected();
}
/**
* Checks if information is valid.
*
* @return error message or NULL if everything is OK.
*/
protected String validateInformation()
{
String msg = validateTitle();
if (msg == null) msg = validatePublishing();
return msg;
}
/**
* Validates the publishing information entered.
*
* @return error message or <code>NULL</code> if everything is OK.
*/
protected String validatePublishing()
{
String msg = null;
if (isPublishingEnabled())
{
String publishingTitle = getPublishingTitle();
if (StringUtils.isEmpty(publishingTitle))
{
msg = Strings.message("guide.dialog.validation.publishing.empty.title");
} else if (StringUtils.indexOfAny(publishingTitle, new String[] { "/", "\"" }) > -1)
{
msg = Strings.message("guide.dialog.validation.publishing.invalid.title");
} else
{
IGuide currentGuide = getGuide();
IGuide otherGuide = guidesSet.getGuideByPublishingTitle(publishingTitle);
if (currentGuide == null
? otherGuide != null
: otherGuide != null && otherGuide != currentGuide)
{
msg = MessageFormat.format(Strings.message("guide.dialog.validation.publishing.existing.title"),
getPublishingTitle());
}
}
}
return msg;
}
/**
* The guide we are looking at.
*
* @return the guide.
*/
protected abstract IGuide getGuide();
/**
* Checks if title is valid.
*
* @return error message or NULL.
*/
protected String validateTitle()
{
String message = null;
final String title = tfTitle.getText();
if (title == null || title.trim().length() == 0)
{
message = Strings.message("guide.dialog.validation.empty.title");
} else if (CommonUtils.areDifferent(originalTitle, title) && presentTitles.contains(title))
{
message = Strings.message("guide.dialog.validation.already.present");
}
return message;
}
/**
* Returns test probe to the caller.
*
* @return test probe.
*/
public Probe getProbe()
{
return new Probe();
}
/**
* Called when user confirms the information.
*/
public void doAccept()
{
String validationMessage = validateInformation();
if (validationMessage == null)
{
super.doAccept();
} else
{
JOptionPane.showMessageDialog(this, validationMessage,
Strings.message("guide.dialog.error"),
JOptionPane.ERROR_MESSAGE);
}
}
/**
* Creates Publishing tab.
*
* @return component.
*/
protected JComponent buildPublishingTab()
{
JComponent wording = ComponentsFactory.createWrappedMultilineLabel(
Strings.message("guide.dialog.publishing.publish"));
return publishingAvailable
? (isReachedPublishingLimit()
? buildPublishingTabLimitReached(wording)
: buildPublishingTabAvailable(wording))
: buildPublishingTabUnavailable(wording);
}
/**
* Tests if the publishing limit is reached.
*
* @return <code>TRUE</code> if the limit has been reached and it's not the already published guide.
*/
private boolean isReachedPublishingLimit()
{
return publishingLimitReached && !chPublishingEnabled.isSelected();
}
/**
* Builds the panel for publishing tab when too many guides are already published.
*
* @param wording wording to put on the page.
*
* @return component.
*/
private JPanel buildPublishingTabLimitReached(JComponent wording)
{
BBFormBuilder builder = new BBFormBuilder("0:grow");
builder.setDefaultDialogBorder();
builder.append(wording);
builder.appendUnrelatedComponentsGapRow(2);
builder.append(ComponentsFactory.createWrappedMultilineLabel(
MessageFormat.format(Strings.message("guide.dialog.publishing.limit.reached"), publishingLimit)));
builder.appendUnrelatedComponentsGapRow(2);
LinkLabel link = new LinkLabel(Strings.message("guide.dialog.publishing.limit.reached.link"), SERVICE_LINK);
builder.append(link);
return builder.getPanel();
}
/**
* Builds panel for publishing tab when publishing is unavailable.
*
* @param aWording wording to put on the page.
*
* @return component.
*/
private JPanel buildPublishingTabUnavailable(JComponent aWording)
{
// Panel
BBFormBuilder builder = new BBFormBuilder("0:grow");
builder.setDefaultDialogBorder();
builder.append(aWording);
builder.appendUnrelatedComponentsGapRow(2);
builder.append(ComponentsFactory.createWrappedMultilineLabel(
Strings.message("guide.dialog.publishing.you.need.bbservice.account")));
return builder.getPanel();
}
/**
* Builds panel for publishing tab when publishing is available.
*
* @param aWording wording to put on the page.
*
* @return component.
*/
private JPanel buildPublishingTabAvailable(JComponent aWording)
{
JPanel sscPanel = new JPanel(new BorderLayout());
sscPanel.add(sscPublishingRating, BorderLayout.WEST);
// Panel
BBFormBuilder builder = new BBFormBuilder("7dlu, p, 2dlu, 100dlu, 0:grow, 2dlu, p");
builder.setDefaultDialogBorder();
builder.append(aWording, 7);
builder.appendUnrelatedComponentsGapRow(2);
builder.append(chMobile, 7);
builder.append(chPublishingEnabled, 7);
builder.setLeadingColumnOffset(1);
builder.append(lbPublishingTitle, tfPublishingTitle);
builder.nextLine();
builder.append(lbPublishingTags, tfPublishingTags);
builder.nextLine();
builder.append(lbPublishingPublic, chPublishingPublic);
builder.nextLine();
builder.append(lbPublishingRating, sscPanel);
builder.appendUnrelatedComponentsGapRow(2);
builder.append(lbPublishingURL);
builder.append(lnkPublishingURL, 2);
builder.append(btnCopyToClipboard);
builder.append(lbLastPublishingDate, tfLastPublishingDate);
builder.setLeadingColumnOffset(0);
builder.appendUnrelatedComponentsGapRow(2);
builder.appendRow("min:grow");
JComponent instructionsBox = ComponentsFactory.createInstructionsBox(
Strings.message("guide.dialog.publishing.instructions"));
builder.append(instructionsBox, 7, CellConstraints.FILL, CellConstraints.FILL);
return builder.getPanel();
}
private JComponent msg(String msg)
{
return ComponentsFactory.createWrappedMultilineLabel(msg);
}
/**
* Creates notifications panel.
*
* @return panel.
*/
protected JComponent buildNotificationsTab()
{
// Wording
JComponent wording = msg(Strings.message("guide.dialog.notifications.wording"));
// Panel
BBFormBuilder builder = new BBFormBuilder("0:grow");
builder.setDefaultDialogBorder();
builder.append(wording);
builder.appendUnrelatedComponentsGapRow(2);
builder.append(chAllowNotifications);
return builder.getPanel();
}
/**
* Builds reading lists tab.
*
* @return component.
*/
protected JComponent buildReadingListsTab()
{
// Wording
JComponent wording = msg(Strings.message("guide.dialog.readinglists.wording"));
// Buttons
Dimension btnSize = new Dimension(20, 20);
btnAddReadingList.setPreferredSize(btnSize);
btnRemoveList.setPreferredSize(btnSize);
FlowLayout layout = new FlowLayout(FlowLayout.LEFT);
JPanel bbar = new JPanel(layout);
bbar.add(btnAddReadingList);
bbar.add(btnRemoveList);
layout.setHgap(0);
layout.setVgap(0);
// Panel
BBFormBuilder builder = new BBFormBuilder("0:grow");
builder.setDefaultDialogBorder();
builder.append(wording);
builder.appendUnrelatedComponentsGapRow(2);
builder.appendRow("min:grow");
builder.append(new JScrollPane(tblReadingLists), 1,
CellConstraints.FILL, CellConstraints.FILL);
builder.append(bbar);
return builder.getPanel();
}
/**
* Shows given list of reading lists.
*
* @param lists lists.
*/
protected void setReadingLists(ReadingList[] lists)
{
tblReadingLists.setEnabled(lists != null);
btnAddReadingList.setEnabled(lists != null);
btnRemoveList.setEnabled(lists != null);
readingListsModel.setLists(lists);
}
/**
* Returns currently displayed list of reading lists.
*
* @return list which is currently displayed.
*/
public ReadingList[] getReadingLists()
{
return readingListsModel.getLists();
}
protected void resizeHook(JComponent content)
{
int height = (int)(DIALOG_WIDTH * 1.1);
content.setPreferredSize(new Dimension(DIALOG_WIDTH, height));
}
/**
* Opens a dialog.
*
* @param set guides set.
*/
public void openDialog(GuidesSet set)
{
guidesSet = set;
super.open();
}
/**
* Renders simple icon element basing on the key of resource passed in <code>value</code>
* parameter as a String.
*/
protected static class IconListCellRenderer extends JPanel
implements ListCellRenderer
{
private JLabel iconLabel = new JLabel();
/**
* Constructs new cell renderer.
*/
public IconListCellRenderer()
{
add(iconLabel);
}
/**
* Return a component that has been configured to display the specified
* value.
*
* @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList,
* Object, int, boolean, boolean)
*/
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
final String key = (String)value;
final Icon icon = IconSource.getIcon(key);
final Color back = isSelected ? list.getSelectionBackground() : list.getBackground();
setBackground(back);
iconLabel.setBackground(back);
iconLabel.setIcon(icon);
return this;
}
}
/**
* Cell renderer that makes missing reading lists appear gray.
*/
private static class ReadingListsTableCellRenderer extends TooltipTableCellRenderer
{
private final ReadingListsTableModel model;
/**
* Creates cell renderer.
*
* @param model model.
*/
public ReadingListsTableCellRenderer(ReadingListsTableModel model)
{
this.model = model;
}
/**
* Returns the default table cell renderer.
*
* @param table the <code>JTable</code>
* @param value the value to assign to the cell at
* <code>[row, column]</code>
* @param isSelected true if cell is selected
* @param hasFocus true if cell has focus
* @param row the row of the cell to render
* @param column the column of the cell to render
* @return the default table cell renderer
*/
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column)
{
ReadingList list = model.getLists()[row];
Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
comp.setForeground(list.isMissing() ? Color.GRAY : table.getForeground());
return comp;
}
}
/**
* Reading lists table model.
*/
private static class ReadingListsTableModel extends DefaultTableModel
{
// Format for dates
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("EEE MMM dd, yy");
/** List name. */
public static final int COL_NAME = 0;
/** List URL. */
public static final int COL_URL = 1;
/** List latest update time. */
public static final int COL_LATEST = 2;
private static final String[] COLUMNS = {
Strings.message("guide.dialog.readinglists.table.name"),
Strings.message("guide.dialog.readinglists.table.url"),
Strings.message("guide.dialog.readinglists.table.latest")
};
private static final Class[] CLASSES = { String.class, String.class, String.class };
private ReadingList[] lists;
/**
* Returns current version of reading lists.
*
* @return current version.
*/
public ReadingList[] getLists()
{
return lists;
}
/**
* Sets the version of reading lists.
*
* @param aLists lists.
*/
public void setLists(ReadingList[] aLists)
{
lists = aLists;
fireTableDataChanged();
}
/**
* Returns number of columns in this table.
*
* @return columns
*/
public int getColumnCount()
{
return COLUMNS.length;
}
/**
* Returns number of rows in the table.
*
* @return rows.
*/
public int getRowCount()
{
return lists == null ? 0 : lists.length;
}
/**
* Returns value of a cell.
*
* @param row row.
* @param column column.
*
* @return value.
*/
public Object getValueAt(int row, int column)
{
Object value;
ReadingList list = lists[row];
switch (column)
{
case COL_NAME:
value = list.getTitle();
break;
case COL_URL:
value = list.getURL().toString();
break;
case COL_LATEST:
long lastPollTime = list.getLastPollTime();
value = pollTimeToString(lastPollTime);
break;
default:
value = null;
}
return value;
}
/**
* Converts timestamp into some string representation.
*
* @param aTime time to convert.
*
* @return string.
*/
private String pollTimeToString(long aTime)
{
String timeS;
if (aTime == -1)
{
timeS = Strings.message("guide.dialog.readinglists.table.latest.never");
} else
{
TimeRange range = findTimeRange(aTime);
if (range == TimeRange.TR_FUTURE)
{
timeS = Strings.message("guide.dialog.readinglists.table.latest.never");
} else if (range == TimeRange.TR_TODAY)
{
DateFormat fmt = DateFormat.getTimeInstance(DateFormat.SHORT);
timeS = MessageFormat.format(Strings.message("guide.dialog.readinglists.table.latest.today.0"),
fmt.format(new Date(aTime)));
} else if (range == TimeRange.TR_YESTERDAY)
{
DateFormat fmt = DateFormat.getTimeInstance(DateFormat.SHORT);
timeS = MessageFormat.format(Strings.message("guide.dialog.readinglists.table.latest.yesterday.0"),
fmt.format(new Date(aTime)));
} else
{
timeS = DATE_FORMAT.format(new Date(aTime));
}
}
return timeS;
}
/**
* Finds range matching this time.
*
* @param aTime time.
*
* @return range.
*/
private TimeRange findTimeRange(long aTime)
{
TimeRange range = null;
for (int i = 0; range == null && i < TimeRange.TIME_RANGES.length; i++)
{
TimeRange timeRange = TimeRange.TIME_RANGES[i];
if (timeRange.isInRange(aTime)) range = timeRange;
}
return range;
}
/**
* None of the cells editable.
*
* @param row row.
* @param column column.
*
* @return <code>FALSE</code>.
*/
public boolean isCellEditable(int row, int column)
{
return false;
}
/**
* Returns the title of the column.
*
* @param column column.
*
* @return title.
*/
public String getColumnName(int column)
{
return COLUMNS[column];
}
/**
* Returns data class of the column.
*
* @param column column.
*
* @return class.
*/
public Class getColumnClass(int column)
{
return CLASSES[column];
}
/**
* Removes specific rows from the list of reading lists.
*
* @param aRows rows to remove.
*/
public void removeRows(int[] aRows)
{
Arrays.sort(aRows);
java.util.List<ReadingList> newLists = new ArrayList<ReadingList>(Arrays.asList(lists));
for (int i = aRows.length - 1; i >= 0; i--)
{
newLists.remove(aRows[i]);
}
setLists(newLists.toArray(new ReadingList[newLists.size()]));
}
/**
* Adds new reading list URL.
*
* @param aNewListURL new reading list.
*/
public void addList(URL aNewListURL)
{
ReadingList[] newList = new ReadingList[lists.length + 1];
System.arraycopy(lists, 0, newList, 0, lists.length);
newList[lists.length] = new ReadingList(aNewListURL);
setLists(newList);
}
}
/**
* New reading list addition dialog with verification of URL.
*/
private class NewReadingListDialog extends AbstractReadingListDialog
{
private final JButton btnSuggest;
/**
* Creates dialog.
*
* @param parent parent dialog.
*/
public NewReadingListDialog(Dialog parent)
{
super(parent, Strings.message("guide.dialog.add.readinglist"));
btnSuggest = new JButton(new SuggestAction());
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
}
/**
* Repacks the window each time it is displayed to adjust size to fit
* wording and buttons.
*
* @param e event.
*/
protected void processWindowEvent(WindowEvent e)
{
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_OPENED) pack();
}
/**
* Builds main part.
*
* @return main part.
*/
protected JComponent buildMain()
{
BBFormBuilder builder = new BBFormBuilder("pref, 4dlu, max(pref;200px):grow, 4dlu, p");
builder.setDefaultDialogBorder();
JComponent wording = ComponentsFactory.createWrappedMultilineLabel(
Strings.message("guide.dialog.readinglists.add.wording"));
builder.append(wording, 3);
builder.appendUnrelatedComponentsGapRow(2);
builder.append(Strings.message("guide.dialog.readinglists.add.address"), tfAddress);
builder.append(btnSuggest);
builder.append(Strings.message("guide.dialog.readinglists.add.status"), lbStatus);
return builder.getPanel();
}
/**
* Builds buttons.
*
* @return buttons.
*/
protected JComponent buildButtons()
{
return ButtonBarFactory.buildOKCancelBar(btnCheckAndAdd, createCancelButton());
}
private class SuggestAction extends AbstractAction
{
/**
* Defines an <code>Action</code> object with a default
* description string and default icon.
*/
public SuggestAction()
{
super(Strings.message("guide.dialog.readinglists.add.suggest"));
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed(ActionEvent e)
{
CollectionItemsSelectionDialog dialog =
new CollectionItemsSelectionDialog(BasicGuideDialog.this);
tfAddress.setText(dialog.open("", new ArrayList(), true));
if (!dialog.hasBeenCanceled()) NewReadingListDialog.super.doAccept();
}
}
}
/**
* Testing agent used in tests.
*/
public class Probe
{
/**
* Initializes structured and values necessary for title validation.
*
* @param orgTitle original title (NULL for new guide).
* @param prTitles list of present titles.
* @param title title entered by user.
*
* @return TRUE if validation was successful.
*/
public boolean validate(String orgTitle, Collection prTitles, String title)
{
originalTitle = orgTitle;
setPresentTitles(prTitles);
tfTitle.setText(title);
return validateInformation() == null;
}
}
}