/* ********************************************************************** **
** Copyright notice **
** **
** (c) 2005-2006 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;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IExportWizard;
import org.eclipse.ui.IWorkbench;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IFolder;
import org.rssowl.core.persist.IMark;
import org.rssowl.core.persist.ISearchCondition;
import org.rssowl.core.persist.ISearchMark;
import org.rssowl.core.persist.dao.DynamicDAO;
import org.rssowl.core.persist.dao.IPreferenceDAO;
import org.rssowl.core.persist.reference.FolderReference;
import org.rssowl.core.persist.service.PersistenceException;
import org.rssowl.core.util.StringUtils;
import org.rssowl.ui.internal.Activator;
import org.rssowl.ui.internal.Controller;
import org.rssowl.ui.internal.OwlUI;
import org.rssowl.ui.internal.views.explorer.BookMarkExplorer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.DateFormat;
import java.util.Date;
import java.util.EnumSet;
import java.util.List;
/**
* A <code>Wizard</code> that allows to export all feeds into an OPML file.
*
* @author bpasero
*/
public class ExportOPMLWizard extends Wizard implements IExportWizard {
private ExportOPMLWizardPage fPage;
private DateFormat fDateFormat = DateFormat.getDateInstance();
/* Page for Wizard */
private static class ExportOPMLWizardPage extends WizardPage {
private Text fInput;
ExportOPMLWizardPage(String pageName) {
super(pageName, pageName, OwlUI.getImageDescriptor("icons/obj16/bkmrk_wiz.gif"));
setMessage("Please select the file to which all newsfeeds should be exported to.");
}
/*
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
public void createControl(Composite parent) {
Composite control = new Composite(parent, SWT.NONE);
control.setLayout(new GridLayout(3, false));
Label label = new Label(control, SWT.None);
label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
label.setText("File: ");
fInput = new Text(control, SWT.BORDER);
fInput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
fInput.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
setErrorMessage(null);
}
});
Button search = new Button(control, SWT.PUSH);
search.setText("Search...");
search.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
search.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
dialog.setFilterExtensions(new String[] { "*.opml", "*.xml", "*.*" });
dialog.setFileName("feeds.opml");
String file = dialog.open();
if (file != null)
fInput.setText(file);
}
});
setControl(control);
}
String getFile() {
return fInput.getText();
}
void focusInput() {
fInput.setFocus();
fInput.selectAll();
}
}
/*
* @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#addPages()
*/
@Override
public void addPages() {
fPage = new ExportOPMLWizardPage("Export Newsfeeds");
setWindowTitle("Newsfeeds");
setHelpAvailable(false);
addPage(fPage);
}
/*
* @see org.eclipse.jface.wizard.Wizard#performFinish()
*/
@Override
public boolean performFinish() {
String file = fPage.getFile();
if (!StringUtils.isSet(file)) {
fPage.setErrorMessage("Please enter the path to the file.");
return false;
}
try {
IFolder selectedRootFolder = getRootFolder();
exportToOPML(new File(file), selectedRootFolder);
} catch (IOException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
return true;
}
private IFolder getRootFolder() throws PersistenceException {
/* Otherwise return visible root-folder */
String selectedBookMarkSetPref = BookMarkExplorer.getSelectedBookMarkSetPref(OwlUI.getWindow());
Long selectedRootFolderID = DynamicDAO.getDAO(IPreferenceDAO.class).load(selectedBookMarkSetPref).getLong();
if (selectedRootFolderID != null)
return new FolderReference(selectedRootFolderID).resolve();
/* Finally return the first root folder */
return Controller.getDefault().getCacheService().getRootFolders().iterator().next();
}
private void exportToOPML(File file, IFolder root) throws IOException, PersistenceException {
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
writer.write("<opml version=\"1.1\" xmlns:rssowl=\"http://www.rssowl.org\">\n");
writer.write("<body>\n");
exportToOPML(root, writer);
writer.write("</body>\n");
writer.write("</opml>\n");
writer.close();
}
private void exportToOPML(IFolder folder, OutputStreamWriter writer) throws IOException, PersistenceException {
List<IMark> marks = folder.getMarks();
for (IMark mark : marks) {
String name = escape(mark.getName());
/* Export BookMark */
if (mark instanceof IBookMark) {
String link = escape(((IBookMark) mark).getFeedLinkReference().getLink().toString());
writer.write("<outline text=\"" + name + "\" xmlUrl=\"" + link + "\" />\n");
}
/* Export SearchMark */
else if (mark instanceof ISearchMark) {
ISearchMark searchMark = (ISearchMark) mark;
List<ISearchCondition> conditions = searchMark.getSearchConditions();
writer.write("<rssowl:savedsearch name=\"" + name + "\" matchAllConditions=\"" + searchMark.matchAllConditions() + "\">\n");
for (ISearchCondition condition : conditions) {
writer.write("\t<rssowl:searchcondition>\n");
writer.write(toXML(condition));
writer.write("\t</rssowl:searchcondition>\n");
}
writer.write("</rssowl:savedsearch>\n\n");
}
}
List<IFolder> childFolders = folder.getFolders();
for (IFolder childFolder : childFolders) {
String name = escape(childFolder.getName());
writer.write("<outline text=\"" + name + "\">\n");
exportToOPML(childFolder, writer);
writer.write("</outline>\n");
}
}
private String escape(String str) {
str = StringUtils.replaceAll(str, "&", "&");
str = StringUtils.replaceAll(str, "<", "<");
str = StringUtils.replaceAll(str, ">", ">");
return str;
}
private String toXML(ISearchCondition condition) {
StringBuilder str = new StringBuilder();
/* Search Specifier */
str.append("\t\t<rssowl:searchspecifier id=\"" + condition.getSpecifier().ordinal() + "\" />\n");
/* Single Value */
if (!EnumSet.class.isAssignableFrom(condition.getValue().getClass()))
str.append("\t\t<rssowl:searchvalue value=\"" + getValueString(condition) + "\" type=\"" + condition.getField().getSearchValueType().getId() + "\" />\n");
/* Multiple Values */
else {
EnumSet<?> values = ((EnumSet<?>) condition.getValue());
str.append("\t\t<rssowl:searchvalue type=\"" + condition.getField().getSearchValueType().getId() + "\">\n");
for (Enum<?> enumValue : values)
str.append("\t\t\t<rssowl:newsstate value=\"" + enumValue.ordinal() + "\" />\n");
str.append("\t\t</rssowl:searchvalue>\n");
}
/* Search Field */
str.append("\t\t<rssowl:searchfield id=\"" + condition.getField().getId() + "\" entity=\"" + condition.getField().getEntityName() + "\" />\n");
return str.toString();
}
private String getValueString(ISearchCondition condition) {
if (condition.getValue() instanceof Date)
return fDateFormat.format((Date) condition.getValue());
return escape(condition.getValue().toString());
}
}