package org.docear.plugin.core.ui;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.docear.plugin.core.DocearController;
import org.docear.plugin.core.ui.wizard.AWizardPage;
import org.docear.plugin.core.ui.wizard.WizardSession;
import org.docear.plugin.core.workspace.controller.DocearConversionDescriptor;
import org.docear.plugin.core.workspace.model.DocearWorkspaceProject;
import org.freeplane.core.io.ReadManager;
import org.freeplane.core.io.xml.TreeXmlReader;
import org.freeplane.core.util.LogUtils;
import org.freeplane.core.util.TextUtils;
import org.freeplane.n3.nanoxml.XMLException;
import org.freeplane.plugin.workspace.URIUtils;
import org.freeplane.plugin.workspace.WorkspaceController;
import org.freeplane.plugin.workspace.model.AWorkspaceTreeNode;
import org.freeplane.plugin.workspace.model.IResultProcessor;
import org.freeplane.plugin.workspace.model.project.AWorkspaceProject;
import org.freeplane.plugin.workspace.model.project.ProjectLoader;
import org.freeplane.plugin.workspace.nodes.ProjectRootNode;
import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
public class ImportProjectPagePanel extends AWizardPage {
private static final SimpleDateFormat format = new SimpleDateFormat("M/d/yy HH:mm");
private static final long serialVersionUID = 1L;
private JTextField txtImportHome;
private ProjectVersionsModel versionModel;
private JList lstVersions;
private WizardSession cachedContext;
private JLabel lblWarning;
private JCheckBox chckbxDeleteOldSettings;
/***********************************************************************************
* CONSTRUCTORS
**********************************************************************************/
public ImportProjectPagePanel() {
setBackground(Color.WHITE);
setLayout(new FormLayout(new ColumnSpec[] {
FormFactory.RELATED_GAP_COLSPEC,
ColumnSpec.decode("default:grow"),
FormFactory.RELATED_GAP_COLSPEC,
FormFactory.DEFAULT_COLSPEC,
FormFactory.RELATED_GAP_COLSPEC,
ColumnSpec.decode("default:grow"),},
new RowSpec[] {
FormFactory.RELATED_GAP_ROWSPEC,
RowSpec.decode("fill:default"),
FormFactory.RELATED_GAP_ROWSPEC,
FormFactory.DEFAULT_ROWSPEC,
FormFactory.RELATED_GAP_ROWSPEC,
FormFactory.DEFAULT_ROWSPEC,
FormFactory.RELATED_GAP_ROWSPEC,
FormFactory.DEFAULT_ROWSPEC,
FormFactory.RELATED_GAP_ROWSPEC,
FormFactory.DEFAULT_ROWSPEC,
FormFactory.RELATED_GAP_ROWSPEC,
FormFactory.DEFAULT_ROWSPEC,
FormFactory.RELATED_GAP_ROWSPEC,
FormFactory.DEFAULT_ROWSPEC,}));
JEditorPane dtrpnInfo = new JEditorPane();
dtrpnInfo.setBackground(Color.WHITE);
dtrpnInfo.setEnabled(true);
dtrpnInfo.setEditable(false);
dtrpnInfo.setText(TextUtils.getText("docear.setup.wizard.import.info"));
add(dtrpnInfo, "2, 2, 5, 1, fill, fill");
JLabel lblSelectTheHome = new JLabel(TextUtils.getText("docear.setup.wizard.import.home.label"));
add(lblSelectTheHome, "2, 6, 5, 1");
txtImportHome = new JTextField();
txtImportHome.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {
updateProjectVersions();
}
@Override
public void keyPressed(KeyEvent e) {}
});
add(txtImportHome, "2, 8, fill, default");
txtImportHome.setColumns(10);
JButton btnBrowse = new JButton(TextUtils.getText("docear.setup.wizard.import.home.browse"));
btnBrowse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
File home = URIUtils.getAbsoluteFile(getImportHome());
while(home != null && !home.exists()) {
home = home.getParentFile();
}
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setFileHidingEnabled(true);
if(home != null) {
chooser.setCurrentDirectory(home);
}
int response = chooser.showOpenDialog(ImportProjectPagePanel.this);
if(response == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
setImportHome(file.getAbsolutePath());
}
}
});
add(btnBrowse, "4, 8");
JScrollPane scrollPane = new JScrollPane();
add(scrollPane, "2, 10, 4, 1, fill, fill");
lstVersions = new JList();
lstVersions.setVisibleRowCount(10);
lstVersions.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lstVersions.setModel(getModel());
lstVersions.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
enableControls(cachedContext);
}
});
scrollPane.setViewportView(lstVersions);
lblWarning = new JLabel();
lblWarning.setVisible(false);
URL url = WorkspaceController.class.getResource("/images/16x16/dialog-warning-4.png");
if(url != null) {
lblWarning.setIcon(new ImageIcon(url));
}
chckbxDeleteOldSettings = new JCheckBox(TextUtils.getText("docear.setup.wizard.import.delete.old"));
chckbxDeleteOldSettings.setBackground(Color.WHITE);
chckbxDeleteOldSettings.setEnabled(false);
add(chckbxDeleteOldSettings, "2, 12, 5, 1");
add(lblWarning, "2, 14");
}
/***********************************************************************************
* METHODS
**********************************************************************************/
private void setImportHome(String path) {
txtImportHome.setText(path);
updateProjectVersions();
}
private URI getImportHome() {
if(txtImportHome.getText().length()==0) {
return WorkspaceController.getDefaultProjectHome();
}
return new File(txtImportHome.getText()).toURI();
}
private void enableControls(WizardSession context) {
chckbxDeleteOldSettings.setEnabled(false);
if(context != null) {
boolean enabled = getModel().getSize() > 0;
lblWarning.setText(TextUtils.getText("docear.setup.wizard.import.warn1"));
lblWarning.setVisible(false);
lstVersions.setEnabled(enabled);
if(lstVersions.getSelectedValue() == null) {
context.getNextButton().setEnabled(false);
if(lstVersions.isEnabled()) {
lblWarning.setText(TextUtils.getText("docear.setup.wizard.import.warn2"));
lblWarning.setVisible(true);
}
else if(!txtImportHome.getText().isEmpty()) {
lblWarning.setVisible(true);
}
}
else {
if(WorkspaceController.getCurrentModel().getProject(((VersionItem) lstVersions.getSelectedValue()).getProject().getProjectID()) != null) {
lblWarning.setText(TextUtils.getText("docear.setup.wizard.import.warn3"));
lblWarning.setVisible(true);
context.getNextButton().setEnabled(false);
}
else if(getProject().getExtensions(DocearConversionDescriptor.class) != null) {
lblWarning.setText(TextUtils.getText("docear.setup.wizard.import.warn4"));
lblWarning.setVisible(true);
chckbxDeleteOldSettings.setEnabled(true);
context.getNextButton().setEnabled(true);
}
else{
context.getNextButton().setEnabled(true);
lblWarning.setVisible(false);
}
}
}
}
private void updateProjectVersions() {
File home = new File(txtImportHome.getText());
getModel().clear();
lstVersions.getSelectionModel().clearSelection();
File _data = new File(home, "_data");
if(_data.exists()) {
readVersions(_data);
}
lookForIncompatibles();
if(getModel().getSize() > 0) {
lstVersions.setSelectedIndex(0);
}
enableControls(cachedContext);
}
private void readVersions(File home) {
for(File folder : home.listFiles(new FileFilter() {
public boolean accept(File pathname) {
if(pathname.isDirectory()) {
return true;
}
return false;
}
})) {
File settings = new File(folder, "settings.xml");
if(settings.exists()) {
AWorkspaceProject project = AWorkspaceProject.create(folder.getName(), home.getParentFile().toURI());
String item = new TempProjectLoader().getMetaInfo(project);
if(item == null) {
continue;
}
//see issue #113
if(WorkspaceController.getCurrentModel().getProject(project.getProjectID()) == null) {
getModel().addItem(new VersionItem(project, item, new Date(settings.lastModified())));
}
}
}
}
private ProjectVersionsModel getModel() {
if(this.versionModel == null) {
this.versionModel = new ProjectVersionsModel();
}
return this.versionModel;
}
private void lookForIncompatibles() {
File dir = URIUtils.getFile(getImportHome());
if(dir != null) {
dir = DocearConversionDescriptor.getOldProfilesHome(dir);
if(dir.exists()) {
for (File profileHome : dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.isDirectory()) {
return true;
}
return false;
}
})) {
if(new File(profileHome, "workspace.xml").exists()) {
String profileName = profileHome.getName();
DocearWorkspaceProject project = new DocearWorkspaceProject(getImportHome());
project.addExtension(new DocearConversionDescriptor(project, profileName));
getModel().addItem(new ConversionItem(project, profileName, new Date(profileHome.lastModified())));
}
}
//enableControlls(cachedContext);
}
}
}
public boolean isConversionNecessary() {
return getProject().getExtensions(DocearConversionDescriptor.class) != null;
}
public boolean deleteOldSettings() {
return chckbxDeleteOldSettings.isEnabled() && chckbxDeleteOldSettings.isSelected();
}
public AWorkspaceProject getProject() {
VersionItem item = (VersionItem) lstVersions.getSelectedValue();
if(item == null) {
return null;
}
DocearConversionDescriptor desc = item.getProject().getExtensions(DocearConversionDescriptor.class);
if(desc != null) {
desc.setDeleteOldSettings(deleteOldSettings());
}
return item.getProject();
}
/***********************************************************************************
* REQUIRED METHODS FOR INTERFACES
**********************************************************************************/
@Override
public String getTitle() {
//TODO Service
if(DocearController.getController().isServiceAvailable()){
return TextUtils.getText("docear.setup.wizard.import.title");
}
else{
return TextUtils.getText("docear.setup.wizard.import.title.noservice");
}
}
@Override
public void preparePage(WizardSession context) {
this.cachedContext = context;
context.setWizardTitle(getTitle());
context.getNextButton().setText(TextUtils.getText("docear.setup.wizard.controls.finish"));
enableControls(context);
}
/***********************************************************************************
* NESTED TYPES
**********************************************************************************/
class ProjectVersionsModel implements ListModel {
private List<VersionItem> items = new ArrayList<VersionItem>();
private List<ListDataListener> listeners = new ArrayList<ListDataListener>();
public int getSize() {
return items.size();
}
public Object getElementAt(int index) {
return items.get(index);
}
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
public void clear() {
int endIdx = items.size();
this.items.clear();
fireItemsRemoved(0, endIdx);
}
public void addItem(VersionItem item) {
for(VersionItem it : items) {
if(it.compareTo(item) < 0) {
insertItem(item, items.indexOf(it));
return;
}
}
insertItem(item, items.size());
}
private void insertItem(VersionItem item, int index) {
if(item == null) {
return;
}
if(index < 0 || index > items.size()) {
throw new IndexOutOfBoundsException();
}
items.add(index, item);
fireItemsAdded(index, index);
}
public void removeItem(VersionItem anItem) {
if(anItem == null) {
return;
}
int idx = items.indexOf(anItem);
if(idx == -1) {
return;
}
removeItem(idx);
}
public VersionItem removeItem(int index) {
if(index < 0 || index >= items.size()) {
throw new IndexOutOfBoundsException();
}
VersionItem obj = items.remove(index);
fireItemsRemoved(index, index);
return obj;
}
protected void fireItemsAdded(int startIndex, int endIndex) {
ListDataEvent event = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, startIndex, endIndex);
for (int i = listeners.size()-1; i >= 0; i--) {
listeners.get(i).intervalAdded(event);
}
}
protected void fireItemsRemoved(int startIndex, int endIndex) {
ListDataEvent event = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, startIndex, endIndex);
for (int i = listeners.size()-1; i >= 0; i--) {
listeners.get(i).intervalRemoved(event);
}
}
protected void fireItemsChanged(int startIndex, int endIndex) {
ListDataEvent event = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, startIndex, endIndex);
for (int i = listeners.size()-1; i >= 0; i--) {
listeners.get(i).contentsChanged(event);
}
}
}
class TempProjectLoader extends ProjectLoader {
StringBuilder versionString;
private final ReadManager readManager;
public TempProjectLoader() {
this.readManager = new ReadManager();
readManager.addElementHandler("workspace", getProjectRootCreator());
readManager.addElementHandler("project", getProjectRootCreator());
}
protected void load(final URI xmlFile) throws MalformedURLException, XMLException, IOException {
final TreeXmlReader reader = new TreeXmlReader(readManager);
reader.load(new InputStreamReader(new BufferedInputStream(xmlFile.toURL().openStream())));
}
public String getMetaInfo(AWorkspaceProject project) {
try {
versionString = new StringBuilder();
LOAD_RETURN_TYPE retType = this.loadProject(project);
if(LOAD_RETURN_TYPE.EXISTING_PROJECT.equals(retType)) {
return versionString.length() == 0 ? null : versionString.toString();
}
} catch (IOException e) {
LogUtils.warn(e);
}
return null;
}
@Override
public IResultProcessor getDefaultResultProcessor() {
return new IResultProcessor() {
public void process(AWorkspaceTreeNode parent, AWorkspaceTreeNode node) {
if(node == null) {
return;
}
if(node instanceof ProjectRootNode) {
versionString.append(node.getName());
}
if(parent == null) {
return;
}
parent.addChildNode(node);
}
public void setProject(AWorkspaceProject project) {
}
};
}
}
class VersionItem implements Comparable<VersionItem> {
private final AWorkspaceProject project;
private final Date latestUse;
private final String name;
/***********************************************************************************
* CONSTRUCTORS
**********************************************************************************/
public VersionItem(AWorkspaceProject prj, String name, Date version) {
if(prj == null || name == null || version == null) {
throw new IllegalArgumentException("NULLPointer");
}
this.project = prj;
this.latestUse = version;
this.name = name;
}
/***********************************************************************************
* METHODS
**********************************************************************************/
public AWorkspaceProject getProject() {
return project;
}
public String toString() {
return this.name + " [" +format.format(latestUse) + "]";
}
/***********************************************************************************
* REQUIRED METHODS FOR INTERFACES
**********************************************************************************/
public int compareTo(VersionItem o) {
return (int) (latestUse.getTime()-o.latestUse.getTime());
}
}
class ConversionItem extends VersionItem {
private ConversionItem(DocearWorkspaceProject prj, String name, Date version) {
super(prj, name, version);
}
public String toString() {
return /*"[profile] " +/**/ super.toString();
}
}
}