/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2005-2009 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** All rights reserved ** ** ** ** This program and the accompanying materials are made available under ** ** the terms of the Eclipse Public License v1.0 which accompanies this ** ** distribution, and is available at: ** ** http://www.rssowl.org/legal/epl-v10.html ** ** ** ** A copy is found in the file epl-v10.html and important notices to the ** ** license from the team is found in the textfile LICENSE.txt distributed ** ** in this package. ** ** ** ** This copyright notice MUST APPEAR in all copies of the file! ** ** ** ** Contributors: ** ** RSSOwl Development Team - initial API and implementation ** ** ** ** ********************************************************************** */ package org.rssowl.ui.internal.dialogs.properties; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Spinner; import org.rssowl.core.Owl; import org.rssowl.core.internal.persist.pref.DefaultPreferences; import org.rssowl.core.persist.IBookMark; import org.rssowl.core.persist.IEntity; import org.rssowl.core.persist.IFolder; import org.rssowl.core.persist.IFolderChild; import org.rssowl.core.persist.IMark; import org.rssowl.core.persist.INewsMark; import org.rssowl.core.persist.pref.IPreferenceScope; import org.rssowl.core.util.CoreUtils; import org.rssowl.core.util.RetentionStrategy; import org.rssowl.core.util.SyncUtils; import org.rssowl.ui.dialogs.properties.IEntityPropertyPage; import org.rssowl.ui.dialogs.properties.IPropertyDialogSite; import org.rssowl.ui.internal.Controller; import org.rssowl.ui.internal.FolderNewsMark; import org.rssowl.ui.internal.OwlUI; import org.rssowl.ui.internal.util.LayoutUtils; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Retention Properties. * * @author bpasero */ public class RetentionPropertyPage implements IEntityPropertyPage { private IPropertyDialogSite fSite; private List<IEntity> fEntities; private Spinner fMaxCountSpinner; private Spinner fMaxAgeSpinner; private Button fDeleteNewsByCountCheck; private Button fDeleteNewsByAgeCheck; private Button fDeleteReadNewsCheck; private Button fNeverDeleteUnreadNewsCheck; private Button fNeverDeleteLabeledNewsCheck; private boolean fSettingsChanged; /* Settings */ private List<IPreferenceScope> fEntityPreferences; private boolean fPrefDeleteNewsByCountState; private int fPrefDeleteNewsByCountValue; private boolean fPrefDeleteNewsByAgeState; private int fPrefDeleteNewsByAgeValue; private boolean fPrefDeleteReadNews; private boolean fPrefNeverDeleteUnReadNews; private boolean fPrefNeverDeleteLabeledNews; /* * @see org.rssowl.ui.dialogs.properties.IEntityPropertyPage#init(org.rssowl.ui.dialogs.properties.IPropertyDialogSite, * java.util.List) */ public void init(IPropertyDialogSite site, List<IEntity> entities) { Assert.isTrue(!entities.isEmpty()); fSite = site; fEntities = entities; /* Load Entity Preferences */ fEntityPreferences = new ArrayList<IPreferenceScope>(fEntities.size()); for (IEntity entity : entities) fEntityPreferences.add(Owl.getPreferenceService().getEntityScope(entity)); /* Load initial Settings */ loadInitialSettings(); } private void loadInitialSettings() { /* Take the first scope as initial values */ IPreferenceScope firstScope = fEntityPreferences.get(0); fPrefDeleteNewsByCountState = firstScope.getBoolean(DefaultPreferences.DEL_NEWS_BY_COUNT_STATE); fPrefDeleteNewsByCountValue = firstScope.getInteger(DefaultPreferences.DEL_NEWS_BY_COUNT_VALUE); fPrefDeleteNewsByAgeState = firstScope.getBoolean(DefaultPreferences.DEL_NEWS_BY_AGE_STATE); fPrefDeleteNewsByAgeValue = firstScope.getInteger(DefaultPreferences.DEL_NEWS_BY_AGE_VALUE); fPrefDeleteReadNews = firstScope.getBoolean(DefaultPreferences.DEL_READ_NEWS_STATE); fPrefNeverDeleteUnReadNews = firstScope.getBoolean(DefaultPreferences.NEVER_DEL_UNREAD_NEWS_STATE); fPrefNeverDeleteLabeledNews = firstScope.getBoolean(DefaultPreferences.NEVER_DEL_LABELED_NEWS_STATE); /* For any other scope not sharing the initial values, use the default */ IPreferenceScope defaultScope = Owl.getPreferenceService().getDefaultScope(); for (int i = 1; i < fEntityPreferences.size(); i++) { IPreferenceScope otherScope = fEntityPreferences.get(i); if (otherScope.getBoolean(DefaultPreferences.DEL_NEWS_BY_COUNT_STATE) != fPrefDeleteNewsByCountState) fPrefDeleteNewsByCountState = defaultScope.getBoolean(DefaultPreferences.DEL_NEWS_BY_COUNT_STATE); if (otherScope.getInteger(DefaultPreferences.DEL_NEWS_BY_COUNT_VALUE) != fPrefDeleteNewsByCountValue) fPrefDeleteNewsByCountValue = defaultScope.getInteger(DefaultPreferences.DEL_NEWS_BY_COUNT_VALUE); if (otherScope.getBoolean(DefaultPreferences.DEL_NEWS_BY_AGE_STATE) != fPrefDeleteNewsByAgeState) fPrefDeleteNewsByAgeState = defaultScope.getBoolean(DefaultPreferences.DEL_NEWS_BY_AGE_STATE); if (otherScope.getInteger(DefaultPreferences.DEL_NEWS_BY_AGE_VALUE) != fPrefDeleteNewsByAgeValue) fPrefDeleteNewsByAgeValue = defaultScope.getInteger(DefaultPreferences.DEL_NEWS_BY_AGE_VALUE); if (otherScope.getBoolean(DefaultPreferences.DEL_READ_NEWS_STATE) != fPrefDeleteReadNews) fPrefDeleteReadNews = defaultScope.getBoolean(DefaultPreferences.DEL_READ_NEWS_STATE); if (otherScope.getBoolean(DefaultPreferences.NEVER_DEL_UNREAD_NEWS_STATE) != fPrefNeverDeleteUnReadNews) fPrefNeverDeleteUnReadNews = defaultScope.getBoolean(DefaultPreferences.NEVER_DEL_UNREAD_NEWS_STATE); if (otherScope.getBoolean(DefaultPreferences.NEVER_DEL_LABELED_NEWS_STATE) != fPrefNeverDeleteLabeledNews) fPrefNeverDeleteLabeledNews = defaultScope.getBoolean(DefaultPreferences.NEVER_DEL_LABELED_NEWS_STATE); } } /* * @see org.rssowl.ui.internal.dialogs.properties.IEntityPropertyPage#createContents(org.eclipse.swt.widgets.Composite) */ public Control createContents(Composite parent) { boolean isSynchronized = isSynchronized(fEntities); Composite container = new Composite(parent, SWT.NONE); container.setLayout(LayoutUtils.createGridLayout(2, 10, 10, 5, 5, false)); /* Explanation Label */ Label explanationLabel = new Label(container, SWT.WRAP); explanationLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false, 2, 1)); explanationLabel.setText(Messages.RetentionPropertyPage_CLEANUP_INFO); /* Delete by Count */ fDeleteNewsByCountCheck = new Button(container, SWT.CHECK); fDeleteNewsByCountCheck.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); fDeleteNewsByCountCheck.setSelection(fPrefDeleteNewsByCountState); fDeleteNewsByCountCheck.setText(isSynchronized ? Messages.RetentionPropertyPage_MAX_NUMBER_SYNCHRONIZED : Messages.RetentionPropertyPage_MAX_NUMBER); fDeleteNewsByCountCheck.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fMaxCountSpinner.setEnabled(fDeleteNewsByCountCheck.getSelection()); } }); fMaxCountSpinner = new Spinner(container, SWT.BORDER); fMaxCountSpinner.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); fMaxCountSpinner.setEnabled(fDeleteNewsByCountCheck.getSelection()); fMaxCountSpinner.setMinimum(0); fMaxCountSpinner.setMaximum(99999); fMaxCountSpinner.setSelection(fPrefDeleteNewsByCountValue); /* Delete by Age */ fDeleteNewsByAgeCheck = new Button(container, SWT.CHECK); fDeleteNewsByAgeCheck.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); fDeleteNewsByAgeCheck.setSelection(fPrefDeleteNewsByAgeState); fDeleteNewsByAgeCheck.setText(isSynchronized ? Messages.RetentionPropertyPage_MAX_AGE_SYNCHRONIZED : Messages.RetentionPropertyPage_MAX_AGE); fDeleteNewsByAgeCheck.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { fMaxAgeSpinner.setEnabled(fDeleteNewsByAgeCheck.getSelection()); } }); fMaxAgeSpinner = new Spinner(container, SWT.BORDER); fMaxAgeSpinner.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); fMaxAgeSpinner.setEnabled(fDeleteNewsByAgeCheck.getSelection()); fMaxAgeSpinner.setMinimum(0); fMaxAgeSpinner.setMaximum(99999); fMaxAgeSpinner.setSelection(fPrefDeleteNewsByAgeValue); /* Delete by State */ fDeleteReadNewsCheck = new Button(container, SWT.CHECK); fDeleteReadNewsCheck.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 2, 1)); fDeleteReadNewsCheck.setText(Messages.RetentionPropertyPage_DELETE_READ); fDeleteReadNewsCheck.setSelection(fPrefDeleteReadNews); /* Never Delete Unread News State */ fNeverDeleteUnreadNewsCheck = new Button(container, SWT.CHECK); fNeverDeleteUnreadNewsCheck.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 2, 1)); fNeverDeleteUnreadNewsCheck.setText(Messages.RetentionPropertyPage_DELETE_UNREAD); fNeverDeleteUnreadNewsCheck.setSelection(fPrefNeverDeleteUnReadNews); /* Never Delete Labeled News State */ fNeverDeleteLabeledNewsCheck = new Button(container, SWT.CHECK); fNeverDeleteLabeledNewsCheck.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 2, 1)); fNeverDeleteLabeledNewsCheck.setText(Messages.RetentionPropertyPage_NEVER_DELETE_LABELED); fNeverDeleteLabeledNewsCheck.setSelection(fPrefNeverDeleteLabeledNews); /* Info Container */ Composite infoContainer = new Composite(container, SWT.None); infoContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); infoContainer.setLayout(LayoutUtils.createGridLayout(2, 0, 0)); ((GridLayout) infoContainer.getLayout()).marginTop = 5; Label infoImg = new Label(infoContainer, SWT.NONE); infoImg.setImage(OwlUI.getImage(fSite.getResourceManager(), "icons/obj16/info.gif")); //$NON-NLS-1$ infoImg.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); Label infoText = new Label(infoContainer, SWT.WRAP); infoText.setText(Messages.RetentionPropertyPage_CLEANUP_NOTE); infoText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); return container; } private boolean isSynchronized(List<IEntity> entities) { for (IEntity entity : entities) { /* Folder */ if (entity instanceof IFolder) { IFolder folder = (IFolder) entity; if (!isSynchronized(folder)) return false; } /* Bookmark */ else if (entity instanceof IBookMark) { IBookMark bm = (IBookMark) entity; if (!SyncUtils.isSynchronized(bm)) return false; } /* Anything Else */ else return false; } return true; } private boolean isSynchronized(IFolder folder) { for (IFolderChild child : folder.getChildren()) { /* Folder */ if (child instanceof IFolder) { IFolder childFolder = (IFolder) child; if (!isSynchronized(childFolder)) return false; } /* Bookmark */ else if (child instanceof IBookMark) { IBookMark bm = (IBookMark) child; if (!SyncUtils.isSynchronized(bm)) return false; } /* Anything Else */ else return false; } return true; } /* * @see org.rssowl.ui.dialogs.properties.IEntityPropertyPage#getImage() */ public ImageDescriptor getImage() { return null; } /* * @see org.rssowl.ui.dialogs.properties.IEntityPropertyPage#setFocus() */ public void setFocus() {} /* * @see org.rssowl.ui.dialogs.properties.IEntityPropertyPage#performOk(java.util.Set) */ public boolean performOk(Set<IEntity> entitiesToSave) { /* Update this Entity */ for (IPreferenceScope scope : fEntityPreferences) { if (updatePreferences(scope)) { IEntity entityToSave = fEntities.get(fEntityPreferences.indexOf(scope)); entitiesToSave.add(entityToSave); fSettingsChanged = true; } } /* Update changes in all Childs as well if Folder */ for (IEntity entity : fEntities) { if (fSettingsChanged && entity instanceof IFolder) updateChildPreferences((IFolder) entity); } return true; } private void updateChildPreferences(IFolder folder) { /* Update changes to Child-BookMarks */ List<IMark> marks = folder.getMarks(); for (IMark mark : marks) { if (mark instanceof IBookMark) { IPreferenceScope scope = Owl.getPreferenceService().getEntityScope(mark); updatePreferences(scope); } } /* Update changes to Child-Folders */ List<IFolder> folders = folder.getFolders(); for (IFolder childFolder : folders) { IPreferenceScope scope = Owl.getPreferenceService().getEntityScope(childFolder); updatePreferences(scope); /* Recursively Proceed */ updateChildPreferences(childFolder); } } private boolean updatePreferences(IPreferenceScope scope) { boolean changed = false; /* Delete by Count */ boolean bVal = fDeleteNewsByCountCheck.getSelection(); if (fPrefDeleteNewsByCountState != bVal) { scope.putBoolean(DefaultPreferences.DEL_NEWS_BY_COUNT_STATE, bVal); changed = true; } int iVal = fMaxCountSpinner.getSelection(); if (fPrefDeleteNewsByCountValue != iVal) { scope.putInteger(DefaultPreferences.DEL_NEWS_BY_COUNT_VALUE, iVal); changed = true; } /* Delete by Age */ bVal = fDeleteNewsByAgeCheck.getSelection(); if (fPrefDeleteNewsByAgeState != bVal) { scope.putBoolean(DefaultPreferences.DEL_NEWS_BY_AGE_STATE, bVal); changed = true; } iVal = fMaxAgeSpinner.getSelection(); if (fPrefDeleteNewsByAgeValue != iVal) { scope.putInteger(DefaultPreferences.DEL_NEWS_BY_AGE_VALUE, iVal); changed = true; } /* Delete Read News */ bVal = fDeleteReadNewsCheck.getSelection(); if (fPrefDeleteReadNews != bVal) { scope.putBoolean(DefaultPreferences.DEL_READ_NEWS_STATE, bVal); changed = true; } /* Never Delete Unread News */ bVal = fNeverDeleteUnreadNewsCheck.getSelection(); if (fPrefNeverDeleteUnReadNews != bVal) { scope.putBoolean(DefaultPreferences.NEVER_DEL_UNREAD_NEWS_STATE, bVal); changed = true; } /* Never Delete Labeled News */ bVal = fNeverDeleteLabeledNewsCheck.getSelection(); if (fPrefNeverDeleteLabeledNews != bVal) { scope.putBoolean(DefaultPreferences.NEVER_DEL_LABELED_NEWS_STATE, bVal); changed = true; } return changed; } /* * @see org.rssowl.ui.internal.dialogs.properties.IEntityPropertyPage#finish() */ public void finish() { /* Run Retention since settings changed */ if (fSettingsChanged) { final INewsMark activeFeedViewNewsMark = OwlUI.getActiveFeedViewNewsMark(); Job retentionJob = new Job(Messages.RetentionPropertyPage_PERFORMING_CLEANUP) { @Override protected IStatus run(IProgressMonitor monitor) { try { Set<IBookMark> bookmarks = new HashSet<IBookMark>(); for (IEntity entity : fEntities) { if (entity instanceof IBookMark) bookmarks.add((IBookMark) entity); else if (entity instanceof IFolder) CoreUtils.fillBookMarks(bookmarks, Collections.singleton((IFolder) entity)); } monitor.beginTask(Messages.RetentionPropertyPage_PERFORMING_CLEANUP, bookmarks.size()); for (IBookMark bookmark : bookmarks) { if (Controller.getDefault().isShuttingDown() || monitor.isCanceled()) break; /* Check if retention should run or not */ if (activeFeedViewNewsMark != null) { if (activeFeedViewNewsMark.equals(bookmark)) continue; //Avoid clean up on feed the user is reading on else if (activeFeedViewNewsMark instanceof FolderNewsMark && ((FolderNewsMark) activeFeedViewNewsMark).contains(bookmark)) continue; //Avoid clean up on folder the user is reading on if feed contained } monitor.subTask(bookmark.getName()); RetentionStrategy.process(bookmark); monitor.worked(1); } } finally { monitor.done(); } return Status.OK_STATUS; } }; retentionJob.schedule(); } } }