You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/10/16 09:32:48 UTC

[1/2] git commit: ISIS-401: highlight row in table if changed by other

Updated Branches:
  refs/heads/master e521a1222 -> f328529bd


ISIS-401: highlight row in table if changed by other

How it works:
- When the concurrency exception is found, it is stored in the EntityModel of the row.
- IsisAjaxFallbackDataTable now uses a custom IItemReuseStrategy that allows this this model
to be reused for the repainting of the table with new UI Items.
  - requires EntityModel to implement equals/hashCode
- when repainting is done, the exception is cleared and in its stead the
  row has a class set, "reloaded-after-concurrency-exception".  This is
  styled to highlight the row.
- a new Javascript library "livequery" (MIT licensed), sets up a callback
  that looks for this new class.  It sets up a callback to detect any row
  element with this class and to remove it after a short period.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/0476cc57
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/0476cc57
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/0476cc57

Branch: refs/heads/master
Commit: 0476cc57709d5f4bbcda3fafb6491b70fb4f53b1
Parents: e521a12
Author: Dan Haywood <da...@apache.org>
Authored: Wed Oct 16 07:48:00 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Wed Oct 16 07:48:00 2013 +0100

----------------------------------------------------------------------
 .../viewer/wicket/model/models/EntityModel.java |  36 +++
 .../CollectionContentsAsAjaxTablePanel.css      |   9 +
 .../CollectionContentsAsAjaxTablePanel.java     |   3 +
 .../ajaxtable/IsisAjaxFallbackDataTable.java    |  72 ++++++
 .../IsisAjaxFallbackHeadersToolbar.java         |   2 +-
 .../ajaxtable/IsisAjaxHeadersToolbar.html       |  26 +++
 .../ajaxtable/IsisAjaxHeadersToolbar.java       | 179 +++++++++++++++
 .../ajaxtable/MyHeadersToolbar.html             |  26 ---
 .../ajaxtable/MyHeadersToolbar.java             | 179 ---------------
 .../columns/ObjectAdapterToggleboxColumn.java   |  12 +
 .../viewer/wicket/ui/pages/PageAbstract.css     |   4 +-
 .../viewer/wicket/ui/pages/PageAbstract.java    |   6 +-
 .../ui/pages/jquery.isis.wicket.viewer.js       |  10 +
 .../viewer/wicket/ui/pages/jquery.livequery.js  | 226 +++++++++++++++++++
 14 files changed, 582 insertions(+), 208 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
index e1791da..e2925ee 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
@@ -518,6 +518,40 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
 
 
     // //////////////////////////////////////////////////////////
+    // equals, hashCode
+    // //////////////////////////////////////////////////////////
+    
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((adapterMemento == null) ? 0 : adapterMemento.hashCode());
+        return result;
+    }
+
+    /**
+     * In order that <tt>IsisAjaxFallbackDataTable</tt> can use a
+     * <tt>ReuseIfModelsEqualStrategy</tt> to preserve any concurrency exception
+     * information in original model. 
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        EntityModel other = (EntityModel) obj;
+        if (adapterMemento == null) {
+            if (other.adapterMemento != null)
+                return false;
+        } else if (!adapterMemento.equals(other.adapterMemento))
+            return false;
+        return true;
+    }
+    
+    // //////////////////////////////////////////////////////////
     // Dependencies (from context)
     // //////////////////////////////////////////////////////////
 
@@ -525,6 +559,8 @@ public class EntityModel extends BookmarkableModel<ObjectAdapter> {
 		return IsisContext.getOidMarshaller();
 	}
 
+
+
     protected SpecificationLoaderSpi getSpecificationLoader() {
         return IsisContext.getSpecificationLoader();
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.css
index 662f50d..10cff28 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.css
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.css
@@ -35,6 +35,15 @@
 	background-color:#D2F0F3;
 }
 
+.collectionContentsAsAjaxTablePanel table.contents tr.reloaded-after-concurrency-exception {
+    background-color: yellow;
+}
+
+.collectionContentsAsAjaxTablePanel table.contents tr.reloaded-after-concurrency-exception:hover td {
+    background-color: orange;
+}
+
+
 .collectionContentsAsAjaxTablePanel table.contents tr td { 
 	padding-left: 8px; 
 	padding-right: 10px; 

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
index 134344b..00ba745 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -27,6 +27,7 @@ import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 
+import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.Session;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -65,6 +66,7 @@ import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuBuilde
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuLinkFactory;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuPanel;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
 /**
  * {@link PanelAbstract Panel} that represents a {@link EntityCollectionModel
@@ -133,6 +135,7 @@ public class CollectionContentsAsAjaxTablePanel extends PanelAbstract<EntityColl
                 // but it isn't possible (yet) to raise any warning
                 // because that only gets flushed on page refresh.
                 //
+                
                 // perhaps something to tackle in a separate ticket....
                 ajaxRequestTarget.add(dataTable);
             }

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java
index e1b9c14..ceab997 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackDataTable.java
@@ -18,16 +18,22 @@
  */
 package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
 
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxNavigationToolbar;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
 import org.apache.wicket.extensions.markup.html.repeater.data.table.NoRecordsToolbar;
+import org.apache.wicket.markup.repeater.IItemFactory;
+import org.apache.wicket.markup.repeater.IItemReuseStrategy;
 import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.markup.repeater.OddEvenItem;
+import org.apache.wicket.markup.repeater.ReuseIfModelsEqualStrategy;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.util.lang.Generics;
 
 public class IsisAjaxFallbackDataTable<T, S> extends DataTable<T, S>
 {
@@ -42,6 +48,8 @@ public class IsisAjaxFallbackDataTable<T, S> extends DataTable<T, S>
         addTopToolbar(new IsisAjaxFallbackHeadersToolbar<S>(this, dataProvider));
         addBottomToolbar(new AjaxNavigationToolbar(this));
         addBottomToolbar(new NoRecordsToolbar(this));
+        //setItemReuseStrategy(new ReuseIfModelsEqualStrategy());
+        setItemReuseStrategy(new PreserveModelReuseStrategy());
     }
 
     @Override
@@ -50,4 +58,68 @@ public class IsisAjaxFallbackDataTable<T, S> extends DataTable<T, S>
         return new OddEvenItem<T>(id, index, model);
     }
 
+    static class PreserveModelReuseStrategy implements IItemReuseStrategy {
+        private static final long serialVersionUID = 1L;
+
+        private static IItemReuseStrategy instance = new PreserveModelReuseStrategy();
+
+        /**
+         * @return static instance
+         */
+        public static IItemReuseStrategy getInstance()
+        {
+            return instance;
+        }
+
+        /**
+         * @see org.apache.wicket.markup.repeater.IItemReuseStrategy#getItems(org.apache.wicket.markup.repeater.IItemFactory,
+         *      java.util.Iterator, java.util.Iterator)
+         */
+        @Override
+        public <T> Iterator<Item<T>> getItems(final IItemFactory<T> factory,
+            final Iterator<IModel<T>> newModels, Iterator<Item<T>> existingItems)
+        {
+            final Map<IModel<T>, Item<T>> modelToItem = Generics.newHashMap();
+            while (existingItems.hasNext())
+            {
+                final Item<T> item = existingItems.next();
+                modelToItem.put(item.getModel(), item);
+            }
+
+            return new Iterator<Item<T>>()
+            {
+                private int index = 0;
+
+                @Override
+                public boolean hasNext()
+                {
+                    return newModels.hasNext();
+                }
+
+                @Override
+                public Item<T> next()
+                {
+                    final IModel<T> model = newModels.next();
+                    final Item<T> oldItem = modelToItem.get(model);
+
+                    final IModel<T> model2;
+                    if (oldItem == null) {
+                        model2 = model;
+                    } else {
+                        model2 = oldItem.getModel();
+                    }
+                    return factory.newItem(index++, 
+                            model2);
+                }
+
+                @Override
+                public void remove()
+                {
+                    throw new UnsupportedOperationException();
+                }
+
+            };
+        }
+
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
index e59e388..daabcd5 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxFallbackHeadersToolbar.java
@@ -28,7 +28,7 @@ import org.apache.wicket.markup.html.WebMarkupContainer;
 /**
  * Adapted from Wicket's own {@link AjaxFallbackHeadersToolbar}.
  */
-public class IsisAjaxFallbackHeadersToolbar<S> extends MyHeadersToolbar<S>
+public class IsisAjaxFallbackHeadersToolbar<S> extends IsisAjaxHeadersToolbar<S>
 {
     private static final long serialVersionUID = 1L;
 

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html
new file mode 100644
index 0000000..79ae3b8
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.html
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org">
+    <tr class="headers">
+        <wicket:container wicket:id="headers">
+            <th wicket:id="header">
+                <span wicket:id="label">[header-label]</span>
+            </th>
+        </wicket:container>
+    </tr>
+</wicket:panel>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java
new file mode 100644
index 0000000..05c9aa6
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/IsisAjaxHeadersToolbar.java
@@ -0,0 +1,179 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractToolbar;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.HeadersToolbar;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IStyledColumn;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.RefreshingView;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.util.string.Strings;
+
+
+/**
+ * Adapted from Wicket's own {@link HeadersToolbar}.
+ */
+public class IsisAjaxHeadersToolbar<S> extends AbstractToolbar
+{
+    private static final long serialVersionUID = 1L;
+
+    static abstract class CssAttributeBehavior extends Behavior
+    {
+        private static final long serialVersionUID = 1L;
+
+        protected abstract String getCssClass();
+
+        /**
+         * @see Behavior#onComponentTag(Component, ComponentTag)
+         */
+        @Override
+        public void onComponentTag(final Component component, final ComponentTag tag)
+        {
+            String className = getCssClass();
+            if (!Strings.isEmpty(className))
+            {
+                tag.append("class", className, " ");
+            }
+        }
+    }
+
+    /**
+     * Constructor
+     * 
+     * @param <T>
+     *            the column data type
+     * @param table
+     *            data table this toolbar will be attached to
+     * @param stateLocator
+     *            locator for the ISortState implementation used by sortable headers
+     */
+    public <T> IsisAjaxHeadersToolbar(final DataTable<T, S> table, final ISortStateLocator<S> stateLocator)
+    {
+        super(table);
+
+        RefreshingView<IColumn<T, S>> headers = new RefreshingView<IColumn<T, S>>("headers")
+        {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected Iterator<IModel<IColumn<T, S>>> getItemModels()
+            {
+                List<IModel<IColumn<T, S>>> columnsModels = new LinkedList<IModel<IColumn<T, S>>>();
+
+                for (IColumn<T, S> column : table.getColumns())
+                {
+                    columnsModels.add(Model.of(column));
+                }
+
+                return columnsModels.iterator();
+            }
+
+            @Override
+            protected void populateItem(Item<IColumn<T, S>> item)
+            {
+                final IColumn<T, S> column = item.getModelObject();
+
+                WebMarkupContainer header = null;
+
+                if (column.isSortable())
+                {
+                    header = newSortableHeader("header", column.getSortProperty(), stateLocator);
+                }
+                else
+                {
+                    header = new WebMarkupContainer("header");
+                }
+
+                if (column instanceof IStyledColumn)
+                {
+                    CssAttributeBehavior cssAttributeBehavior = new CssAttributeBehavior()
+                    {
+                        private static final long serialVersionUID = 1L;
+
+                        @Override
+                        protected String getCssClass()
+                        {
+                            return ((IStyledColumn<?, S>)column).getCssClass();
+                        }
+                    };
+
+                    header.add(cssAttributeBehavior);
+                }
+
+                item.add(header);
+                item.setRenderBodyOnly(true);
+                
+                Component label;
+                //Component checkBox;
+                //if(column instanceof ObjectAdapterToggleboxColumn) {
+                    label = new Label("label");
+                //    checkBox = column.getHeader("checkbox");
+                //    label.setVisible(false);
+                //} else {
+                    label = column.getHeader("label");
+                //    checkBox = new CheckBox("checkbox");
+                //    checkBox.setVisible(false);
+                // }
+                header.add(label);
+                //header.add(checkBox);
+            }
+        };
+        add(headers);
+    }
+
+    /**
+     * Factory method for sortable header components. A sortable header component must have id of
+     * <code>headerId</code> and conform to markup specified in <code>HeadersToolbar.html</code>
+     * 
+     * @param headerId
+     *            header component id
+     * @param property
+     *            property this header represents
+     * @param locator
+     *            sort state locator
+     * @return created header component
+     */
+    protected WebMarkupContainer newSortableHeader(final String headerId, final S property,
+        final ISortStateLocator<S> locator)
+    {
+        return new OrderByBorder<S>(headerId, property, locator)
+        {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onSortChanged()
+            {
+                getTable().setCurrentPage(0);
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.html
deleted file mode 100644
index 79ae3b8..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
--->
-<wicket:panel xmlns:wicket="http://wicket.apache.org">
-    <tr class="headers">
-        <wicket:container wicket:id="headers">
-            <th wicket:id="header">
-                <span wicket:id="label">[header-label]</span>
-            </th>
-        </wicket:container>
-    </tr>
-</wicket:panel>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.java
deleted file mode 100644
index 1d441e0..0000000
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/MyHeadersToolbar.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/**
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.wicket.Component;
-import org.apache.wicket.behavior.Behavior;
-import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortStateLocator;
-import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractToolbar;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.HeadersToolbar;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.IStyledColumn;
-import org.apache.wicket.markup.ComponentTag;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.repeater.Item;
-import org.apache.wicket.markup.repeater.RefreshingView;
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.util.string.Strings;
-
-
-/**
- * Adapted from Wicket's own {@link HeadersToolbar}.
- */
-public class MyHeadersToolbar<S> extends AbstractToolbar
-{
-    private static final long serialVersionUID = 1L;
-
-    static abstract class CssAttributeBehavior extends Behavior
-    {
-        private static final long serialVersionUID = 1L;
-
-        protected abstract String getCssClass();
-
-        /**
-         * @see Behavior#onComponentTag(Component, ComponentTag)
-         */
-        @Override
-        public void onComponentTag(final Component component, final ComponentTag tag)
-        {
-            String className = getCssClass();
-            if (!Strings.isEmpty(className))
-            {
-                tag.append("class", className, " ");
-            }
-        }
-    }
-
-    /**
-     * Constructor
-     * 
-     * @param <T>
-     *            the column data type
-     * @param table
-     *            data table this toolbar will be attached to
-     * @param stateLocator
-     *            locator for the ISortState implementation used by sortable headers
-     */
-    public <T> MyHeadersToolbar(final DataTable<T, S> table, final ISortStateLocator<S> stateLocator)
-    {
-        super(table);
-
-        RefreshingView<IColumn<T, S>> headers = new RefreshingView<IColumn<T, S>>("headers")
-        {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            protected Iterator<IModel<IColumn<T, S>>> getItemModels()
-            {
-                List<IModel<IColumn<T, S>>> columnsModels = new LinkedList<IModel<IColumn<T, S>>>();
-
-                for (IColumn<T, S> column : table.getColumns())
-                {
-                    columnsModels.add(Model.of(column));
-                }
-
-                return columnsModels.iterator();
-            }
-
-            @Override
-            protected void populateItem(Item<IColumn<T, S>> item)
-            {
-                final IColumn<T, S> column = item.getModelObject();
-
-                WebMarkupContainer header = null;
-
-                if (column.isSortable())
-                {
-                    header = newSortableHeader("header", column.getSortProperty(), stateLocator);
-                }
-                else
-                {
-                    header = new WebMarkupContainer("header");
-                }
-
-                if (column instanceof IStyledColumn)
-                {
-                    CssAttributeBehavior cssAttributeBehavior = new CssAttributeBehavior()
-                    {
-                        private static final long serialVersionUID = 1L;
-
-                        @Override
-                        protected String getCssClass()
-                        {
-                            return ((IStyledColumn<?, S>)column).getCssClass();
-                        }
-                    };
-
-                    header.add(cssAttributeBehavior);
-                }
-
-                item.add(header);
-                item.setRenderBodyOnly(true);
-                
-                Component label;
-                //Component checkBox;
-                //if(column instanceof ObjectAdapterToggleboxColumn) {
-                    label = new Label("label");
-                //    checkBox = column.getHeader("checkbox");
-                //    label.setVisible(false);
-                //} else {
-                    label = column.getHeader("label");
-                //    checkBox = new CheckBox("checkbox");
-                //    checkBox.setVisible(false);
-                // }
-                header.add(label);
-                //header.add(checkBox);
-            }
-        };
-        add(headers);
-    }
-
-    /**
-     * Factory method for sortable header components. A sortable header component must have id of
-     * <code>headerId</code> and conform to markup specified in <code>HeadersToolbar.html</code>
-     * 
-     * @param headerId
-     *            header component id
-     * @param property
-     *            property this header represents
-     * @param locator
-     *            sort state locator
-     * @return created header component
-     */
-    protected WebMarkupContainer newSortableHeader(final String headerId, final S property,
-        final ISortStateLocator<S> locator)
-    {
-        return new OrderByBorder<S>(headerId, property, locator)
-        {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            protected void onSortChanged()
-            {
-                getTable().setCurrentPage(0);
-            }
-        };
-    }
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
index bf63837..e933f2b 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterToggleboxColumn.java
@@ -24,6 +24,7 @@ import java.util.List;
 import com.google.common.collect.Lists;
 
 import org.apache.wicket.Component;
+import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.Session;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
@@ -39,6 +40,7 @@ import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.viewer.wicket.model.common.SelectionHandler;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.checkbox.ContainedToggleboxPanel;
+import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
 public final class ObjectAdapterToggleboxColumn extends ColumnAbstract<ObjectAdapter> {
 
@@ -71,6 +73,14 @@ public final class ObjectAdapterToggleboxColumn extends ColumnAbstract<ObjectAda
             
     @Override
     public void populateItem(final Item<ICellPopulator<ObjectAdapter>> cellItem, final String componentId, final IModel<ObjectAdapter> rowModel) {
+        final MarkupContainer row = cellItem.getParent().getParent();
+        row.setOutputMarkupId(true);
+        final EntityModel entityModel = (EntityModel) rowModel;
+        String concurrencyExceptionIfAny = entityModel.getAndClearConcurrencyExceptionIfAny();
+        if(concurrencyExceptionIfAny != null) {
+            row.add(new CssClassAppender("reloaded-after-concurrency-exception"));
+        }
+        
         final ContainedToggleboxPanel toggle = new ContainedToggleboxPanel(componentId) {
             private static final long serialVersionUID = 1L;
             @Override
@@ -85,6 +95,8 @@ public final class ObjectAdapterToggleboxColumn extends ColumnAbstract<ObjectAda
                     // should work second time, because the previous attempt will have updated the OAM's OIDs version.
                     selectedAdapter = entityModel.load(ConcurrencyChecking.CHECK);
                     handler.onConcurrencyException(this, selectedAdapter, ex, target);
+                    
+                    entityModel.setException(ex);
                 }
             }
         };

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
index c581f0c..eae472c 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.css
@@ -846,4 +846,6 @@ div#jGrowl div.jGrowl-closer {
 
 .hidden {
 	display: none;
-}
\ No newline at end of file
+}
+
+

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
index 79eef11..e589df0 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/PageAbstract.java
@@ -88,6 +88,10 @@ public abstract class PageAbstract extends WebPage {
     public static final String ID_ABOUT_LINK = "aboutLink";
 
     private static final JavaScriptResourceReference JQUERY_JGROWL_JS = new JavaScriptResourceReference(PageAbstract.class, "jquery.jgrowl.js");
+    /**
+     * @see https://github.com/brandonaaron/livequery
+     */
+    private static final JavaScriptResourceReference JQUERY_LIVEQUERY_JS = new JavaScriptResourceReference(PageAbstract.class, "jquery.livequery.js");
     private static final JavaScriptResourceReference JQUERY_ISIS_WICKET_VIEWER_JS = new JavaScriptResourceReference(PageAbstract.class, "jquery.isis.wicket.viewer.js");
     
     //private static final JavaScriptResourceReference BOOTSTRAP_JS = new JavaScriptResourceReference(PageAbstract.class, "bootstrap/js/bootstrap.min.js");
@@ -177,8 +181,8 @@ public abstract class PageAbstract extends WebPage {
         super.renderHead(response);
         response.render(new PriorityHeaderItem(JavaScriptHeaderItem.forReference(Application.get().getJavaScriptLibrarySettings().getJQueryReference())));
         response.render(new PriorityHeaderItem(JavaScriptReferenceHeaderItem.forReference(JQUERY_JGROWL_JS)));
+        response.render(new PriorityHeaderItem(JavaScriptReferenceHeaderItem.forReference(JQUERY_LIVEQUERY_JS)));
         response.render(new PriorityHeaderItem(JavaScriptReferenceHeaderItem.forReference(JQUERY_ISIS_WICKET_VIEWER_JS)));
-        //response.render(new PriorityHeaderItem(JavaScriptReferenceHeaderItem.forReference(BOOTSTRAP_JS)));
         
         final String feedbackMsg = JGrowlUtil.asJGrowlCalls(getMessageBroker());
         if (!Strings.isNullOrEmpty(feedbackMsg)) {

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
index 4367501..c4afc78 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.isis.wicket.viewer.js
@@ -26,4 +26,14 @@ $(document).ready(function() {
     $('.cssSubMenuItemsPanel .cssSubMenuItem a:not(.noVeil)').click(showVeil);
     
     $('.first-field input').focus();
+    
+    
+    $('div.collectionContentsAsAjaxTablePanel > table.contents > tbody > tr.reloaded-after-concurrency-exception') 
+        .livequery(function(){
+            x=$(this);
+            $(this).animate({ "backgroundColor": "#FFF" }, 1000, "linear", function() {
+                $(x).css('background-color','').removeClass("reloaded-after-concurrency-exception");
+            }); 
+        }); 
+    
 });

http://git-wip-us.apache.org/repos/asf/isis/blob/0476cc57/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.livequery.js
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.livequery.js b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.livequery.js
new file mode 100644
index 0000000..0c8d4ff
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/jquery.livequery.js
@@ -0,0 +1,226 @@
+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (MIT_LICENSE.txt)
+ * and GPL Version 2 (GPL_LICENSE.txt) licenses.
+ *
+ * Version: 1.1.1
+ * Requires jQuery 1.3+
+ * Docs: http://docs.jquery.com/Plugins/livequery
+ */
+
+(function($) {
+
+$.extend($.fn, {
+    livequery: function(type, fn, fn2) {
+        var self = this, q;
+
+        // Handle different call patterns
+        if ($.isFunction(type))
+            fn2 = fn, fn = type, type = undefined;
+
+        // See if Live Query already exists
+        $.each( $.livequery.queries, function(i, query) {
+            if ( self.selector == query.selector && self.context == query.context &&
+                type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )
+                    // Found the query, exit the each loop
+                    return (q = query) && false;
+        });
+
+        // Create new Live Query if it wasn't found
+        q = q || new $.livequery(this.selector, this.context, type, fn, fn2);
+
+        // Make sure it is running
+        q.stopped = false;
+
+        // Run it immediately for the first time
+        q.run();
+
+        // Contnue the chain
+        return this;
+    },
+
+    expire: function(type, fn, fn2) {
+        var self = this;
+
+        // Handle different call patterns
+        if ($.isFunction(type))
+            fn2 = fn, fn = type, type = undefined;
+
+        // Find the Live Query based on arguments and stop it
+        $.each( $.livequery.queries, function(i, query) {
+            if ( self.selector == query.selector && self.context == query.context &&
+                (!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped )
+                    $.livequery.stop(query.id);
+        });
+
+        // Continue the chain
+        return this;
+    }
+});
+
+$.livequery = function(selector, context, type, fn, fn2) {
+    this.selector = selector;
+    this.context  = context;
+    this.type     = type;
+    this.fn       = fn;
+    this.fn2      = fn2;
+    this.elements = [];
+    this.stopped  = false;
+
+    // The id is the index of the Live Query in $.livequery.queries
+    this.id = $.livequery.queries.push(this)-1;
+
+    // Mark the functions for matching later on
+    fn.$lqguid = fn.$lqguid || $.livequery.guid++;
+    if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;
+
+    // Return the Live Query
+    return this;
+};
+
+$.livequery.prototype = {
+    stop: function() {
+        var query = this;
+
+        if ( this.type )
+            // Unbind all bound events
+            this.elements.unbind(this.type, this.fn);
+        else if (this.fn2)
+            // Call the second function for all matched elements
+            this.elements.each(function(i, el) {
+                query.fn2.apply(el);
+            });
+
+        // Clear out matched elements
+        this.elements = [];
+
+        // Stop the Live Query from running until restarted
+        this.stopped = true;
+    },
+
+    run: function() {
+        // Short-circuit if stopped
+        if ( this.stopped ) return;
+        var query = this;
+
+        var oEls = this.elements,
+            els  = $(this.selector, this.context),
+            nEls = els.not(oEls);
+
+        // Set elements to the latest set of matched elements
+        this.elements = els;
+
+        if (this.type) {
+            // Bind events to newly matched elements
+            nEls.bind(this.type, this.fn);
+
+            // Unbind events to elements no longer matched
+            if (oEls.length > 0)
+                $.each(oEls, function(i, el) {
+                    if ( $.inArray(el, els) < 0 )
+                        $.event.remove(el, query.type, query.fn);
+                });
+        }
+        else {
+            // Call the first function for newly matched elements
+            nEls.each(function() {
+                query.fn.apply(this);
+            });
+
+            // Call the second function for elements no longer matched
+            if ( this.fn2 && oEls.length > 0 )
+                $.each(oEls, function(i, el) {
+                    if ( $.inArray(el, els) < 0 )
+                        query.fn2.apply(el);
+                });
+        }
+    }
+};
+
+$.extend($.livequery, {
+    guid: 0,
+    queries: [],
+    queue: [],
+    running: false,
+    timeout: null,
+
+    checkQueue: function() {
+        if ( $.livequery.running && $.livequery.queue.length ) {
+            var length = $.livequery.queue.length;
+            // Run each Live Query currently in the queue
+            while ( length-- )
+                $.livequery.queries[ $.livequery.queue.shift() ].run();
+        }
+    },
+
+    pause: function() {
+        // Don't run anymore Live Queries until restarted
+        $.livequery.running = false;
+    },
+
+    play: function() {
+        // Restart Live Queries
+        $.livequery.running = true;
+        // Request a run of the Live Queries
+        $.livequery.run();
+    },
+
+    registerPlugin: function() {
+        $.each( arguments, function(i,n) {
+            // Short-circuit if the method doesn't exist
+            if (!$.fn[n]) return;
+
+            // Save a reference to the original method
+            var old = $.fn[n];
+
+            // Create a new method
+            $.fn[n] = function() {
+                // Call the original method
+                var r = old.apply(this, arguments);
+
+                // Request a run of the Live Queries
+                $.livequery.run();
+
+                // Return the original methods result
+                return r;
+            }
+        });
+    },
+
+    run: function(id) {
+        if (id != undefined) {
+            // Put the particular Live Query in the queue if it doesn't already exist
+            if ( $.inArray(id, $.livequery.queue) < 0 )
+                $.livequery.queue.push( id );
+        }
+        else
+            // Put each Live Query in the queue if it doesn't already exist
+            $.each( $.livequery.queries, function(id) {
+                if ( $.inArray(id, $.livequery.queue) < 0 )
+                    $.livequery.queue.push( id );
+            });
+
+        // Clear timeout if it already exists
+        if ($.livequery.timeout) clearTimeout($.livequery.timeout);
+        // Create a timeout to check the queue and actually run the Live Queries
+        $.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
+    },
+
+    stop: function(id) {
+        if (id != undefined)
+            // Stop are particular Live Query
+            $.livequery.queries[ id ].stop();
+        else
+            // Stop all Live Queries
+            $.each( $.livequery.queries, function(id) {
+                $.livequery.queries[ id ].stop();
+            });
+    }
+});
+
+// Register core DOM manipulation methods
+$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove', 'html');
+
+// Run Live Queries when the Document is ready
+$(function() { $.livequery.play(); });
+
+})(jQuery);
\ No newline at end of file


[2/2] git commit: ISIS-401: show concurrency ex. if object changed while action prompt is displayed

Posted by da...@apache.org.
ISIS-401: show concurrency ex. if object changed while action prompt is displayed

In fact, was displaying already for some actions (eg ToDoItem#updateCost).  However,
for ToDoItem#updateCategories(...) it was not, because the loading of the
object adapters to compute the choices was causing the adapter to be
silently resynced.

This is now captured and we forward onto the entity page, as per normal.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/f328529b
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/f328529b
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/f328529b

Branch: refs/heads/master
Commit: f328529bd51f4a65a5fa3a6080450845b744bcef
Parents: 0476cc5
Author: Dan Haywood <da...@apache.org>
Authored: Wed Oct 16 08:32:27 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Wed Oct 16 08:32:27 2013 +0100

----------------------------------------------------------------------
 .../viewer/wicket/model/models/ScalarModel.java |  2 +-
 .../actions/ActionParametersFormPanel.java      | 39 +++++++++++++++-----
 .../adaptermanager/AdapterManagerDefault.java   | 10 ++++-
 3 files changed, 40 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/f328529b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
index 262fe55..b226b53 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
@@ -301,7 +301,7 @@ public class ScalarModel extends EntityModel implements LinksProvider {
             public List<ObjectAdapter> getChoices(final ScalarModel scalarModel, final ObjectAdapter[] argumentsIfAvailable) {
                 final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
                 final ObjectActionParameter actionParameter = parameterMemento.getActionParameter();
-                final ObjectAdapter[] choices = actionParameter.getChoices(scalarModel.parentObjectAdapterMemento.getObjectAdapter(ConcurrencyChecking.NO_CHECK), argumentsIfAvailable);
+                final ObjectAdapter[] choices = actionParameter.getChoices(scalarModel.parentObjectAdapterMemento.getObjectAdapter(ConcurrencyChecking.CHECK), argumentsIfAvailable);
                 return choicesAsList(choices);
             }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/f328529b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
index e04e4cf..f935810 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersFormPanel.java
@@ -30,6 +30,7 @@ import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
 import org.apache.wicket.Component;
+import org.apache.wicket.RestartResponseAtInterceptPageException;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.form.Button;
@@ -41,6 +42,7 @@ import org.apache.isis.core.commons.ensure.Ensure;
 import org.apache.isis.core.commons.lang.ObjectExtensions;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.viewer.wicket.model.mementos.ActionParameterMemento;
@@ -50,10 +52,12 @@ import org.apache.isis.viewer.wicket.model.models.ActionModel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.model.util.MementoFunctions;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.components.actions.ActionPanel.ResultType;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarModelSubscriber;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
 import org.apache.isis.viewer.wicket.ui.components.scalars.TextFieldValueModel.ScalarModelProvider;
 import org.apache.isis.viewer.wicket.ui.components.widgets.formcomponent.FormFeedbackPanel;
+import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
@@ -173,16 +177,33 @@ public class ActionParametersFormPanel extends PanelAbstract<ActionModel> {
             final ActionModel actionModel = getActionModel();
             
             final ObjectAdapter[] pendingArguments = actionModel.getArgumentsAsArray();
-            System.out.println(pendingArguments);
-
-            final ObjectAction action = actionModel.getActionMemento().getAction();
-            final int numParams = action.getParameterCount();
-            for (int i = 0; i < numParams; i++) {
-                final ScalarPanelAbstract paramPanel = paramPanels.get(i);
-                if(paramPanel != null) {
-                    paramPanel.updateChoices(pendingArguments);
-                    target.add(paramPanel);
+            
+            try {
+                final ObjectAction action = actionModel.getActionMemento().getAction();
+                final int numParams = action.getParameterCount();
+                for (int i = 0; i < numParams; i++) {
+                    final ScalarPanelAbstract paramPanel = paramPanels.get(i);
+                    if(paramPanel != null) {
+                        // this could throw a ConcurrencyException as we may have to reload the 
+                        // object adapter of the action in order to compute the choices
+                        // (and that object adapter might have changed)
+                        paramPanel.updateChoices(pendingArguments);
+                        target.add(paramPanel);
+                    }
                 }
+            } catch(ConcurrencyException ex) {
+                
+                // second attempt should succeed, because the Oid would have
+                // been updated in the attempt
+                ObjectAdapter targetAdapter = getActionModel().getTargetAdapter();
+
+                // forward onto the target page with the concurrency exception
+                final EntityPage entityPage = new EntityPage(targetAdapter, ex);
+                
+                ActionParametersFormPanel.this.setResponsePage(entityPage);
+                
+                getAuthenticationSession().getMessageBroker().addWarning(ex.getMessage());
+                return;
             }
             
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/f328529b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
index 74a98a7..5ceb378 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
@@ -335,8 +335,16 @@ public class AdapterManagerDefault implements AdapterManagerSpi {
                     }
                 }
             } finally {
+                
+                final Version originalVersion = originalOid.getVersion();
                 final Version recreatedVersion = recreatedOid.getVersion();
-                originalOid.setVersion(recreatedVersion);
+                if(recreatedVersion != null && (
+                        originalVersion == null || 
+                        recreatedVersion.different(originalVersion))
+                    ) {
+                   LOG.info("updating version in oid, on " + originalOid + " (" + originalVersion + ") to (" + recreatedVersion +")");
+                   originalOid.setVersion(recreatedVersion);
+                }
             }
         }