Required Information

Version(s) of Ext GWT
Sencha GXT 3.0.

Browser versions and OS
(and desktop environment, if applicable)
  • Chromium 18.0.1025.168, Ubuntu 12.04, Unity;
  • Firefox 12.0, Ubuntu 12.04, Unity.

Virtual Machine
No.

Description
The problem occurs in the File Manager of the Web Desktop example in Sencha GXT 3.0.
The abnormal behavior (data loss or exceptions thrown) is caused by the possibility to initiate an action after starting to edit a file name but before cancelling or completing the edit and by not tracking which FileModel has its name edited.

Run mode
Both.

Steps to reproduce the problem
Case 1:
  1. Open File Manager.
  2. Create a document.
  3. Deselect the document.
  4. Click “New Spreadsheet”.
  5. Click on the document.


Case 2:
  1. Open File Manager.
  2. Click “New Document”.
  3. Click “Delete” promptly.
  4. Close File Manager.


Case 3 (Chromium only):
  1. Open File Manager.
  2. Click “New Folder”.
  3. Click “New Bookmark”.


Expected result
Ad 1. The document is not replaced by the spreadsheet.
Ad 2. No exception is thrown.
Ad 3. No exception is thrown.

Actual result
Ad 1. The spreadsheet replaces the document.
Ad 2. An exception is thrown.
Ad 3. An exception is thrown.

Helpful Information

Live test
http://www.sencha.com/examples/desktop.html

Possible fix
It is possible to fix this problem by disabling toolbar buttons while editing a file name and by tracking which FileModel is being edited and modifying only that model in “onEditFileNameComplete”.

To the extent possible under law, the author has dedicated all copyright and related and neighboring rights to this patch to the public domain worldwide. This patch is distributed without any warranty.
Code:
diff --git examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenter.java examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenter.java
index 46fd1b4..3ace954 100644
--- examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenter.java
+++ examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenter.java
@@ -27,7 +27,7 @@ public interface FileManagerPresenter extends Presenter {
 
   void onDelete();
 
-  void onEditFileNameComplete(boolean isSaved);
+  void onEditFileNameComplete(FileModel fileModel, boolean isSaved);
 
   void onEditName();
 
diff --git examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenterImpl.java examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenterImpl.java
index 8be02bc..fded04d 100644
--- examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenterImpl.java
+++ examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerPresenterImpl.java
@@ -24,7 +24,6 @@ public class FileManagerPresenterImpl implements FileManagerPresenter {
   private DesktopBus desktopBus;
 
   private FileManagerView fileManagerView;
-  private boolean isNewlyCreated;
 
   public FileManagerPresenterImpl(FileSystem fileSystem, DesktopBus desktopBus) {
     this.fileSystem = fileSystem;
@@ -44,19 +43,19 @@ public class FileManagerPresenterImpl implements FileManagerPresenter {
   public boolean isEnableCreate() {
     FileModel selectedItem = getFileManagerView().getSelectedItem();
     FileType fileType = selectedItem == null ? null : selectedItem.getFileType();
-    return fileType == null || fileType == FileType.FOLDER;
+    return (fileType == null || fileType == FileType.FOLDER) && !getFileManagerView().isNameEdited();
   }
 
   @Override
   public boolean isEnableDelete() {
     FileModel selectedItem = getFileManagerView().getSelectedItem();
-    return selectedItem != null;
+    return selectedItem != null && !getFileManagerView().isNameEdited();
   }
 
   @Override
   public boolean isEnableEditName() {
     FileModel selectedItem = getFileManagerView().getSelectedItem();
-    return selectedItem != null;
+    return selectedItem != null && !getFileManagerView().isNameEdited();
   }
 
   @Override
@@ -74,7 +73,7 @@ public class FileManagerPresenterImpl implements FileManagerPresenter {
           break;
       }
     }
-    return isEnableOpen;
+    return isEnableOpen && !getFileManagerView().isNameEdited();
   }
 
   @Override
@@ -88,7 +87,7 @@ public class FileManagerPresenterImpl implements FileManagerPresenter {
     String name = getFileSystem().getNextUntitledFileName(parentFileModel, fileType);
     FileModel childFileModel = getFileSystem().createFileModel(parentFileModel, name, fileType);
     getFileManagerView().selectFileModel(childFileModel);
-    isNewlyCreated = true;
+    childFileModel.setNewlyCreated(true);
     getFileManagerView().editName(childFileModel);
   }
 
@@ -101,17 +100,16 @@ public class FileManagerPresenterImpl implements FileManagerPresenter {
   }
 
   @Override
-  public void onEditFileNameComplete(boolean isSaved) {
-    FileModel fileModel = getFileManagerView().getSelectedItem();
+  public void onEditFileNameComplete(FileModel fileModel, boolean isSaved) {
     if (fileModel != null) {
       fileModel.setLastModified(new Date());
     }
-    if (isNewlyCreated) {
-      isNewlyCreated = false;
+    if (fileModel.getNewlyCreated()) {
+      fileModel.setNewlyCreated(false);
       if (isSaved) {
-        onOpen();
+        getDesktopBus().fireOpenFileModelEvent(new OpenFileModelEvent(getFileSystem(), fileModel));
       } else {
-        onDelete();
+        getFileSystem().remove(fileModel);
       }
     }
   }
diff --git examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerView.java examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerView.java
index 34b33aa..2d7e9a2 100644
--- examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerView.java
+++ examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerView.java
@@ -14,6 +14,8 @@ import com.sencha.gxt.desktopapp.client.persistence.FileModel;
 
 public interface FileManagerView extends IsWidget {
 
+  public boolean isNameEdited();
+
   public void collapse();
 
   public void editName(FileModel childFileModel);
diff --git examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerViewImpl.java examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerViewImpl.java
index b44c22d..8d2573c 100644
--- examples-src/com/sencha/gxt/desktopapp/client/filemanager/FileManagerViewImpl.java
+++ examples-src-patched/com/sencha/gxt/desktopapp/client/filemanager/FileManagerViewImpl.java
@@ -72,9 +72,21 @@ public class FileManagerViewImpl implements FileManagerView, HideHandler {
   private CancelEditHandler<FileModel> cancelEditHandler;
   private FileModel editFileModel;
 
+  private boolean nameEdited;
+
   public FileManagerViewImpl(FileManagerPresenter fileManagerPresenter, FileSystem fileSystem) {
     this.fileManagerPresenter = fileManagerPresenter;
     this.fileSystem = fileSystem;
+    this.nameEdited = false;
+  }
+
+  @Override
+  public boolean isNameEdited() {
+    return this.nameEdited;
+  }
+
+  private void setNameEdited(boolean nameEdited) {
+    this.nameEdited = nameEdited;
   }
 
   @Override
@@ -94,6 +106,8 @@ public class FileManagerViewImpl implements FileManagerView, HideHandler {
 
   @Override
   public void editName(FileModel fileModel) {
+    setNameEdited(true);
+    getFileManagerToolBar().setButtonEnabledState();
     editSaveFileModel(fileModel);
     Element row = getTreeGrid().getView().getRow(fileModel);
     int rowIndex = getTreeGrid().getView().findRowIndex(row);
@@ -159,11 +173,14 @@ public class FileManagerViewImpl implements FileManagerView, HideHandler {
            * update operation that does not change the value is reported as a
            * cancel.
            */
+          FileModel fileModel = getTreeGrid().getStore().get(event.getEditCell().getCol());
           if (gridEditing.isEnter()) {
-            getFileManagerPresenter().onEditFileNameComplete(true);
+            getFileManagerPresenter().onEditFileNameComplete(fileModel, true);
           } else {
-            getFileManagerPresenter().onEditFileNameComplete(false);
+            getFileManagerPresenter().onEditFileNameComplete(fileModel, false);
           }
+          setNameEdited(false);
+          getFileManagerToolBar().setButtonEnabledState();
         }
       };
     }
@@ -188,7 +205,10 @@ public class FileManagerViewImpl implements FileManagerView, HideHandler {
         @Override
         public void onCompleteEdit(CompleteEditEvent<FileModel> event) {
           editRestoreFileModel();
-          getFileManagerPresenter().onEditFileNameComplete(true);
+          FileModel fileModel = getTreeGrid().getStore().get(event.getEditCell().getCol());
+          getFileManagerPresenter().onEditFileNameComplete(fileModel, true);
+          setNameEdited(false);
+          getFileManagerToolBar().setButtonEnabledState();
           // Give the change a chance to propagate to model and store
           Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
             @Override
diff --git examples-src/com/sencha/gxt/desktopapp/client/persistence/FileModel.java examples-src-patched/com/sencha/gxt/desktopapp/client/persistence/FileModel.java
index ea5adc4..8d94464 100644
--- examples-src/com/sencha/gxt/desktopapp/client/persistence/FileModel.java
+++ examples-src-patched/com/sencha/gxt/desktopapp/client/persistence/FileModel.java
@@ -21,6 +21,8 @@ public interface FileModel {
     }
   }
 
+  public boolean getNewlyCreated();
+
   public String getContent();
 
   public FileType getFileType();
@@ -33,6 +35,8 @@ public interface FileModel {
 
   public Long getSize();
 
+  public void setNewlyCreated(boolean newlyCreated);
+
   public void setContent(String content);
 
   public void setFileType(FileType fileType);