/* ********************************************************************** **
** 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.exporter;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.ui.IExportWizard;
import org.eclipse.ui.IWorkbench;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.newsaction.CopyNewsAction;
import org.rssowl.core.internal.newsaction.MoveNewsAction;
import org.rssowl.core.interpreter.InterpreterException;
import org.rssowl.core.interpreter.ITypeExporter.Options;
import org.rssowl.core.persist.IFilterAction;
import org.rssowl.core.persist.IFolder;
import org.rssowl.core.persist.IFolderChild;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.INewsBin;
import org.rssowl.core.persist.ISearch;
import org.rssowl.core.persist.ISearchCondition;
import org.rssowl.core.persist.ISearchFilter;
import org.rssowl.core.persist.ISearchMark;
import org.rssowl.core.persist.dao.DynamicDAO;
import org.rssowl.core.persist.dao.IFolderDAO;
import org.rssowl.core.persist.reference.NewsBinReference;
import org.rssowl.core.util.CoreUtils;
import org.rssowl.ui.internal.Activator;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.views.explorer.BookMarkExplorer;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* A {@link Wizard} to export bookmarks, saved searches and bins with the option
* to also export settings to OPML.
* <p>
* TODO While this wizard tries to add missing locations from saved searches and
* filters, this is not recursive. Thus it can still happen that a missing
* location adds more saved searches with missing locations in return.
*</p>
*
* @author bpasero
*/
public class ExportWizard extends Wizard implements IExportWizard {
private ExportElementsPage fExportElementsPage;
private ExportOptionsPage fExportOptionsPage;
/** Leave for Reflection */
public ExportWizard() {}
/*
* @see org.eclipse.jface.wizard.Wizard#addPages()
*/
@Override
public void addPages() {
setWindowTitle(Messages.ExportWizard_EXPORT);
/* Page 1: Folder Child Selection */
fExportElementsPage = new ExportElementsPage(Messages.ExportWizard_CHOOSE_ELEMENTS);
addPage(fExportElementsPage);
/* Page 2: Export Settings Configuration */
fExportOptionsPage = new ExportOptionsPage(Messages.ExportWizard_EXPORT_OPTIONS);
addPage(fExportOptionsPage);
}
/*
* @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, org.eclipse.jface.viewers.IStructuredSelection)
*/
public void init(IWorkbench workbench, IStructuredSelection selection) {}
/*
* @see org.eclipse.jface.wizard.Wizard#canFinish()
*/
@Override
public boolean canFinish() {
return true;
}
/*
* @see org.eclipse.jface.wizard.Wizard#performFinish()
*/
@Override
public boolean performFinish() {
/* Prompt for Filename */
FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
dialog.setText(Messages.ExportWizard_EXPORT_FILE);
/* Receive Formats for Export */
List<String> filterExtensions = new ArrayList<String>();
filterExtensions.add("*.opml"); //$NON-NLS-1$
filterExtensions.add("*.xml"); //$NON-NLS-1$
Collection<String> exportFormats = Owl.getInterpreter().getExportFormats();
for (String exportFormat : exportFormats) {
String format = "*." + exportFormat.toLowerCase(); //$NON-NLS-1$
if (!filterExtensions.contains(format))
filterExtensions.add(format);
}
if (!filterExtensions.contains("*.*")) //$NON-NLS-1$
filterExtensions.add("*.*"); //$NON-NLS-1$
dialog.setFilterExtensions(filterExtensions.toArray(new String[filterExtensions.size()]));
dialog.setFileName("rssowl.opml"); //$NON-NLS-1$
dialog.setOverwrite(true);
String string = dialog.open();
/* Export to given File */
if (string != null) {
/* Enforce that Explorer Settings are up to date if necessary */
if (fExportOptionsPage.getExportOptions() != null && fExportOptionsPage.getExportOptions().contains(Options.EXPORT_PREFERENCES)) {
BookMarkExplorer explorer = OwlUI.getOpenedBookMarkExplorer();
if (explorer != null)
explorer.saveState();
}
/* Export */
File file = new File(string);
try {
Owl.getInterpreter().exportTo(file, getElementsToExport(), fExportOptionsPage.getExportOptions());
return true;
} catch (InterpreterException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
}
return false;
}
/* Ensure that Childs to Export is normalized and contains all dependent Locations from Searches and Filters */
private List<IFolderChild> getElementsToExport() {
List<IFolderChild> selectedElements = fExportElementsPage.getElementsToExport();
Set<Options> options = fExportOptionsPage.getExportOptions();
/* Check if dependent locations need to be added manually */
Collection<IFolder> rootFolders = DynamicDAO.getDAO(IFolderDAO.class).loadRoots();
if (!selectedElements.containsAll(rootFolders)) {
/* Find Folders and Saved Searches */
Set<ISearchMark> savedSearches = new HashSet<ISearchMark>();
Set<IFolder> folders = new HashSet<IFolder>();
for (IFolderChild child : selectedElements) {
if (child instanceof IFolder)
folders.add((IFolder) child);
else if (child instanceof ISearchMark)
savedSearches.add((ISearchMark) child);
}
/* Find Saved Searches from Folders */
for (IFolder folder : folders) {
findSavedSearches(savedSearches, folder);
}
/* Add those Locations required by Saved Searches */
for (ISearchMark savedSearch : savedSearches) {
collectLocations(selectedElements, savedSearch);
}
/* Add those Locations required by Filters */
if (options != null && options.contains(Options.EXPORT_FILTERS)) {
Collection<ISearchFilter> filters = DynamicDAO.loadAll(ISearchFilter.class);
for (ISearchFilter filter : filters) {
collectLocations(selectedElements, filter);
}
}
}
/* Remove those childs where its parents are present in the list already */
CoreUtils.normalize(selectedElements);
return selectedElements;
}
/* Collect Locations from Searches */
private void collectLocations(List<IFolderChild> selectedElements, ISearch search) {
if (search != null) {
List<ISearchCondition> conditions = search.getSearchConditions();
for (ISearchCondition condition : conditions) {
if (condition.getField().getId() == INews.LOCATION) {
Object value = condition.getValue();
if (value instanceof Long[][]) {
List<IFolderChild> locations = CoreUtils.toEntities((Long[][]) value);
for (IFolderChild location : locations) {
if (!selectedElements.contains(location))
selectedElements.add(location);
}
}
}
}
}
}
/* Collect Locations from Filters */
private void collectLocations(List<IFolderChild> selectedElements, ISearchFilter filter) {
/* Locations from Search */
collectLocations(selectedElements, filter.getSearch());
/* Locations from Actions */
List<IFilterAction> actions = filter.getActions();
for (IFilterAction action : actions) {
if (MoveNewsAction.ID.equals(action.getActionId()) || CopyNewsAction.ID.equals(action.getActionId())) {
Object value = action.getData();
if (value instanceof Long[]) {
Long[] binIds = (Long[]) value;
for (Long binId : binIds) {
INewsBin bin = new NewsBinReference(binId).resolve();
if (bin != null && !selectedElements.contains(bin))
selectedElements.add(bin);
}
}
}
}
}
private void findSavedSearches(Set<ISearchMark> savedSearches, IFolder folder) {
List<IFolderChild> children = folder.getChildren();
for (IFolderChild child : children) {
if (child instanceof IFolder)
findSavedSearches(savedSearches, (IFolder) child);
else if (child instanceof ISearchMark)
savedSearches.add((ISearchMark) child);
}
}
/*
* @see org.eclipse.jface.wizard.Wizard#needsProgressMonitor()
*/
@Override
public boolean needsProgressMonitor() {
return false;
}
}