// 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: SyncSettingsPanel.java,v 1.19 2007/02/22 11:55:45 spyromus Exp $ // package com.salas.bb.service; import com.jgoodies.binding.adapter.DocumentAdapter; import com.jgoodies.binding.adapter.ToggleButtonAdapter; import com.jgoodies.binding.beans.PropertyAdapter; import com.jgoodies.binding.value.BufferedValueModel; import com.jgoodies.binding.value.ValueModel; import com.jgoodies.uif.AbstractDialog; import com.jgoodies.uif.util.ResourceUtils; import com.salas.bb.core.GlobalController; import com.salas.bb.service.sync.SyncFullAction; import com.salas.bb.service.sync.SyncInAction; import com.salas.bb.service.sync.SyncOutAction; import com.salas.bb.utils.DateUtils; import com.salas.bb.utils.i18n.Strings; import com.salas.bb.utils.uif.*; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Date; /** * Panel of synchronization settings. */ class SyncSettingsPanel extends JPanel implements IRegistrationListener { private JTextField tfEmail = new JTextField(); private JPasswordField tfPassword = new JPasswordField(); private JLabel lbLastSyncIn = new JLabel("unknown"); private JLabel lbLastSyncOut = new JLabel("unknown"); private JTextField tfSyncPeriod = new JTextField(); private AbstractDialog parentDialog; private ServicePreferences servicePrefs; private JRadioButton rbModePeriodical; private JRadioButton rbModeEachRun; private JRadioButton rbModeManual; private JCheckBox chFeedList; private JCheckBox chPreferences; private JButton btnSyncNow; private CustomPopupButton btnMoreSyncOptions; /** * Creates panel. * * @param parentDiag parent dialog. * @param prefs service preferences. * @param triggerChannel value model. */ public SyncSettingsPanel(AbstractDialog parentDiag, ServicePreferences prefs, ValueModel triggerChannel) { this.parentDialog = parentDiag; servicePrefs = prefs; LinkLabel lnkSignUp = new LinkLabel(Strings.message("service.registration.signup"), ResourceUtils.getString("server.signup.url")); initComponents(triggerChannel); JPanel buttonBar = new JPanel(); buttonBar.add(btnSyncNow); buttonBar.add(btnMoreSyncOptions); BBFormBuilder builder = new BBFormBuilder( "7dlu, pref, 2dlu, pref:grow, 2dlu, 20dlu, 2dlu, 80dlu:grow"); builder.setDefaultDialogBorder(); builder.appendSeparator(Strings.message("service.registration.account.information")); builder.append(Strings.message("service.registration.email"), 2, tfEmail, 5); builder.append(Strings.message("service.registration.password"), 2, tfPassword, 5); builder.append("", 2, lnkSignUp, 5); builder.appendSeparator(Strings.message("service.sync.mode.of.operation")); builder.setLeadingColumnOffset(1); builder.append(rbModePeriodical, 3); builder.append(tfSyncPeriod); builder.append(Strings.message("service.sync.days"), 1); builder.append(rbModeEachRun, 7); builder.append(rbModeManual, 7); builder.appendSeparator(Strings.message("service.sync.what.to.synchronize")); builder.append(chFeedList, 7); builder.append(chPreferences, 7); builder.appendSeparator(Strings.message("service.sync.statistics")); builder.append(Strings.message("service.sync.last.sync.in"), lbLastSyncIn, 5); builder.append(Strings.message("service.sync.last.sync.out"), lbLastSyncOut, 5); builder.setLeadingColumnOffset(0); builder.appendUnrelatedComponentsGapRow(2); builder.append(buttonBar, 8); setLayout(new BorderLayout()); add(builder.getPanel(), BorderLayout.CENTER); } /** * Binds components to data in preferences object. * * @param triggerChannel value model. */ private void initComponents(ValueModel triggerChannel) { btnSyncNow = new JButton(new SyncWrapperAction(SyncFullAction.getInstance())); final JPopupMenu menu = new JPopupMenu(); menu.add(new SyncWrapperAction(SyncInAction.getInstance())); menu.add(new SyncWrapperAction(SyncOutAction.getInstance())); btnMoreSyncOptions = new CustomPopupButton(btnSyncNow, Strings.message("service.sync.more"), menu); rbModePeriodical = ComponentsFactory.createRadioButton( Strings.message("service.sync.synchronize.every")); rbModeEachRun = ComponentsFactory.createRadioButton( Strings.message("service.sync.synchronize.each.application.run")); rbModeManual = ComponentsFactory.createRadioButton( Strings.message("service.sync.manual.synchronization.only")); ButtonGroup bg = new ButtonGroup(); bg.add(rbModePeriodical); bg.add(rbModeEachRun); bg.add(rbModeManual); rbModePeriodical.addItemListener(new PeriodicalSelectionListener()); tfSyncPeriod.setEnabled(false); chFeedList = ComponentsFactory.createCheckBox( Strings.message("service.sync.feed.list"), new ToggleButtonAdapter(new BufferedValueModel(new PropertyAdapter(servicePrefs, ServicePreferences.PROP_SYNC_FEEDS), triggerChannel))); chFeedList.addActionListener(new FullSyncEnabled()); chPreferences = ComponentsFactory.createCheckBox( Strings.message("service.sync.preferences"), new ToggleButtonAdapter(new BufferedValueModel(new PropertyAdapter(servicePrefs, ServicePreferences.PROP_SYNC_PREFERENCES), triggerChannel))); new MandatoryCheckBoxController(chFeedList, chPreferences); tfEmail.setDocument(new DocumentAdapter(new BufferedValueModel( new PropertyAdapter(servicePrefs, "email"), triggerChannel))); tfPassword.setDocument(new DocumentAdapter(new BufferedValueModel( new PropertyAdapter(servicePrefs, "password"), triggerChannel))); tfSyncPeriod.setDocument(new DocumentAdapter(new BufferedValueModel( new PropertyAdapter(new ServicePreferencesWrapper(servicePrefs), "syncPeriod"), triggerChannel))); updateFullSyncButton(); updateSyncDatesView(); selectMode(); } /** * Updates text on sync dates labels. */ private void updateSyncDatesView() { Date lastSyncInDate = servicePrefs.getLastSyncInDate(); Date lastSyncOutDate = servicePrefs.getLastSyncOutDate(); String strSyncIn = lastSyncInDate == null ? Strings.message("service.sync.not.performed") : DateUtils.dateToString(lastSyncInDate) + " [" + servicePrefs.getLastSyncInStatus() + "]"; String strSyncOut = lastSyncOutDate == null ? Strings.message("service.sync.not.performed") : DateUtils.dateToString(lastSyncOutDate) + " [" + servicePrefs.getLastSyncOutStatus() + "]"; lbLastSyncIn.setText(strSyncIn); lbLastSyncOut.setText(strSyncOut); } /** * Selects mode basing on preference. */ private void selectMode() { int mode = servicePrefs.getSyncMode(); JRadioButton selected = null; switch (mode) { case ServicePreferences.SYNC_MODE_EACH_RUN: selected = rbModeEachRun; break; case ServicePreferences.SYNC_MODE_MANUAL: selected = rbModeManual; break; case ServicePreferences.SYNC_MODE_PERIODICAL: selected = rbModePeriodical; break; default: break; } if (selected != null) selected.setSelected(true); } /** * Writes selected mode back into preferences. */ public void writeMode() { int mode; if (rbModeEachRun.isSelected()) { mode = ServicePreferences.SYNC_MODE_EACH_RUN; } else if (rbModePeriodical.isSelected()) { mode = ServicePreferences.SYNC_MODE_PERIODICAL; } else { mode = ServicePreferences.SYNC_MODE_MANUAL; } servicePrefs.setSyncMode(mode); } private void updateFullSyncButton() { boolean enabled = SyncFullAction.getInstance().isEnabled() && GlobalController.SINGLETON.isInitializationFinished(); btnSyncNow.setEnabled(enabled); } /** * Invoked when registration finished successfully. * * @param email email used for registration. * @param password password. */ public void registeredSuccessfully(String email, String password) { final String textEmail = tfEmail.getText(); if (textEmail == null || textEmail.trim().length() == 0) { // email is not set - fill with new data tfEmail.setText(email); tfPassword.setText(password); } } /** * Wrapper for action, which applies dialog changes before action event. */ private class SyncWrapperAction extends AbstractAction implements PropertyChangeListener { private Action act; /** * Creates wrapper for action. * * @param action action to wrap. */ public SyncWrapperAction(Action action) { this.act = action; action.addPropertyChangeListener(this); } /** * Invoked when an action occurs. * * @param e action object. */ public void actionPerformed(ActionEvent e) { parentDialog.doApply(); act.actionPerformed(e); // When putting code here note that the above action can be (if extended from // ThreadedAction) executed asynchronously, which means that the code below will // be executed *before* actual action completion. } /** * Returns true if the action is enabled. * * @return true if the action is enabled, false otherwise * @see javax.swing.Action#isEnabled */ public boolean isEnabled() { return act.isEnabled(); } /** * Gets the <code>Object</code> associated with the specified key. * * @param key a string containing the specified <code>key</code> * @return the binding <code>Object</code> stored with this key; if there * are no keys, it will return <code>null</code> * @see javax.swing.Action#getValue */ public Object getValue(String key) { return act.getValue(key); } /** * Sets the <code>Value</code> associated with the specified key. * * @param key the <code>String</code> that identifies the stored object * @param newValue the <code>Object</code> to store using this key * @see javax.swing.Action#putValue */ public void putValue(String key, Object newValue) { act.putValue(key, newValue); } /** * This method gets called when a bound property is changed. * * @param evt A PropertyChangeEvent object describing the event source * and the property that has changed. */ public void propertyChange(PropertyChangeEvent evt) { firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()); // Small hack to update GUI on action completion if (evt.getPropertyName().equals("enabled") && evt.getNewValue() == Boolean.TRUE) { updateFullSyncButton(); updateSyncDatesView(); } } } /** * Simple wrapper for preferences object. Makes integer properties feel like Strings. */ public static class ServicePreferencesWrapper { private ServicePreferences prefs; /** * Creates new wrapper. * * @param prefobject preferences object. */ public ServicePreferencesWrapper(ServicePreferences prefobject) { this.prefs = prefobject; } /** * Returns string representation of <code>syncPeriod</code> property. * * @return string representation. */ public String getSyncPeriod() { return Integer.toString(prefs.getSyncPeriod()); } /** * Sets <code>syncPeriod</code> property from string value. * * @param period string representation of period. */ public void setSyncPeriod(String period) { prefs.setSyncPeriod(Integer.parseInt(period)); } } /** * Listens for Periodical mode selection radio-button and enables / disables * field of period entry. */ private class PeriodicalSelectionListener implements ItemListener { /** * Invoked when an item has been selected or deselected by the user. * The code written for this method performs the operations * that need to occur when an item is selected (or deselected). */ public void itemStateChanged(ItemEvent e) { tfSyncPeriod.setEnabled(rbModePeriodical.isSelected()); } } /** * Listens for changes of Feeds List check-box and enables/disables * Full synchronization action accordingly. */ private class FullSyncEnabled implements ActionListener { /** * Invoked when an action occurs. */ public void actionPerformed(ActionEvent e) { updateFullSyncButton(); } } }