changeset 31:6e713f85467d

Update Commands page when xml changes Make PluginModel the main model behind the plugin and update it whenever the source xml changes. Also update XML document whenever the model changes any other way.
author Omair Majid <omajid@redhat.com>
date Wed, 04 Dec 2013 20:52:33 -0500
parents aea870cda1db
children 65bb9dd2f605
files src/com/redhat/thermostat/plugin/eclipse/editor/CommandsMasterDetailsBlock.java src/com/redhat/thermostat/plugin/eclipse/editor/MultiPageEditor.java src/com/redhat/thermostat/plugin/eclipse/model/PluginModel.java
diffstat 3 files changed, 146 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/CommandsMasterDetailsBlock.java	Wed Dec 04 16:01:46 2013 -0500
+++ b/src/com/redhat/thermostat/plugin/eclipse/editor/CommandsMasterDetailsBlock.java	Wed Dec 04 20:52:33 2013 -0500
@@ -2,6 +2,7 @@
 
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.swt.SWT;
@@ -17,8 +18,17 @@
 import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.Section;
 
+import com.redhat.thermostat.plugin.eclipse.model.PluginModel;
+import com.redhat.thermostat.plugin.eclipse.model.PluginModel.PluginModelChangeListener;
+
 public class CommandsMasterDetailsBlock extends MasterDetailsBlock {
 
+    private PluginModel model;
+
+    public void setModel(PluginModel model) {
+        this.model = model;
+    }
+
     @Override
     protected void registerPages(DetailsPart detailsPart) {
         detailsPart.registerPage(String.class, new CommandEditPage());
@@ -45,16 +55,23 @@
 
         Table list = toolkit.createTable(sectionContents, SWT.BORDER | SWT.V_SCROLL);
         list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-        TableViewer viewer = new TableViewer(list);
+        final TableViewer viewer = new TableViewer(list);
         viewer.addSelectionChangedListener(new ISelectionChangedListener() {
             @Override
             public void selectionChanged(SelectionChangedEvent event) {
                 managedForm.fireSelectionChanged(sectionPart, event.getSelection());
             }
         });
-        ArrayContentProvider contentProvider = ArrayContentProvider.getInstance();
+        IStructuredContentProvider contentProvider = ArrayContentProvider.getInstance();
         viewer.setContentProvider(contentProvider);
-        viewer.setInput(new String[] { "Hello", "Hi", "Bye!"} );
+        viewer.setInput(model.getNewCommands().toArray());
+        model.addModelChangeListener(new PluginModelChangeListener() {
+            @Override
+            public void modelChanged() {
+                viewer.setInput(model.getNewCommands().toArray());
+                viewer.refresh();
+            }
+        });
 
         Composite buttons = toolkit.createComposite(sectionContents);
         GridData buttonCompositeLayoutData = new GridData(SWT.FILL, SWT.FILL, false, true);
--- a/src/com/redhat/thermostat/plugin/eclipse/editor/MultiPageEditor.java	Wed Dec 04 16:01:46 2013 -0500
+++ b/src/com/redhat/thermostat/plugin/eclipse/editor/MultiPageEditor.java	Wed Dec 04 20:52:33 2013 -0500
@@ -9,6 +9,9 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
@@ -26,10 +29,8 @@
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.editors.text.TextEditor;
 import org.eclipse.ui.forms.IManagedForm;
 import org.eclipse.ui.forms.ManagedForm;
-import org.eclipse.ui.forms.MasterDetailsBlock;
 import org.eclipse.ui.forms.events.HyperlinkAdapter;
 import org.eclipse.ui.forms.events.HyperlinkEvent;
 import org.eclipse.ui.forms.widgets.Form;
@@ -51,11 +52,13 @@
     private static final int INDEX_EXTENSIONS = 2;
     private static final int INDEX_SOURCE = 3;
 
-    private TextEditor editor;
+    private StructuredTextEditor editor;
+    private boolean editorIsDirty = false;
 
     private FormToolkit toolkit;
 
     private PluginModel model;
+    private int oldPage = -1;
 
     public MultiPageEditor() {
         super();
@@ -172,7 +175,8 @@
         form.setText("Commands");
         form.getBody().setLayout(new TableWrapLayout());
 
-        MasterDetailsBlock masterAndDetails = new CommandsMasterDetailsBlock();
+        CommandsMasterDetailsBlock masterAndDetails = new CommandsMasterDetailsBlock();
+        masterAndDetails.setModel(model);
         masterAndDetails.createContent(managedForm);
 
         addPage(INDEX_COMMANDS, form);
@@ -184,6 +188,20 @@
             editor = new StructuredTextEditor();
             addPage(INDEX_SOURCE, editor, getEditorInput());
             setPageText(INDEX_SOURCE, editor.getTitle());
+
+            getDocument().addDocumentListener(new IDocumentListener() {
+
+                @Override
+                public void documentChanged(DocumentEvent event) {
+                    editorIsDirty = true;
+                }
+
+                @Override
+                public void documentAboutToBeChanged(DocumentEvent event) {
+                    // nothing to do
+                }
+
+            });
         } catch (PartInitException e) {
             ErrorDialog.openError(getSite().getShell(),
                     "Error creating nested text editor", null, e.getStatus());
@@ -256,10 +274,27 @@
     }
 
     @Override
+    protected void pageChange(int newPageIndex) {
+        if (oldPage != -1) {
+            if (oldPage == INDEX_SOURCE && editorIsDirty) {
+                updateModelFromSource();
+            } else if (newPageIndex == INDEX_SOURCE) {
+                updateSourceFromModel();
+            }
+        }
+
+        super.pageChange(newPageIndex);
+
+        oldPage = newPageIndex;
+    }
+
+    @Override
     public void doSave(IProgressMonitor monitor) {
-        // FIXME sync model and editor all the time and fix saving
-        // getEditor(pageNameAndIndex.get("source")).doSave(monitor);
-        model.doSave(monitor);
+        if (getActivePage() != INDEX_SOURCE) {
+            updateSourceFromModel();
+        }
+
+        editor.doSave(monitor);
     }
 
     @Override
@@ -272,6 +307,25 @@
         throw new AssertionError("SaveAs is not allowed");
     }
 
+    private void updateSourceFromModel() {
+        String modelSource = model.getSourceXml();
+
+        if (!getDocument().get().equals(modelSource)) {
+            getDocument().set(modelSource);
+        }
+
+        editorIsDirty = false;
+    }
+
+    private void updateModelFromSource() {
+        model.readXml(getDocument().get());
+
+        editorIsDirty = false;
+    }
+
+    private IDocument getDocument() {
+        return editor.getDocumentProvider().getDocument(editor.getEditorInput());
+    }
 
     /**
      * Closes all project files on project close.
--- a/src/com/redhat/thermostat/plugin/eclipse/model/PluginModel.java	Wed Dec 04 16:01:46 2013 -0500
+++ b/src/com/redhat/thermostat/plugin/eclipse/model/PluginModel.java	Wed Dec 04 20:52:33 2013 -0500
@@ -4,6 +4,9 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -13,19 +16,31 @@
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
 import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
+/**
+ * Maintains a model of the plugin file.
+ */
 public class PluginModel {
 
     private String name;
     private IFile file;
     private Document doc;
+    private XPathFactory xPathfactory;
+
+    private final List<PluginModelChangeListener> listeners = new CopyOnWriteArrayList<>();
 
     public PluginModel(IFile file) throws CoreException {
         this(file, file.getFullPath().makeAbsolute().removeLastSegments(1).lastSegment(), file.getContents());
@@ -35,6 +50,17 @@
         this.file = file;
         this.name = name;
 
+        this.xPathfactory = XPathFactory.newInstance();
+
+        readXml(contents);
+    }
+
+    public void readXml(String contents) {
+        ByteArrayInputStream in = new ByteArrayInputStream(contents.getBytes());
+        readXml(in);
+    }
+
+    public void readXml(InputStream contents) {
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         DocumentBuilder dBuilder;
 
@@ -50,14 +76,15 @@
         } catch (IOException e) {
             throw new AssertionError("Error reading from an input stream based on a string", e);
         }
+
+        fireModelChanged();
     }
 
     public String getPluginName() {
         return name;
     }
 
-    public void doSave(IProgressMonitor monitor) {
-
+    public String getSourceXml() {
         try {
             TransformerFactory transformerFactory = TransformerFactory.newInstance();
             Transformer transformer = transformerFactory.newTransformer();
@@ -68,20 +95,50 @@
 
             transformer.transform(source, result);
 
-            ByteArrayInputStream toSave = new ByteArrayInputStream(outputStream.toByteArray());
-            file.setContents(toSave, IFile.KEEP_HISTORY, monitor);
-        } catch (CoreException | TransformerException e) {
+            return new String(outputStream.toByteArray());
+
+        } catch (TransformerException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
+        return null;
     }
 
     public void doSaveAs() {
         // TODO Auto-generated method stub
     }
 
-    public Document getDocument() {
-        return doc;
+    public List<String> getNewCommands() {
+        List<String> result = new ArrayList<>();
+        XPath xpath = xPathfactory.newXPath();
+        try {
+            XPathExpression expr = xpath.compile("/plugin/commands/command/name/text()");
+            NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+            for (int i = 0; i < nl.getLength(); i++) {
+                Node n = nl.item(i);
+                result.add(n.getNodeValue());
+            }
+        } catch (XPathExpressionException e) {
+            e.printStackTrace();
+        }
+        return result;
     }
 
+    public void addModelChangeListener(PluginModelChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removeModelChangeListener(PluginModelChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void fireModelChanged() {
+        for (PluginModelChangeListener listener: listeners) {
+            listener.modelChanged();
+        }
+    }
+
+    public static interface PluginModelChangeListener {
+        void modelChanged();
+    }
 }