Moved all web client files to their folder. Updated ignored files
authorChristos Stathis <chstath@ebs.gr>
Wed, 27 Apr 2011 16:10:51 +0000 (19:10 +0300)
committerChristos Stathis <chstath@ebs.gr>
Wed, 27 Apr 2011 16:10:51 +0000 (19:10 +0300)
257 files changed:
build.xml [new file with mode: 0644]
src/com/google/gwt/user/cellview/client/GssSimplePager.java [new file with mode: 0644]
src/org/gss_project/gss/resources/advancedsettings.png [new file with mode: 0644]
src/org/gss_project/gss/resources/ajax-loader.gif [new file with mode: 0644]
src/org/gss_project/gss/resources/asc.png [new file with mode: 0644]
src/org/gss_project/gss/resources/bell.png [new file with mode: 0644]
src/org/gss_project/gss/resources/blank.gif [new file with mode: 0644]
src/org/gss_project/gss/resources/border_remove.png [new file with mode: 0644]
src/org/gss_project/gss/resources/bug.png [new file with mode: 0755]
src/org/gss_project/gss/resources/configure.png [new file with mode: 0644]
src/org/gss_project/gss/resources/database.png [new file with mode: 0644]
src/org/gss_project/gss/resources/db_update.png [new file with mode: 0644]
src/org/gss_project/gss/resources/demo.png [new file with mode: 0644]
src/org/gss_project/gss/resources/desc.png [new file with mode: 0644]
src/org/gss_project/gss/resources/doc_versions.png [new file with mode: 0644]
src/org/gss_project/gss/resources/document.png [new file with mode: 0644]
src/org/gss_project/gss/resources/edit.png [new file with mode: 0644]
src/org/gss_project/gss/resources/edit_add.png [new file with mode: 0755]
src/org/gss_project/gss/resources/edit_group.png [new file with mode: 0644]
src/org/gss_project/gss/resources/edit_group_22.png [new file with mode: 0644]
src/org/gss_project/gss/resources/edit_user.png [new file with mode: 0644]
src/org/gss_project/gss/resources/editcopy.png [new file with mode: 0644]
src/org/gss_project/gss/resources/editcut.png [new file with mode: 0644]
src/org/gss_project/gss/resources/editdelete.png [new file with mode: 0644]
src/org/gss_project/gss/resources/editpaste.png [new file with mode: 0644]
src/org/gss_project/gss/resources/exit.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_blue.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_green.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_home.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_inbox.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_new.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_outbox.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_user.png [new file with mode: 0644]
src/org/gss_project/gss/resources/folder_yellow.png [new file with mode: 0644]
src/org/gss_project/gss/resources/greenled.png [new file with mode: 0644]
src/org/gss_project/gss/resources/grnet-logo.png [new file with mode: 0644]
src/org/gss_project/gss/resources/group.png [new file with mode: 0644]
src/org/gss_project/gss/resources/groupevent.png [new file with mode: 0644]
src/org/gss_project/gss/resources/help.png [new file with mode: 0644]
src/org/gss_project/gss/resources/info.png [new file with mode: 0644]
src/org/gss_project/gss/resources/internet.png [new file with mode: 0644]
src/org/gss_project/gss/resources/khelpcenter.png [new file with mode: 0644]
src/org/gss_project/gss/resources/linewidth.png [new file with mode: 0644]
src/org/gss_project/gss/resources/lock.png [new file with mode: 0644]
src/org/gss_project/gss/resources/messagebox_critical.png [new file with mode: 0644]
src/org/gss_project/gss/resources/messagebox_info.png [new file with mode: 0644]
src/org/gss_project/gss/resources/messagebox_warning.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/acroread.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/acroread_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/ark2.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/ark2_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/document.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/document_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/html.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/html_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/image.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/image_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/kcmfontinst.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/kcmfontinst_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/knotify.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/knotify_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/log.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/log_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/txt.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/txt_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/video2.png [new file with mode: 0644]
src/org/gss_project/gss/resources/mimetypes/video2_shared.png [new file with mode: 0644]
src/org/gss_project/gss/resources/pithos-logo.png [new file with mode: 0644]
src/org/gss_project/gss/resources/redled.png [new file with mode: 0644]
src/org/gss_project/gss/resources/refresh.png [new file with mode: 0644]
src/org/gss_project/gss/resources/refresh2.png [new file with mode: 0644]
src/org/gss_project/gss/resources/search.png [new file with mode: 0644]
src/org/gss_project/gss/resources/search_16.png [new file with mode: 0644]
src/org/gss_project/gss/resources/translate.png [new file with mode: 0644]
src/org/gss_project/gss/resources/trashcan_empty.png [new file with mode: 0644]
src/org/gss_project/gss/resources/view_text.png [new file with mode: 0644]
src/org/gss_project/gss/resources/windowlist.png [new file with mode: 0644]
src/org/gss_project/gss/resources/xclock.png [new file with mode: 0755]
src/org/gss_project/gss/resources/yellowled.png [new file with mode: 0644]
src/org/gss_project/gss/web/GSS.gwt.xml [new file with mode: 0644]
src/org/gss_project/gss/web/client/AboutDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/AbstractPropertiesDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/CellTreeView.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/CellTreeViewModel.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/CellTreeViewUtils.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/Configuration.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/Configuration.properties [new file with mode: 0644]
src/org/gss_project/gss/web/client/ConfirmationDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/CredentialsDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/DeleteFileDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/DeleteFolderDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/DeleteGroupDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/DeleteUserDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/DisplayHelper.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/DnDFolderPopupMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/EditMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FileContextMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FileList.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FileMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FilePropertiesDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FileTable.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FileUploadDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FileUploadGearsDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FileUploadGearsIEDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FilesPropertiesDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FolderContextMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/FolderPropertiesDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/GSS.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/GSSSelectionEventManager.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/GlassPanel.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/GroupContextMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/GroupMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/GroupPropertiesDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/Groups.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/GssCellTable.css [new file with mode: 0644]
src/org/gss_project/gss/web/client/GssCellTreeBasic.css [new file with mode: 0644]
src/org/gss_project/gss/web/client/HelpMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/InsufficientPermissionsException.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/LoadingIndicator.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/MessagePanel.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/ObjectNotFoundException.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/PermissionsAddDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/PermissionsList.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/ProgressBar.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/QuitDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/Search.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/SearchResults.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/SessionExpiredDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/SettingsMenu.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/SortableHeader.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/StatusPanel.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/TopPanel.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/Updateable.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/UserAddDialog.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/UserDetailsPanel.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/VersionsList.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/animation/FadeIn.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/animation/FadeOut.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/cellTreeClosedItem.gif [new file with mode: 0644]
src/org/gss_project/gss/web/client/cellTreeLoadingBasic.gif [new file with mode: 0644]
src/org/gss_project/gss/web/client/cellTreeOpenItem.gif [new file with mode: 0644]
src/org/gss_project/gss/web/client/clipboard/Clipboard.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/clipboard/ClipboardItem.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/CopyCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/CutCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/DeleteCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/DeleteUserOrGroupCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/EmptyTrashCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/GetUserCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/NewFolderCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/NewGroupCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/NewUserCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/PasteCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/PropertiesCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/RefreshCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/ResreshOthersSharesCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/RestoreTrashCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/ToTrashCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/UploadFileCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/commands/ViewImageCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/components/TristateCheckBox.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/downArrow.png [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/CallbackList.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/DeleteCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/GetCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/HeadCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/MultipleDeleteCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/MultipleGetCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/MultipleHeadCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/MultiplePostCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/PostCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/RestCallback.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/RestCommand.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/RestException.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/RestGetCallback.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/FileResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/FolderResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/GroupResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/GroupUserResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/GroupsResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/MyFolderResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/OtherUserResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/OthersFolderResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/OthersResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/PermissionHolder.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/QuotaHolder.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/RestResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/RestResourceWrapper.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/SearchResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/SharedFolderResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/SharedResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/TagsResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/TrashFolderResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/TrashResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/UploadStatusResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/UserResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/rest/resource/UserSearchResource.java [new file with mode: 0644]
src/org/gss_project/gss/web/client/upArrow.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/GSS.html [new file with mode: 0644]
src/org/gss_project/gss/web/public/error403.html [new file with mode: 0644]
src/org/gss_project/gss/web/public/error502.html [new file with mode: 0644]
src/org/gss_project/gss/web/public/error503.html [new file with mode: 0644]
src/org/gss_project/gss/web/public/gss.css [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/background.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/blank.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/bottom.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/close_blue.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/close_gold.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/close_green.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/close_grey.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/close_red.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/header.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/loading.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/next_blue.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/next_gold.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/next_green.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/next_grey.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/next_red.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/page_shadow.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/pause_blue.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/pause_gold.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/pause_green.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/pause_grey.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/pause_red.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/play_blue.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/play_gold.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/play_green.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/play_grey.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/play_red.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/prev_blue.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/prev_gold.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/prev_green.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/prev_grey.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/prev_red.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/service-logo.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/tristate_checked.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/tristate_intermediate.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/images/tristate_unchecked.gif [new file with mode: 0644]
src/org/gss_project/gss/web/public/logout.html [new file with mode: 0644]
src/org/gss_project/gss/web/public/lytebox.css [new file with mode: 0644]
src/org/gss_project/gss/web/public/lytebox.js [new file with mode: 0644]
src/org/gss_project/gss/web/public/main.css [new file with mode: 0644]
src/org/gss_project/gss/web/public/sha1.js [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/corner.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/hborder.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topleft.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topright.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/ie6/hborder_blue_shadow.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/ie6/hborder_gray_shadow.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/ie6/vborder_blue_shadow.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/ie6/vborder_gray_shadow.png [new file with mode: 0644]
src/org/gss_project/gss/web/public/suggest/vborder.png [new file with mode: 0644]
war/WEB-INF/lib/commons-fileupload-1.2.jar [new file with mode: 0644]
war/WEB-INF/lib/commons-io-1.3.2.jar [new file with mode: 0644]
war/WEB-INF/web.xml [new file with mode: 0644]

diff --git a/build.xml b/build.xml
new file mode 100644 (file)
index 0000000..6c4aebb
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<project name="gss" default="package-war" basedir=".">
+       <description>The GSS project build file</description>
+
+       <property file="build.properties"/>
+    <property name="deps.dir" value="dependencies"/>
+
+    <property name="gwt.workers" value="1"/>
+    <property name="jboss.args" value="-b 0.0.0.0" />
+
+    <property name="jboss.version" value="5.1.0"/>
+    <property name="jboss.home" value="${deps.dir}/jboss-${jboss.version}.GA" />
+    <property name="jboss.bin.dir" value="${jboss.home}/bin" />
+    <property name="jboss.conf.dir" value="${jboss.home}/server/default/conf" />
+    <property name="jboss.deploy.dir" value="${jboss.home}/server/default/deploy" />
+    <property name="jboss.lib.dir" value="${jboss.home}/server/default/lib" />
+    <property name="jboss.root.lib.dir" value="${jboss.home}/lib" />
+    <property name="jboss.common.lib.dir" value="${jboss.home}/common/lib" />
+    <property name="jboss.filename" value="jboss-${jboss.version}.GA-jdk6.zip"/>
+       <property name="jboss.download.url" value="http://switch.dl.sourceforge.net/project/jboss/JBoss/JBoss-${jboss.version}.GA/${jboss.filename}"/>
+
+    <property name="gwt.version" value="2.1.1"/>
+       <property name="gwt.home" value="${deps.dir}/gwt-${gwt.version}"/>
+    <property name="gwt.filename" value="gwt-${gwt.version}.zip"/>
+    <property name="gwt.download.url" value="http://google-web-toolkit.googlecode.com/files/${gwt.filename}"/>
+
+    <property name="gwt-gears.version" value="1.3.0"/>
+    <property name="gwt-gears.home" value="${deps.dir}/gwt-gears-${gwt-gears.version}" />
+    <property name="gwt-gears.filename" value="gwt-gears-${gwt-gears.version}.zip"/>
+    <property name="gwt-gears.download.url" value="http://gwt-google-apis.googlecode.com/files/${gwt-gears.filename}"/>
+
+    <property name="gwt-incubator.filename" value="gwt-incubator-20101117-r1766.jar"/>
+    <property name="gwt-incubator.download.url" value="http://google-web-toolkit-incubator.googlecode.com/files/gwt-incubator-20101117-r1766.jar"/>
+    <property name="gwt-visualization.home" value="${deps.dir}/gwt-visualization-1.1.0" />
+    <property name="gwt-visualization.filename" value="gwt-visualization-1.1.0.zip"/>
+    <property name="gwt-visualization.download.url" value="http://gwt-google-apis.googlecode.com/files/${gwt-visualization.filename}"/>
+
+    <property name="gwtquery.filename" value="gwtquery-1.0.0-20110116.074055-7.jar"/>
+    <property name="gwtquery.download.url" value="http://gss.googlecode.com/hg/lib/${gwtquery.filename}?r=0473a2c1bc32c9426423f8ca3b688a29ce30216b"/>
+    <property name="gwtquery-draggable-plugin.filename" value="draggable-plugin-1.0.2.jar"/>
+    <property name="gwtquery-draggable-plugin.download.url" value="http://gss.googlecode.com/hg/lib/${gwtquery-draggable-plugin.filename}?r=0634eeeeaaad1b9bfb7a8e809bfc9e9545d208e2"/>
+    <property name="gwtquery-droppable-plugin.filename" value="droppable-plugin-1.0.2.jar"/>
+    <property name="gwtquery-droppable-plugin.download.url" value="http://gss.googlecode.com/hg/lib/${gwtquery-droppable-plugin.filename}?r=c8bca56a1c4ab780ac0d0cc72a2b40b60d7ca4f7"/>
+    <property name="gwtquery-commonui-plugin.filename" value="commonui-plugin-1.0.3.jar"/>
+    <property name="gwtquery-commonui-plugin.download.url" value="http://gss.googlecode.com/hg/lib/${gwtquery-commonui-plugin.filename}?r=0473a2c1bc32c9426423f8ca3b688a29ce30216b"/>
+
+    <property name="root.context" value="gss" />
+    <property name="gwt.module.class" value="GSS" />
+    <property name="gwt.root.package" value="org.gss_project.gss.web" />
+    <property name="gwt.root.path" value="org/gss_project/gss/web" />
+    <property name="gwt.module" value="${gwt.root.package}.${gwt.module.class}" />
+
+       <property name="src.dir" value="${basedir}/src"/>
+
+       <!-- Build dirs -->
+       <property name="build.dir" value="${basedir}/bin" />
+       <property name="build.classes.dir" value="${build.dir}/classes" />
+       <property name="gwt.www.dir" value="${build.dir}/www" />
+       <property name="gwt.www.admin.dir" value="${build.dir}/wwwadmin" />
+       <property name="dist.war" value="${ant.project.name}.war"/>
+       <property name="war.dir" value="${basedir}/war" />
+       <property name="war.web-inf.dir" value="${war.dir}/WEB-INF"/>
+       <property name="war.lib.dir" value="${war.web-inf.dir}/lib"/>
+
+       <!-- set classpath -->
+       <path id="project.class.path">
+        <pathelement location="${gwt.home}/gwt-user.jar"/>
+        <pathelement location="${war.lib.dir}/commons-fileupload-1.2.jar"/>
+       </path>
+
+       <target name="check-dependencies" description="Checks if all dependencies are present">
+        <condition property="dependencies.present">
+            <and>
+                <available file="${jboss.home}" type="dir"/>
+                <available file="${gwt.home}" type="dir"/>
+                <available file="${gwt-gears.home}" type="dir"/>
+                <available file="${deps.dir}/${gwtquery.filename}"/>
+                <available file="${deps.dir}/${gwtquery-draggable-plugin.filename}"/>
+                <available file="${deps.dir}/${gwtquery-droppable-plugin.filename}"/>
+                <available file="${deps.dir}/${gwtquery-commonui-plugin.filename}"/>
+                <available file="${deps.dir}/${gwt-incubator.filename}"/>
+                <available file="${deps.dir}/${gwt-visualization.filename}"/>
+            </and>
+        </condition>
+        <echo message="dependencies.present=${dependencies.present}"/>
+    </target>
+
+    <target name="fetch-dependencies" unless="dependencies.present" description="Fetch the dpendencies if not present" depends="check-dependencies">
+       <mkdir dir="${deps.dir}"/>
+        <get src="${gwt.download.url}" dest="${deps.dir}/${gwt.filename}" usetimestamp="true"/>
+        <get src="${gwt-gears.download.url}" dest="${deps.dir}/${gwt-gears.filename}" usetimestamp="true"/>
+        <get src="${gwt-incubator.download.url}" dest="${deps.dir}/${gwt-incubator.filename}"/>
+        <get src="${gwt-visualization.download.url}" dest="${deps.dir}/${gwt-visualization.filename}"/>
+        <get src="${gwtquery.download.url}" dest="${deps.dir}/${gwtquery.filename}" usetimestamp="true"/>
+        <get src="${gwtquery-draggable-plugin.download.url}" dest="${deps.dir}/${gwtquery-draggable-plugin.filename}" usetimestamp="true"/>
+        <get src="${gwtquery-droppable-plugin.download.url}" dest="${deps.dir}/${gwtquery-droppable-plugin.filename}" usetimestamp="true"/>
+        <get src="${gwtquery-commonui-plugin.download.url}" dest="${deps.dir}/${gwtquery-commonui-plugin.filename}" usetimestamp="true"/>
+       <unzip src="${deps.dir}/${gwt.filename}" dest="${gwt.home}/.."/>
+        <unzip src="${deps.dir}/${gwt-gears.filename}" dest="${gwt-gears.home}/.."/>
+        <unzip src="${deps.dir}/${gwt-visualization.filename}" dest="${gwt-visualization.home}/.."/>
+    </target>
+
+       <target name="check-gwt-compile" description="Checks is the web gwt client sources are up-to-date with the compiled artifacts">
+               <uptodate property="compilation-not-needed">
+                       <srcfiles dir="${src.dir}">
+                <include name="${gwt.root.path}/**"/>
+            </srcfiles>
+                       <mergemapper to="${gwt.www.dir}/${gwt.module}/${gwt.module}.nocache.js"/>
+               </uptodate>
+       </target>
+
+       <target name="gwt-compile" depends="check-gwt-compile, fetch-dependencies" unless="compilation-not-needed" description="Compile the gwt web client code to JavaScript">
+               <java classname="com.google.gwt.dev.Compiler" failonerror="true" fork="true">
+                       <arg value="-localWorkers" />
+                       <arg value="${gwt.workers}" />
+                       <arg value="-war"/>
+                       <arg value="${gwt.www.dir}"/>
+                       <arg value="${gwt.module}"/>
+                       
+                   <classpath>
+                <pathelement path="${gwt.home}/gwt-dev.jar"/>
+                <pathelement location="${deps.dir}/${gwtquery.filename}"/>
+                <pathelement location="${deps.dir}/${gwtquery-droppable-plugin.filename}"/>
+                <pathelement location="${deps.dir}/${gwtquery-draggable-plugin.filename}"/>
+                <pathelement location="${deps.dir}/${gwtquery-commonui-plugin.filename}"/>
+                <pathelement location="${gwt-gears.home}/gwt-gears.jar"/>
+                <pathelement path="${gwt.home}/gwt-user.jar" />
+                               <path refid="project.class.path"/>
+                               <pathelement path="${src.dir}" />
+                   </classpath>
+               </java>
+        <!--move file="${gwt.www.dir}/${gwt.module}/${gwt.module.class}.html" tofile="${gwt.www.dir}/${gwt.module}/index.html"/-->
+       </target>
+       
+    <target name="package-war" depends="gwt-compile" description="Package up the web client as a war">
+        <jar destfile="${build.dir}/${dist.war}">
+            <zipfileset dir="${war.dir}"/>
+            <zipfileset dir="${gwt.www.dir}/${gwt.module}"/>
+        </jar>
+    </target>
+
+       <target name="clean" description="Delete all build artifacts">
+               <delete dir="${build.dir}"/>
+       </target>
+
+    <target name="distclean" depends="clean" description="Delete all downloaded dependencies">
+        <delete dir="${deps.dir}"/>
+    </target>
+
+    <target name="run-web-dev-mode" description="Run web client in development mode">
+        <java fork="true" classname="com.google.gwt.dev.DevMode" spawn="true">
+            <classpath>
+                <pathelement location="${src.dir}"/>
+                <pathelement location="${build.classes.dir}"/>
+                <pathelement path="${gwt.home}/gwt-dev.jar"/>
+                <pathelement location="${deps.dir}/${gwtquery.filename}"/>
+                <pathelement location="${deps.dir}/${gwtquery-draggable-plugin.filename}"/>
+                <pathelement location="${deps.dir}/${gwtquery-droppable-plugin.filename}"/>
+                <pathelement location="${deps.dir}/${gwtquery-commonui-plugin.filename}"/>
+                <pathelement location="${gwt-gears.home}/gwt-gears.jar"/>
+                <pathelement path="${gwt.home}/gwt-user.jar" />
+                <path refid="project.class.path"/>
+            </classpath>
+            <jvmarg value="-Xmx256M"/>
+            <jvmarg value="-Xdebug"/>
+            <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=55555"/>
+            <arg value="-war"/>
+            <arg value="${gwt.www.dir}/${gwt.module}"/>
+            <arg value="-startupUrl"/>
+            <arg value="GSS.html"/>
+            <arg value="${gwt.module}"/>
+        </java>
+    </target>
+</project>
diff --git a/src/com/google/gwt/user/cellview/client/GssSimplePager.java b/src/com/google/gwt/user/cellview/client/GssSimplePager.java
new file mode 100644 (file)
index 0000000..2457e71
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed 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 com.google.gwt.user.cellview.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.resources.client.ImageResource.ImageOptions;
+import com.google.gwt.uibinder.client.UiConstructor;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasVerticalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.view.client.HasRows;
+import com.google.gwt.view.client.Range;
+
+/**
+ * A pager for controlling a {@link HasRows} that only supports simple page
+ * navigation.
+ *
+ * <p>
+ * <h3>Example</h3>
+ * {@example com.google.gwt.examples.cellview.SimplePagerExample}
+ * </p>
+ */
+public class GssSimplePager extends AbstractPager {
+
+  /**
+   * A ClientBundle that provides images for this widget.
+   */
+  public static interface Resources extends ClientBundle {
+
+    /**
+     * The image used to skip ahead multiple pages.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerFastForward();
+
+    /**
+     * The disabled "fast forward" image.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerFastForwardDisabled();
+
+    /**
+     * The image used to go to the first page.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerFirstPage();
+
+    /**
+     * The disabled first page image.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerFirstPageDisabled();
+
+    /**
+     * The image used to go to the last page.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerLastPage();
+
+    /**
+     * The disabled last page image.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerLastPageDisabled();
+
+    /**
+     * The image used to go to the next page.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerNextPage();
+
+    /**
+     * The disabled next page image.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerNextPageDisabled();
+
+    /**
+     * The image used to go to the previous page.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerPreviousPage();
+
+    /**
+     * The disabled previous page image.
+     */
+    @ImageOptions(flipRtl = true)
+    ImageResource simplePagerPreviousPageDisabled();
+
+    /**
+     * The styles used in this widget.
+     */
+    @Source("SimplePager.css")
+    Style simplePagerStyle();
+  }
+
+  /**
+   * Styles used by this widget.
+   */
+  public static interface Style extends CssResource {
+
+    /**
+     * Applied to buttons.
+     */
+    String button();
+
+    /**
+     * Applied to disabled buttons.
+     */
+    String disabledButton();
+
+    /**
+     * Applied to the details text.
+     */
+    String pageDetails();
+  }
+
+  /**
+   * The location of the text relative to the paging buttons.
+   */
+  public static enum TextLocation {
+    CENTER, LEFT, RIGHT;
+  }
+
+  private static int DEFAULT_FAST_FORWARD_ROWS = 1000;
+  private static Resources DEFAULT_RESOURCES;
+
+  private static Resources getDefaultResources() {
+    if (DEFAULT_RESOURCES == null) {
+      DEFAULT_RESOURCES = GWT.create(Resources.class);
+    }
+    return DEFAULT_RESOURCES;
+  }
+
+  private final Image fastForward;
+
+  private final int fastForwardRows;
+
+  private final Image firstPage;
+
+  /**
+   * We use an {@link HTML} so we can embed the loading image.
+   */
+  private final HTML label = new HTML();
+
+  private final Image lastPage;
+
+  /**
+   * Set to true when the next and last buttons are disabled.
+   */
+  private boolean nextDisabled;
+
+  private final Image nextPage;
+
+  /**
+   * Set to true when the prev and first buttons are disabled.
+   */
+  private boolean prevDisabled;
+
+  private final Image prevPage;
+
+  /**
+   * The {@link Resources} used by this widget.
+   */
+  private final Resources resources;
+
+  /**
+   * The {@link Style} used by this widget.
+   */
+  private final Style style;
+
+  /**
+   * Construct a {@link GssSimplePager} with the default text location.
+   */
+  public GssSimplePager() {
+    this(TextLocation.CENTER);
+  }
+
+  /**
+   * Construct a {@link GssSimplePager} with the specified text location.
+   *
+   * @param location the location of the text relative to the buttons
+   */
+  @UiConstructor
+  // Hack for Google I/O demo
+  public GssSimplePager(TextLocation location) {
+    this(location, getDefaultResources(), false, DEFAULT_FAST_FORWARD_ROWS,
+        true);
+  }
+
+  /**
+   * Construct a {@link GssSimplePager} with the specified resources.
+   *
+   * @param location the location of the text relative to the buttons
+   * @param resources the {@link Resources} to use
+   * @param showFastForwardButton if true, show a fast-forward button that
+   *          advances by a larger increment than a single page
+   * @param fastForwardRows the number of rows to jump when fast forwarding
+   * @param showLastPageButton if true, show a button to go the the last page
+   */
+  public GssSimplePager(TextLocation location, Resources resources,
+      boolean showFastForwardButton, final int fastForwardRows,
+      boolean showLastPageButton) {
+    this.resources = resources;
+    this.fastForwardRows = fastForwardRows;
+    this.style = resources.simplePagerStyle();
+    this.style.ensureInjected();
+
+    // Create the buttons.
+    firstPage = new Image(resources.simplePagerFirstPage());
+    firstPage.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        firstPage();
+      }
+    });
+    nextPage = new Image(resources.simplePagerNextPage());
+    nextPage.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        nextPage();
+      }
+    });
+    prevPage = new Image(resources.simplePagerPreviousPage());
+    prevPage.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        previousPage();
+      }
+    });
+    if (showLastPageButton) {
+      lastPage = new Image(resources.simplePagerLastPage());
+      lastPage.addClickHandler(new ClickHandler() {
+        public void onClick(ClickEvent event) {
+          lastPage();
+        }
+      });
+    } else {
+      lastPage = null;
+    }
+    if (showFastForwardButton) {
+      fastForward = new Image(resources.simplePagerFastForward());
+      fastForward.addClickHandler(new ClickHandler() {
+        public void onClick(ClickEvent event) {
+          setPage(getPage() + getFastForwardPages());
+        }
+      });
+    } else {
+      fastForward = null;
+    }
+
+    // Construct the widget.
+    HorizontalPanel layout = new HorizontalPanel();
+    layout.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
+    initWidget(layout);
+    if (location == TextLocation.RIGHT) {
+      layout.add(label);
+    }
+    layout.add(firstPage);
+    layout.add(prevPage);
+    if (location == TextLocation.CENTER) {
+      layout.add(label);
+    }
+    layout.add(nextPage);
+    if (showFastForwardButton) {
+      layout.add(fastForward);
+    }
+    if (showLastPageButton) {
+      layout.add(lastPage);
+    }
+    if (location == TextLocation.LEFT) {
+      layout.add(label);
+    }
+
+    // Add style names to the cells.
+    firstPage.getElement().getParentElement().addClassName(style.button());
+    prevPage.getElement().getParentElement().addClassName(style.button());
+    label.getElement().getParentElement().addClassName(style.pageDetails());
+    nextPage.getElement().getParentElement().addClassName(style.button());
+    if (showFastForwardButton) {
+      fastForward.getElement().getParentElement().addClassName(style.button());
+    }
+    if (showLastPageButton) {
+      lastPage.getElement().getParentElement().addClassName(style.button());
+    }
+
+    // Disable the buttons by default.
+    setDisplay(null);
+  }
+
+  @Override
+  public void firstPage() {
+    super.firstPage();
+  }
+
+  @Override
+  public int getPage() {
+    return super.getPage();
+  }
+
+  @Override
+  public int getPageCount() {
+    return super.getPageCount();
+  }
+
+  @Override
+  public boolean hasNextPage() {
+    return super.hasNextPage();
+  }
+
+  @Override
+  public boolean hasNextPages(int pages) {
+    return super.hasNextPages(pages);
+  }
+
+  @Override
+  public boolean hasPage(int index) {
+    return super.hasPage(index);
+  }
+
+  @Override
+  public boolean hasPreviousPage() {
+    return super.hasPreviousPage();
+  }
+
+  @Override
+  public boolean hasPreviousPages(int pages) {
+    return super.hasPreviousPages(pages);
+  }
+
+  @Override
+  public void lastPage() {
+    super.lastPage();
+  }
+
+  @Override
+  public void lastPageStart() {
+    super.lastPageStart();
+  }
+
+  @Override
+  public void nextPage() {
+    super.nextPage();
+  }
+
+  @Override
+  public void previousPage() {
+    super.previousPage();
+  }
+
+  @Override
+  public void setDisplay(HasRows display) {
+    // Enable or disable all buttons.
+    boolean disableButtons = (display == null);
+    setFastForwardDisabled(disableButtons);
+    setNextPageButtonsDisabled(disableButtons);
+    setPrevPageButtonsDisabled(disableButtons);
+    super.setDisplay(display);
+  }
+
+  @Override
+  public void setPage(int index) {
+    super.setPage(index);
+  }
+
+  @Override
+  public void setPageSize(int pageSize) {
+    super.setPageSize(pageSize);
+  }
+
+  @Override
+  public void setPageStart(int index) {
+    super.setPageStart(index);
+  }
+
+  /**
+   * Let the page know that the table is loading. Call this method to clear all
+   * data from the table and hide the current range when new data is being
+   * loaded into the table.
+   */
+  public void startLoading() {
+    getDisplay().setRowCount(0, true);
+    label.setHTML("");
+  }
+
+  /**
+   * Get the text to display in the pager that reflects the state of the pager.
+   *
+   * @return the text
+   */
+  protected String createText() {
+    // Default text is 1 based.
+    NumberFormat formatter = NumberFormat.getFormat("#,###");
+    HasRows display = getDisplay();
+    Range range = display.getVisibleRange();
+    int pageStart = range.getStart() + 1;
+    int pageSize = range.getLength();
+    int dataSize = display.getRowCount();
+    int endIndex = Math.min(dataSize, pageStart + pageSize - 1);
+    endIndex = Math.max(pageStart, endIndex);
+    boolean exact = display.isRowCountExact();
+    return formatter.format(pageStart) + "-" + formatter.format(endIndex)
+        + (exact ? " of " : " of over ") + formatter.format(dataSize);
+  }
+
+  @Override
+  protected void onRangeOrRowCountChanged() {
+    HasRows display = getDisplay();
+    label.setText(createText());
+
+    // Update the prev and first buttons.
+    setPrevPageButtonsDisabled(!hasPreviousPage());
+
+    // Update the next and last buttons.
+    if (isRangeLimited() || !display.isRowCountExact()) {
+      setNextPageButtonsDisabled(!hasNextPage());
+      setFastForwardDisabled(!hasNextPages(getFastForwardPages()));
+    }
+  }
+
+  /**
+   * Check if the next button is disabled. Visible for testing.
+   */
+  boolean isNextButtonDisabled() {
+    return nextDisabled;
+  }
+
+  /**
+   * Check if the previous button is disabled. Visible for testing.
+   */
+  boolean isPreviousButtonDisabled() {
+    return prevDisabled;
+  }
+
+  /**
+   * Get the number of pages to fast forward based on the current page size.
+   *
+   * @return the number of pages to fast forward
+   */
+  private int getFastForwardPages() {
+    int pageSize = getPageSize();
+    return pageSize > 0 ? fastForwardRows / pageSize : 0;
+  }
+
+  /**
+   * Enable or disable the fast forward button.
+   *
+   * @param disabled true to disable, false to enable
+   */
+  private void setFastForwardDisabled(boolean disabled) {
+    if (fastForward == null) {
+      return;
+    }
+    if (disabled) {
+      fastForward.setResource(resources.simplePagerFastForwardDisabled());
+      fastForward.getElement().getParentElement().addClassName(
+          style.disabledButton());
+    } else {
+      fastForward.setResource(resources.simplePagerFastForward());
+      fastForward.getElement().getParentElement().removeClassName(
+          style.disabledButton());
+    }
+  }
+
+  /**
+   * Enable or disable the next page buttons.
+   *
+   * @param disabled true to disable, false to enable
+   */
+  private void setNextPageButtonsDisabled(boolean disabled) {
+    if (disabled == nextDisabled) {
+      return;
+    }
+
+    nextDisabled = disabled;
+    if (disabled) {
+      nextPage.setResource(resources.simplePagerNextPageDisabled());
+      nextPage.getElement().getParentElement().addClassName(
+          style.disabledButton());
+      if (lastPage != null) {
+        lastPage.setResource(resources.simplePagerLastPageDisabled());
+        lastPage.getElement().getParentElement().addClassName(
+            style.disabledButton());
+      }
+    } else {
+      nextPage.setResource(resources.simplePagerNextPage());
+      nextPage.getElement().getParentElement().removeClassName(
+          style.disabledButton());
+      if (lastPage != null) {
+        lastPage.setResource(resources.simplePagerLastPage());
+        lastPage.getElement().getParentElement().removeClassName(
+            style.disabledButton());
+      }
+    }
+  }
+
+  /**
+   * Enable or disable the previous page buttons.
+   *
+   * @param disabled true to disable, false to enable
+   */
+  private void setPrevPageButtonsDisabled(boolean disabled) {
+    if (disabled == prevDisabled) {
+      return;
+    }
+
+    prevDisabled = disabled;
+    if (disabled) {
+      firstPage.setResource(resources.simplePagerFirstPageDisabled());
+      firstPage.getElement().getParentElement().addClassName(
+          style.disabledButton());
+      prevPage.setResource(resources.simplePagerPreviousPageDisabled());
+      prevPage.getElement().getParentElement().addClassName(
+          style.disabledButton());
+    } else {
+      firstPage.setResource(resources.simplePagerFirstPage());
+      firstPage.getElement().getParentElement().removeClassName(
+          style.disabledButton());
+      prevPage.setResource(resources.simplePagerPreviousPage());
+      prevPage.getElement().getParentElement().removeClassName(
+          style.disabledButton());
+    }
+  }
+}
diff --git a/src/org/gss_project/gss/resources/advancedsettings.png b/src/org/gss_project/gss/resources/advancedsettings.png
new file mode 100644 (file)
index 0000000..0c9faff
Binary files /dev/null and b/src/org/gss_project/gss/resources/advancedsettings.png differ
diff --git a/src/org/gss_project/gss/resources/ajax-loader.gif b/src/org/gss_project/gss/resources/ajax-loader.gif
new file mode 100644 (file)
index 0000000..3288d10
Binary files /dev/null and b/src/org/gss_project/gss/resources/ajax-loader.gif differ
diff --git a/src/org/gss_project/gss/resources/asc.png b/src/org/gss_project/gss/resources/asc.png
new file mode 100644 (file)
index 0000000..e5586cd
Binary files /dev/null and b/src/org/gss_project/gss/resources/asc.png differ
diff --git a/src/org/gss_project/gss/resources/bell.png b/src/org/gss_project/gss/resources/bell.png
new file mode 100644 (file)
index 0000000..7a3fcae
Binary files /dev/null and b/src/org/gss_project/gss/resources/bell.png differ
diff --git a/src/org/gss_project/gss/resources/blank.gif b/src/org/gss_project/gss/resources/blank.gif
new file mode 100644 (file)
index 0000000..e8f26b0
Binary files /dev/null and b/src/org/gss_project/gss/resources/blank.gif differ
diff --git a/src/org/gss_project/gss/resources/border_remove.png b/src/org/gss_project/gss/resources/border_remove.png
new file mode 100644 (file)
index 0000000..b2305be
Binary files /dev/null and b/src/org/gss_project/gss/resources/border_remove.png differ
diff --git a/src/org/gss_project/gss/resources/bug.png b/src/org/gss_project/gss/resources/bug.png
new file mode 100755 (executable)
index 0000000..719983c
Binary files /dev/null and b/src/org/gss_project/gss/resources/bug.png differ
diff --git a/src/org/gss_project/gss/resources/configure.png b/src/org/gss_project/gss/resources/configure.png
new file mode 100644 (file)
index 0000000..7bb010a
Binary files /dev/null and b/src/org/gss_project/gss/resources/configure.png differ
diff --git a/src/org/gss_project/gss/resources/database.png b/src/org/gss_project/gss/resources/database.png
new file mode 100644 (file)
index 0000000..ee17b38
Binary files /dev/null and b/src/org/gss_project/gss/resources/database.png differ
diff --git a/src/org/gss_project/gss/resources/db_update.png b/src/org/gss_project/gss/resources/db_update.png
new file mode 100644 (file)
index 0000000..a003024
Binary files /dev/null and b/src/org/gss_project/gss/resources/db_update.png differ
diff --git a/src/org/gss_project/gss/resources/demo.png b/src/org/gss_project/gss/resources/demo.png
new file mode 100644 (file)
index 0000000..4d40262
Binary files /dev/null and b/src/org/gss_project/gss/resources/demo.png differ
diff --git a/src/org/gss_project/gss/resources/desc.png b/src/org/gss_project/gss/resources/desc.png
new file mode 100644 (file)
index 0000000..0ba4c05
Binary files /dev/null and b/src/org/gss_project/gss/resources/desc.png differ
diff --git a/src/org/gss_project/gss/resources/doc_versions.png b/src/org/gss_project/gss/resources/doc_versions.png
new file mode 100644 (file)
index 0000000..504572a
Binary files /dev/null and b/src/org/gss_project/gss/resources/doc_versions.png differ
diff --git a/src/org/gss_project/gss/resources/document.png b/src/org/gss_project/gss/resources/document.png
new file mode 100644 (file)
index 0000000..9e45538
Binary files /dev/null and b/src/org/gss_project/gss/resources/document.png differ
diff --git a/src/org/gss_project/gss/resources/edit.png b/src/org/gss_project/gss/resources/edit.png
new file mode 100644 (file)
index 0000000..4993ee4
Binary files /dev/null and b/src/org/gss_project/gss/resources/edit.png differ
diff --git a/src/org/gss_project/gss/resources/edit_add.png b/src/org/gss_project/gss/resources/edit_add.png
new file mode 100755 (executable)
index 0000000..269aaa6
Binary files /dev/null and b/src/org/gss_project/gss/resources/edit_add.png differ
diff --git a/src/org/gss_project/gss/resources/edit_group.png b/src/org/gss_project/gss/resources/edit_group.png
new file mode 100644 (file)
index 0000000..ee168fa
Binary files /dev/null and b/src/org/gss_project/gss/resources/edit_group.png differ
diff --git a/src/org/gss_project/gss/resources/edit_group_22.png b/src/org/gss_project/gss/resources/edit_group_22.png
new file mode 100644 (file)
index 0000000..b3edf94
Binary files /dev/null and b/src/org/gss_project/gss/resources/edit_group_22.png differ
diff --git a/src/org/gss_project/gss/resources/edit_user.png b/src/org/gss_project/gss/resources/edit_user.png
new file mode 100644 (file)
index 0000000..6327038
Binary files /dev/null and b/src/org/gss_project/gss/resources/edit_user.png differ
diff --git a/src/org/gss_project/gss/resources/editcopy.png b/src/org/gss_project/gss/resources/editcopy.png
new file mode 100644 (file)
index 0000000..8a227f8
Binary files /dev/null and b/src/org/gss_project/gss/resources/editcopy.png differ
diff --git a/src/org/gss_project/gss/resources/editcut.png b/src/org/gss_project/gss/resources/editcut.png
new file mode 100644 (file)
index 0000000..edd1844
Binary files /dev/null and b/src/org/gss_project/gss/resources/editcut.png differ
diff --git a/src/org/gss_project/gss/resources/editdelete.png b/src/org/gss_project/gss/resources/editdelete.png
new file mode 100644 (file)
index 0000000..64d3651
Binary files /dev/null and b/src/org/gss_project/gss/resources/editdelete.png differ
diff --git a/src/org/gss_project/gss/resources/editpaste.png b/src/org/gss_project/gss/resources/editpaste.png
new file mode 100644 (file)
index 0000000..06ea9df
Binary files /dev/null and b/src/org/gss_project/gss/resources/editpaste.png differ
diff --git a/src/org/gss_project/gss/resources/exit.png b/src/org/gss_project/gss/resources/exit.png
new file mode 100644 (file)
index 0000000..609d4d8
Binary files /dev/null and b/src/org/gss_project/gss/resources/exit.png differ
diff --git a/src/org/gss_project/gss/resources/folder_blue.png b/src/org/gss_project/gss/resources/folder_blue.png
new file mode 100644 (file)
index 0000000..1419285
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_blue.png differ
diff --git a/src/org/gss_project/gss/resources/folder_green.png b/src/org/gss_project/gss/resources/folder_green.png
new file mode 100644 (file)
index 0000000..e287ad8
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_green.png differ
diff --git a/src/org/gss_project/gss/resources/folder_home.png b/src/org/gss_project/gss/resources/folder_home.png
new file mode 100644 (file)
index 0000000..ec6e75f
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_home.png differ
diff --git a/src/org/gss_project/gss/resources/folder_inbox.png b/src/org/gss_project/gss/resources/folder_inbox.png
new file mode 100644 (file)
index 0000000..cafac61
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_inbox.png differ
diff --git a/src/org/gss_project/gss/resources/folder_new.png b/src/org/gss_project/gss/resources/folder_new.png
new file mode 100644 (file)
index 0000000..130e35e
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_new.png differ
diff --git a/src/org/gss_project/gss/resources/folder_outbox.png b/src/org/gss_project/gss/resources/folder_outbox.png
new file mode 100644 (file)
index 0000000..91e3b24
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_outbox.png differ
diff --git a/src/org/gss_project/gss/resources/folder_user.png b/src/org/gss_project/gss/resources/folder_user.png
new file mode 100644 (file)
index 0000000..f021c3e
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_user.png differ
diff --git a/src/org/gss_project/gss/resources/folder_yellow.png b/src/org/gss_project/gss/resources/folder_yellow.png
new file mode 100644 (file)
index 0000000..659133c
Binary files /dev/null and b/src/org/gss_project/gss/resources/folder_yellow.png differ
diff --git a/src/org/gss_project/gss/resources/greenled.png b/src/org/gss_project/gss/resources/greenled.png
new file mode 100644 (file)
index 0000000..ac8972e
Binary files /dev/null and b/src/org/gss_project/gss/resources/greenled.png differ
diff --git a/src/org/gss_project/gss/resources/grnet-logo.png b/src/org/gss_project/gss/resources/grnet-logo.png
new file mode 100644 (file)
index 0000000..65a4110
Binary files /dev/null and b/src/org/gss_project/gss/resources/grnet-logo.png differ
diff --git a/src/org/gss_project/gss/resources/group.png b/src/org/gss_project/gss/resources/group.png
new file mode 100644 (file)
index 0000000..6fb8288
Binary files /dev/null and b/src/org/gss_project/gss/resources/group.png differ
diff --git a/src/org/gss_project/gss/resources/groupevent.png b/src/org/gss_project/gss/resources/groupevent.png
new file mode 100644 (file)
index 0000000..31b6f33
Binary files /dev/null and b/src/org/gss_project/gss/resources/groupevent.png differ
diff --git a/src/org/gss_project/gss/resources/help.png b/src/org/gss_project/gss/resources/help.png
new file mode 100644 (file)
index 0000000..5858f03
Binary files /dev/null and b/src/org/gss_project/gss/resources/help.png differ
diff --git a/src/org/gss_project/gss/resources/info.png b/src/org/gss_project/gss/resources/info.png
new file mode 100644 (file)
index 0000000..de189bd
Binary files /dev/null and b/src/org/gss_project/gss/resources/info.png differ
diff --git a/src/org/gss_project/gss/resources/internet.png b/src/org/gss_project/gss/resources/internet.png
new file mode 100644 (file)
index 0000000..9b67db4
Binary files /dev/null and b/src/org/gss_project/gss/resources/internet.png differ
diff --git a/src/org/gss_project/gss/resources/khelpcenter.png b/src/org/gss_project/gss/resources/khelpcenter.png
new file mode 100644 (file)
index 0000000..12cbcd2
Binary files /dev/null and b/src/org/gss_project/gss/resources/khelpcenter.png differ
diff --git a/src/org/gss_project/gss/resources/linewidth.png b/src/org/gss_project/gss/resources/linewidth.png
new file mode 100644 (file)
index 0000000..4e84b0c
Binary files /dev/null and b/src/org/gss_project/gss/resources/linewidth.png differ
diff --git a/src/org/gss_project/gss/resources/lock.png b/src/org/gss_project/gss/resources/lock.png
new file mode 100644 (file)
index 0000000..5294896
Binary files /dev/null and b/src/org/gss_project/gss/resources/lock.png differ
diff --git a/src/org/gss_project/gss/resources/messagebox_critical.png b/src/org/gss_project/gss/resources/messagebox_critical.png
new file mode 100644 (file)
index 0000000..1de7a6f
Binary files /dev/null and b/src/org/gss_project/gss/resources/messagebox_critical.png differ
diff --git a/src/org/gss_project/gss/resources/messagebox_info.png b/src/org/gss_project/gss/resources/messagebox_info.png
new file mode 100644 (file)
index 0000000..96642db
Binary files /dev/null and b/src/org/gss_project/gss/resources/messagebox_info.png differ
diff --git a/src/org/gss_project/gss/resources/messagebox_warning.png b/src/org/gss_project/gss/resources/messagebox_warning.png
new file mode 100644 (file)
index 0000000..d83f349
Binary files /dev/null and b/src/org/gss_project/gss/resources/messagebox_warning.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/acroread.png b/src/org/gss_project/gss/resources/mimetypes/acroread.png
new file mode 100644 (file)
index 0000000..a0e057f
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/acroread.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/acroread_shared.png b/src/org/gss_project/gss/resources/mimetypes/acroread_shared.png
new file mode 100644 (file)
index 0000000..c67b8c2
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/acroread_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/ark2.png b/src/org/gss_project/gss/resources/mimetypes/ark2.png
new file mode 100644 (file)
index 0000000..184f959
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/ark2.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/ark2_shared.png b/src/org/gss_project/gss/resources/mimetypes/ark2_shared.png
new file mode 100644 (file)
index 0000000..26496df
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/ark2_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/document.png b/src/org/gss_project/gss/resources/mimetypes/document.png
new file mode 100644 (file)
index 0000000..bfe1d06
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/document.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/document_shared.png b/src/org/gss_project/gss/resources/mimetypes/document_shared.png
new file mode 100644 (file)
index 0000000..d59243b
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/document_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/html.png b/src/org/gss_project/gss/resources/mimetypes/html.png
new file mode 100644 (file)
index 0000000..2a0e4b3
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/html.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/html_shared.png b/src/org/gss_project/gss/resources/mimetypes/html_shared.png
new file mode 100644 (file)
index 0000000..1442a6a
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/html_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/image.png b/src/org/gss_project/gss/resources/mimetypes/image.png
new file mode 100644 (file)
index 0000000..c3944a2
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/image.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/image_shared.png b/src/org/gss_project/gss/resources/mimetypes/image_shared.png
new file mode 100644 (file)
index 0000000..ca874f1
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/image_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/kcmfontinst.png b/src/org/gss_project/gss/resources/mimetypes/kcmfontinst.png
new file mode 100644 (file)
index 0000000..267a732
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/kcmfontinst.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/kcmfontinst_shared.png b/src/org/gss_project/gss/resources/mimetypes/kcmfontinst_shared.png
new file mode 100644 (file)
index 0000000..3121689
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/kcmfontinst_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/knotify.png b/src/org/gss_project/gss/resources/mimetypes/knotify.png
new file mode 100644 (file)
index 0000000..c4e85b4
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/knotify.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/knotify_shared.png b/src/org/gss_project/gss/resources/mimetypes/knotify_shared.png
new file mode 100644 (file)
index 0000000..f6737ca
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/knotify_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr.png b/src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr.png
new file mode 100644 (file)
index 0000000..9b9a483
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr_shared.png b/src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr_shared.png
new file mode 100644 (file)
index 0000000..0dd8eeb
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/kpresenter_kpr_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/log.png b/src/org/gss_project/gss/resources/mimetypes/log.png
new file mode 100644 (file)
index 0000000..90928f5
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/log.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/log_shared.png b/src/org/gss_project/gss/resources/mimetypes/log_shared.png
new file mode 100644 (file)
index 0000000..548e79a
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/log_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/txt.png b/src/org/gss_project/gss/resources/mimetypes/txt.png
new file mode 100644 (file)
index 0000000..870f1ab
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/txt.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/txt_shared.png b/src/org/gss_project/gss/resources/mimetypes/txt_shared.png
new file mode 100644 (file)
index 0000000..9d8454c
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/txt_shared.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/video2.png b/src/org/gss_project/gss/resources/mimetypes/video2.png
new file mode 100644 (file)
index 0000000..0a26d45
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/video2.png differ
diff --git a/src/org/gss_project/gss/resources/mimetypes/video2_shared.png b/src/org/gss_project/gss/resources/mimetypes/video2_shared.png
new file mode 100644 (file)
index 0000000..704b032
Binary files /dev/null and b/src/org/gss_project/gss/resources/mimetypes/video2_shared.png differ
diff --git a/src/org/gss_project/gss/resources/pithos-logo.png b/src/org/gss_project/gss/resources/pithos-logo.png
new file mode 100644 (file)
index 0000000..e3dc565
Binary files /dev/null and b/src/org/gss_project/gss/resources/pithos-logo.png differ
diff --git a/src/org/gss_project/gss/resources/redled.png b/src/org/gss_project/gss/resources/redled.png
new file mode 100644 (file)
index 0000000..afa4772
Binary files /dev/null and b/src/org/gss_project/gss/resources/redled.png differ
diff --git a/src/org/gss_project/gss/resources/refresh.png b/src/org/gss_project/gss/resources/refresh.png
new file mode 100644 (file)
index 0000000..71d1df7
Binary files /dev/null and b/src/org/gss_project/gss/resources/refresh.png differ
diff --git a/src/org/gss_project/gss/resources/refresh2.png b/src/org/gss_project/gss/resources/refresh2.png
new file mode 100644 (file)
index 0000000..018a93f
Binary files /dev/null and b/src/org/gss_project/gss/resources/refresh2.png differ
diff --git a/src/org/gss_project/gss/resources/search.png b/src/org/gss_project/gss/resources/search.png
new file mode 100644 (file)
index 0000000..4f880ab
Binary files /dev/null and b/src/org/gss_project/gss/resources/search.png differ
diff --git a/src/org/gss_project/gss/resources/search_16.png b/src/org/gss_project/gss/resources/search_16.png
new file mode 100644 (file)
index 0000000..593a566
Binary files /dev/null and b/src/org/gss_project/gss/resources/search_16.png differ
diff --git a/src/org/gss_project/gss/resources/translate.png b/src/org/gss_project/gss/resources/translate.png
new file mode 100644 (file)
index 0000000..2d839cb
Binary files /dev/null and b/src/org/gss_project/gss/resources/translate.png differ
diff --git a/src/org/gss_project/gss/resources/trashcan_empty.png b/src/org/gss_project/gss/resources/trashcan_empty.png
new file mode 100644 (file)
index 0000000..53d39f6
Binary files /dev/null and b/src/org/gss_project/gss/resources/trashcan_empty.png differ
diff --git a/src/org/gss_project/gss/resources/view_text.png b/src/org/gss_project/gss/resources/view_text.png
new file mode 100644 (file)
index 0000000..8d0d849
Binary files /dev/null and b/src/org/gss_project/gss/resources/view_text.png differ
diff --git a/src/org/gss_project/gss/resources/windowlist.png b/src/org/gss_project/gss/resources/windowlist.png
new file mode 100644 (file)
index 0000000..9f0104a
Binary files /dev/null and b/src/org/gss_project/gss/resources/windowlist.png differ
diff --git a/src/org/gss_project/gss/resources/xclock.png b/src/org/gss_project/gss/resources/xclock.png
new file mode 100755 (executable)
index 0000000..31e66e4
Binary files /dev/null and b/src/org/gss_project/gss/resources/xclock.png differ
diff --git a/src/org/gss_project/gss/resources/yellowled.png b/src/org/gss_project/gss/resources/yellowled.png
new file mode 100644 (file)
index 0000000..b09507d
Binary files /dev/null and b/src/org/gss_project/gss/resources/yellowled.png differ
diff --git a/src/org/gss_project/gss/web/GSS.gwt.xml b/src/org/gss_project/gss/web/GSS.gwt.xml
new file mode 100644 (file)
index 0000000..71eb617
--- /dev/null
@@ -0,0 +1,36 @@
+<module>
+       <inherits name="com.google.gwt.user.User"/>
+    <inherits name="com.google.gwt.user.theme.standard.Standard"/>
+       <inherits name="com.google.gwt.gears.Gears"/>
+       <inherits name="com.google.gwt.http.HTTP"/>
+       <inherits name="com.google.gwt.json.JSON"/>
+       <inherits name="gwtquery.plugins.droppable.Droppable"/>
+
+    <entry-point class='org.gss_project.gss.web.client.GSS' />
+       <stylesheet src='gss.css' />
+
+       <!-- Rebind the file upload dialog if Gears is installed -->
+       <replace-with class="org.gss_project.gss.web.client.FileUploadGearsDialog">
+               <all>
+                       <when-type-is class="org.gss_project.gss.web.client.FileUploadDialog"/>
+                       <when-property-is name="gears.installed" value="true"/>
+                       <none>
+                               <when-property-is name="user.agent" value="ie6"/>
+                               <when-property-is name="user.agent" value="ie8"/>
+                       </none>
+               </all>
+       </replace-with>   
+       <!-- Use a special file upload dialog if Gears is installed on IE -->
+       <replace-with class="org.gss_project.gss.web.client.FileUploadGearsIEDialog">
+               <all>
+                       <when-type-is class="org.gss_project.gss.web.client.FileUploadDialog"/>
+                       <when-property-is name="gears.installed" value="true"/>
+                       <any>
+                               <when-property-is name="user.agent" value="ie6"/>
+                               <when-property-is name="user.agent" value="ie8"/>
+                       </any>
+               </all>
+       </replace-with>
+    
+       <source path="client"/>
+</module>
diff --git a/src/org/gss_project/gss/web/client/AboutDialog.java b/src/org/gss_project/gss/web/client/AboutDialog.java
new file mode 100644 (file)
index 0000000..c03ff04
--- /dev/null
@@ -0,0 +1,89 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.user.client.Event.NativePreviewEvent;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.DialogBox;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'about' dialog box.\r
+ */\r
+public class AboutDialog extends DialogBox {\r
+\r
+       /**\r
+        * The widget constructor.\r
+        */\r
+       public AboutDialog() {\r
+               // Set the dialog's caption.\r
+               Configuration conf = (Configuration) GWT.create(Configuration.class);\r
+               String service = conf.serviceName();\r
+               setText("About " + service);\r
+               setAnimationEnabled(true);\r
+               // A VerticalPanel that contains the 'about' label and the 'OK' button.\r
+               final VerticalPanel outer = new VerticalPanel();\r
+\r
+               // Create the 'about' text and set the style.\r
+               final HTML text = new HTML("This is the Web client for the " + service +\r
+                                       " service. You can use it to store, retrieve and share " +\r
+                                       "files in the " + service + " server grid. <p>Pithos version: " +\r
+                                       conf.version() + "<br> A GRNET service designed and implemented by " + "<a href='http://www.grnet.gr'>GRNET</a>" + " and " +\r
+                                       "<a href='http://www.ebs.gr' target='about'>EBS</a></p>");\r
+               text.setStyleName("gss-AboutText");\r
+               outer.add(text);\r
+\r
+               // Create the 'OK' button, along with a listener that hides the dialog\r
+               // when the button is clicked.\r
+               final Button confirm = new Button("Close", new ClickHandler() {\r
+\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               hide();\r
+                       }\r
+               });\r
+               outer.add(confirm);\r
+               outer.setCellHorizontalAlignment(confirm, HasHorizontalAlignment.ALIGN_CENTER);\r
+               outer.setSpacing(8);\r
+               setWidget(outer);\r
+       }\r
+\r
+       @Override\r
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
+               super.onPreviewNativeEvent(preview);\r
+               NativeEvent evt = preview.getNativeEvent();\r
+               if (evt.getType().equals("keydown"))\r
+                       // Use the popup's key preview hooks to close the dialog when\r
+                       // either enter or escape is pressed.\r
+                       switch (evt.getKeyCode()) {\r
+                               case KeyCodes.KEY_ENTER:\r
+                               case KeyCodes.KEY_ESCAPE:\r
+                                       hide();\r
+                                       break;\r
+                       }\r
+       }\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/AbstractPropertiesDialog.java b/src/org/gss_project/gss/web/client/AbstractPropertiesDialog.java
new file mode 100644 (file)
index 0000000..d89ef2c
--- /dev/null
@@ -0,0 +1,165 @@
+/*\r
+ * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.rest.GetCommand;\r
+import org.gss_project.gss.web.client.rest.resource.TagsResource;\r
+\r
+import java.util.List;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.Event.NativePreviewEvent;\r
+import com.google.gwt.user.client.ui.Anchor;\r
+import com.google.gwt.user.client.ui.DialogBox;\r
+import com.google.gwt.user.client.ui.FlowPanel;\r
+import com.google.gwt.user.client.ui.Label;\r
+import com.google.gwt.user.client.ui.TabPanel;\r
+import com.google.gwt.user.client.ui.TextBox;\r
+\r
+/**\r
+ * Abstract class, parent of all 'File properties' dialog boxes.\r
+ *\r
+ * @author droutsis\r
+ */\r
+public abstract class AbstractPropertiesDialog extends DialogBox {\r
+\r
+       protected static final String MULTIPLE_VALUES_TEXT = "(Multiple values)";\r
+\r
+       /**\r
+        * Text box with the tags associated with the file\r
+        */\r
+       protected TextBox tags = new TextBox();\r
+\r
+       protected String initialTagText;\r
+\r
+       /**\r
+        * A FlowPanel with all user tags\r
+        */\r
+       protected FlowPanel allTagsContent;\r
+\r
+\r
+       protected TabPanel inner = null;\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        *\r
+        */\r
+       public AbstractPropertiesDialog() {\r
+\r
+               // Enable IE selection for the dialog (must disable it upon closing it)\r
+               GSS.enableIESelection();\r
+\r
+               setAnimationEnabled(true);\r
+\r
+       }\r
+       /**\r
+        * Retrieves all user tags from the server and updates the FlowPanel\r
+        *\r
+        * @param userId\r
+        */\r
+       protected void updateTags() {\r
+               GetCommand<TagsResource> tc = new GetCommand<TagsResource>(TagsResource.class, GSS.get().getCurrentUserResource().getTagsPath(),null) {\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               allTagsContent.clear();\r
+                               TagsResource tagr = getResult();\r
+                               List<String> userTags = tagr.getTags();\r
+                               Anchor tag = null;\r
+                               for(String usrTag : userTags){\r
+                                       tag = new Anchor(usrTag.toString(), false);\r
+                                       tag.addStyleName("gss-tag");\r
+                                       allTagsContent.add(tag);\r
+                                       Label separator = new Label(", ");\r
+                                       separator.addStyleName("gss-tag");\r
+                                       allTagsContent.add(separator);\r
+                                       tag.addClickHandler( new ClickHandler() {\r
+\r
+                                               @Override\r
+                                               public void onClick(ClickEvent event) {\r
+                                                       String existing = tags.getText();\r
+                                                       if (MULTIPLE_VALUES_TEXT.equals(existing)) existing = "";\r
+                                                       String newTag = ((Anchor) event.getSource()).getText().trim();\r
+                                                       // insert the new tag only if it is not in the list\r
+                                                       // already\r
+                                                       if (existing.indexOf(newTag) == -1 && !existing.trim().endsWith(newTag))\r
+                                                               tags.setText(existing.trim()\r
+                                                                                       + (existing.length() > 0 ? ", " : "")\r
+                                                                                       + newTag);\r
+                                               }\r
+                                       });\r
+                               }\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               GSS.get().displayError("Unable to fetch user tags");\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(tc);\r
+\r
+       }\r
+\r
+       /**\r
+        * Accepts any change and updates the file\r
+        *\r
+        */\r
+       protected abstract void accept();\r
+\r
+       @Override\r
+       @SuppressWarnings("fallthrough")\r
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
+           super.onPreviewNativeEvent(preview);\r
+\r
+           NativeEvent evt = preview.getNativeEvent();\r
+           if (evt.getType().equals("keydown"))\r
+                       // Use the popup's key preview hooks to close the dialog when either\r
+                         // enter or escape is pressed.\r
+                         switch (evt.getKeyCode()) {\r
+                           case KeyCodes.KEY_ENTER:\r
+                               accept();\r
+                           case KeyCodes.KEY_ESCAPE:\r
+                             closeDialog();\r
+                             break;\r
+                         }\r
+         }\r
+\r
+\r
+\r
+       public void selectTab(int _tab) {\r
+               inner.selectTab(_tab);\r
+       }\r
+\r
+\r
+       /**\r
+        * Enables IE selection prevention and hides the dialog\r
+        * (we disable the prevention on creation of the dialog)\r
+        */\r
+       public void closeDialog() {\r
+               GSS.preventIESelection();\r
+               hide();\r
+       }\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/CellTreeView.java b/src/org/gss_project/gss/web/client/CellTreeView.java
new file mode 100644 (file)
index 0000000..c641b23
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.CellTreeViewModel.ClearSelection;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.MyFolderResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.OthersFolderResource;
+import org.gss_project.gss.web.client.rest.resource.OthersResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import gwtquery.plugins.droppable.client.gwt.DragAndDropCellTree;
+
+import java.util.Arrays;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.resources.client.ImageResource.ImageOptions;
+import com.google.gwt.user.cellview.client.CellTree;
+import com.google.gwt.user.cellview.client.TreeNode;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.IncrementalCommand;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.view.client.ProvidesKey;
+import com.google.gwt.view.client.SelectionChangeEvent;
+import com.google.gwt.view.client.SingleSelectionModel;
+import com.google.gwt.view.client.TreeViewModel;
+import com.google.gwt.view.client.SelectionChangeEvent.Handler;
+import com.google.gwt.view.client.TreeViewModel.NodeInfo;
+
+
+/**
+ * @author kman
+ *
+ */
+public class CellTreeView extends Composite{
+       public static final boolean DONE = false;
+       Images images;
+       
+       SingleSelectionModel<RestResource> selectionModel = new SingleSelectionModel<RestResource>(new ProvidesKey<RestResource>() {
+
+               @Override
+               public Object getKey(RestResource item) {
+                       return item.getClass().getName()+":"+item.getUri();
+               }});
+       FolderContextMenu menu;
+       
+       
+       MyFolderResource myFolders=null;
+       TrashResource trash = null;
+       SharedResource myshared = null;
+       OthersResource others = null;
+       
+       CellTreeViewModel model;
+       CellTreeViewUtils utils;
+       
+       public interface Images extends ClientBundle,Tree.Resources, FolderContextMenu.Images {
+
+        @Source("org/gss_project/gss/resources/folder_home.png")
+        ImageResource home();
+
+        @Source("org/gss_project/gss/resources/folder_yellow.png")
+        ImageResource folderYellow();
+
+        @Source("org/gss_project/gss/resources/mimetypes/document.png")
+        ImageResource document();
+
+        @Source("org/gss_project/gss/resources/internet.png")
+        ImageResource othersShared();
+
+        @Source("org/gss_project/gss/resources/edit_user.png")
+        ImageResource myShared();
+
+        @Source("org/gss_project/gss/resources/folder_user.png")
+        ImageResource sharedFolder();
+
+        @Source("org/gss_project/gss/resources/trashcan_empty.png")
+        ImageResource trash();
+       }
+       DragAndDropCellTree tree;
+       /*public interface BasicResources extends CellTree.BasicResources{
+               @ImageOptions(flipRtl = true)
+           @Source("cellTreeLoadingBasic.gif")
+           ImageResource cellTreeLoading();
+               
+               @Source({"GssCellTreeBasic.css"})
+           CellTree.Style cellTreeStyle();
+       }*/
+       public interface BasicResources extends CellTree.Resources {
+
+           @ImageOptions(flipRtl = true)
+           @Source("cellTreeClosedItem.gif")
+           ImageResource cellTreeClosedItem();
+
+           @ImageOptions(flipRtl = true)
+           @Source("cellTreeLoadingBasic.gif")
+           ImageResource cellTreeLoading();
+
+           @ImageOptions(flipRtl = true)
+           @Source("cellTreeOpenItem.gif")
+           ImageResource cellTreeOpenItem();
+
+           //@Source({CellTree.Style.DEFAULT_CSS,"GssCellTreeBasic.css"})
+           @Source({"GssCellTreeBasic.css"})
+           CellTree.Style cellTreeStyle();
+         }
+       /**
+        * 
+        */
+       public CellTreeView(final Images _images) {
+               images = _images;
+               model = new CellTreeViewModel(images,selectionModel);
+           /*
+            * Create the tree using the model. We use <code>null</code> as the default
+            * value of the root node. The default value will be passed to
+            * CustomTreeModel#getNodeInfo();
+            */
+               CellTree.Resources res = GWT.create(BasicResources.class);
+           tree = new DragAndDropCellTree(model,null, res){
+               @Override
+               public void onBrowserEvent(Event event) {
+                       // TODO Auto-generated method stub
+                       super.onBrowserEvent(event);
+               }
+           };
+           utils=new CellTreeViewUtils(tree);
+           tree.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+           /*tree.addOpenHandler(new OpenHandler<TreeNode>() {
+                       
+                       @Override
+                       public void onOpen(OpenEvent<TreeNode> event) {
+                               Window.alert("[NODE OPENED]"+event.getTarget());
+                               
+                       }
+               });
+           tree.addOverDroppableHandler(new OverDroppableEventHandler() {
+                       
+                       @Override
+                       public void onOverDroppable(OverDroppableEvent event) {
+                               GWT.log("OVER:"+event);
+                               
+                       }
+               });
+           tree.addAttachHandler(new AttachEvent.Handler() {
+                       
+                       @Override
+                       public void onAttachOrDetach(AttachEvent event) {
+                               GWT.log("ATTACH:"+event.getSource());
+                               
+                       }
+               });*/
+           Handler selectionHandler = new SelectionChangeEvent.Handler() { 
+            @Override 
+            public void onSelectionChange(com.google.gwt.view.client.SelectionChangeEvent event) {
+               NodeInfo<RestResource> nodeInfo = (NodeInfo<RestResource>) getModel().getNodeInfo(selectionModel.getSelectedObject());
+               if(nodeInfo==null || nodeInfo.getValueUpdater()==null){
+                       GSS.get().showFileList(getSelection());
+               }
+               else
+                       nodeInfo.getValueUpdater().update(selectionModel.getSelectedObject());
+               GSS.get().setCurrentSelection(selectionModel.getSelectedObject());
+               
+               
+            }
+        };
+        selectionModel.addSelectionChangeHandler(selectionHandler);
+           sinkEvents(Event.ONCONTEXTMENU);
+               sinkEvents(Event.ONMOUSEUP);
+           initWidget(tree);
+           FolderResource loadingResource = new FolderResource("loading");
+           loadingResource.setName("Loading....");
+           loadingResource.setShared(false);
+           RestResourceWrapper loading = new RestResourceWrapper(loadingResource);
+           model.getRootNodes().setList(Arrays.asList((RestResource)loading));
+               
+           DeferredCommand.addCommand(new IncrementalCommand() {
+
+                       @Override
+                       public boolean execute() {
+                               return fetchRootFolders();
+                       }
+               });
+       }
+       
+       public void updateNode(RestResource resource){
+               NodeInfo<RestResource> nodeInfo = (NodeInfo<RestResource>) getModel().getNodeInfo(resource);
+               
+               if(nodeInfo!=null){
+               if(nodeInfo.getValueUpdater()==null){}
+               else
+                       nodeInfo.getValueUpdater().update(resource);
+       }
+       }
+       
+       public void updateNodeChildren(final RestResource resource){
+               
+               if(resource instanceof RestResourceWrapper){
+                       boolean updated=false;
+                       if(((RestResourceWrapper)resource).getResource().getFolders().size()==0){
+                               if(((RestResourceWrapper)resource).getResource().getParentURI().equals(getMyFolders().getUri())){
+                                       updateNodeChildren(getMyFolders().getUri());
+                                       return;
+                               }
+                               if(model.getMymap().get(((RestResourceWrapper)resource).getResource().getParentURI())!=null){
+                                       model.getMymap().get(((RestResourceWrapper)resource).getResource().getParentURI()).refresh(null);
+                                       updated=true;
+                               }
+                               if(model.getOthersmap().get(((RestResourceWrapper)resource).getResource().getParentURI())!=null){
+                                       model.getOthersmap().get(((RestResourceWrapper)resource).getResource().getParentURI()).refresh(null);
+                                       updated=true;
+                               }
+                               if(model.getSharedmap().get(((RestResourceWrapper)resource).getResource().getParentURI())!=null){
+                                       model.getSharedmap().get(((RestResourceWrapper)resource).getResource().getParentURI()).refresh(null);
+                                       updated=true;
+                               }
+                               if(updated){
+                                       if(utils.doesSharedNodeContainsResourceIn1stLevel(resource.getUri())){
+                                               updateMySharedNode();
+                                       }
+                                       else if(tree.getRootTreeNode().isChildOpen(2)){
+                                               utils.refreshNodeContainingResource(tree.getRootTreeNode().setChildOpen(2,true),resource.getUri());
+                                       }
+                                       //return;
+                               }
+                       }
+               }
+               
+               utils.refreshNodeContainingResource(resource);
+               if(utils.doesSharedNodeContainsResourceIn1stLevel(resource.getUri())){
+                       updateMySharedNode();
+               }
+               else if(tree.getRootTreeNode().isChildOpen(2)){
+                       GWT.log("REFRESH THE OTHER WAY 2:"+resource);
+                       utils.refreshNodeContainingResource(tree.getRootTreeNode().setChildOpen(2,true),resource.getUri());
+               }
+               
+       }
+       public void updateNodeChildrenForRemove(final String resource){
+               GWT.log("********************************");
+               GWT.log("[UPDATENODECHILDREN]"+resource);
+               GWT.log("********************************");
+               boolean updated=false;
+               TreeNode node=null;
+               TreeNode sharedNode=null;
+               if(tree.getRootTreeNode().isChildOpen(0)){
+                       node = utils.getNodeContainingResource2(tree.getRootTreeNode().setChildOpen(0,true), resource);
+               }
+                       GWT.log("CHECK NODE1:"+node+" "+resource);
+               
+                       if(tree.getRootTreeNode().isChildOpen(2)){
+                               GWT.log("CHECK NODE2:"+node);
+                               if(node==null)
+                                       node = utils.getNodeContainingResource2(tree.getRootTreeNode().setChildOpen(2,true), resource);
+                               
+                       }
+               if(node==null)
+                       if(tree.getRootTreeNode().isChildOpen(3)){
+                               GWT.log("CHECK NODE3:"+node);
+                               node = utils.getNodeContainingResource2(tree.getRootTreeNode().setChildOpen(3,true), resource);
+               }
+               if(node != null && node.getValue() instanceof RestResourceWrapper){
+                       GWT.log("*********************"+((RestResourceWrapper) node.getValue()).getResource().getFolders().size());
+                       RestResourceWrapper wrapper  = (RestResourceWrapper) node.getValue();
+                       if(wrapper.getResource().countNotDeletedSubfolders()==1||wrapper.getResource().countNotDeletedSubfolders()==0){
+                               updateNodeChildren(((RestResourceWrapper) node.getValue()).getResource().getParentURI());
+                               if(((RestResourceWrapper) node.getValue()).getResource().getParentURI().equals(myFolders.getUri())){
+                                       if(utils.doesSharedNodeContainsResourceIn1stLevel(resource)||utils.doesSharedNodeContainsResourceIn2ndLevel(resource)){
+                                               updateMySharedNode();
+                                       }
+                               }
+                                                       
+                       }
+                       else
+                               updateNodeChildren(((RestResource) node.getValue()).getUri());
+                       return;
+               }
+               updateNodeChildren(resource);
+       }
+       public void updateNodeChildren(final String resource){
+               
+                       
+               GWT.log("REFRESH THE OTHER WAY");
+               utils.refreshNodeContainingResource(resource);
+               if(utils.doesSharedNodeContainsResourceIn1stLevel(resource)||utils.doesSharedNodeContainsResourceIn2ndLevel(resource)){
+                       GWT.log("REFRESH THE OTHER WAY 1:"+resource);
+                       updateMySharedNode();
+               }
+               else if(tree.getRootTreeNode().isChildOpen(2)){
+                       GWT.log("REFRESH THE OTHER WAY 2:"+resource);
+                       utils.refreshNodeContainingResource(tree.getRootTreeNode().setChildOpen(2,true),resource);
+               }
+       }
+       
+       protected void showPopup(final int x, final int y) {
+               if (selectionModel.getSelectedObject() == null)
+                       return;
+               if (menu != null)
+                       menu.hide();
+               menu = new FolderContextMenu(images);
+               menu.setPopupPosition(x, y);
+               menu.show();
+       }
+       private boolean init=false;
+       public boolean fetchRootFolders() {
+               UserResource userResource = GSS.get().getCurrentUserResource();
+               if (userResource == null)
+                       return !DONE;
+               if(!init){
+                       final String path = userResource.getFilesPath();
+                       GetCommand<FolderResource> gf = new GetCommand<FolderResource>(FolderResource.class, path, null) {
+       
+                               @Override
+                               public void onComplete() {
+                                       myFolders = new MyFolderResource(getResult());
+                                       //selectionModel.setSelected(myFolders, true);
+                                       //rootNodes.setList(Arrays.asList((RestResource)rootResource));
+                                       //tree.getRootTreeNode().setChildOpen(0, true);
+                               }
+       
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("Error fetching root folder", t);
+                                       GSS.get().displayError("Unable to fetch root folder");
+                               }
+       
+                       };
+                       DeferredCommand.addCommand(gf);
+                       DeferredCommand.addCommand(new GetCommand<TrashResource>(TrashResource.class, GSS.get().getCurrentUserResource().getTrashPath(), null) {
+                               @Override
+                               public void onComplete() {
+                                       trash = getResult();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       if(t instanceof RestException){
+                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                               // On IE status code 1223 may be returned instead of 204.
+                                               if(statusCode == 204 || statusCode == 1223){
+                                                       trash = new TrashResource(GSS.get().getCurrentUserResource().getTrashPath());
+                                       }
+                                       else{
+                                               GWT.log("", t);
+                                               GSS.get().displayError("Unable to fetch trash folder:"+t.getMessage());
+                                               trash = new TrashResource(GSS.get().getCurrentUserResource().getTrashPath());
+                                       }
+                               }
+                       }
+                       });
+                       GetCommand<SharedResource> gs = new GetCommand<SharedResource>(SharedResource.class, userResource.getSharedPath(), null) {
+
+                               @Override
+                               public void onComplete() {
+                                       myshared=getResult();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("Error fetching Shared Root folder", t);
+                                       GSS.get().displayError("Unable to fetch Shared Root folder");
+                               }
+                       };
+                       DeferredCommand.addCommand(gs);
+                       GetCommand<OthersResource> go = new GetCommand<OthersResource>(OthersResource.class,
+                                               userResource.getOthersPath(), null) {
+
+                               @Override
+                               public void onComplete() {
+                                       others = getResult();
+                                       GSS.get().removeGlassPanel();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("Error fetching Others Root folder", t);
+                                       GSS.get().displayError("Unable to fetch Others Root folder");
+                               }
+                       };
+                       DeferredCommand.addCommand(go);
+               }
+               if(myFolders==null||trash==null||myshared==null||others==null)
+                       return !DONE;
+               model.getRootNodes().setList(Arrays.asList((RestResource)myFolders,(RestResource)trash,(RestResource)myshared,(RestResource)others));
+               tree.getRootTreeNode().setChildOpen(0, true);
+               selectionModel.setSelected(myFolders, true);
+               return DONE;
+       }
+
+       public Images getImages() {
+               return images;
+       }
+       
+       
+       public void updateTrashNode(){
+               DeferredCommand.addCommand(new GetCommand<TrashResource>(TrashResource.class, GSS.get().getCurrentUserResource().getTrashPath(), null) {
+                       @Override
+                       public void onComplete() {
+                               trash = getResult();
+                               boolean trashIsOpen = tree.getRootTreeNode().isChildOpen(1);
+                               model.getRootNodes().getList().set(1, trash);
+                               model.getRootNodes().refresh();
+                               tree.getRootTreeNode().setChildOpen(1, true);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       // On IE status code 1223 may be returned instead of 204.
+                                       if(statusCode == 204 || statusCode == 1223){
+                                               trash = new TrashResource(GSS.get().getCurrentUserResource().getTrashPath());
+                                               model.getRootNodes().getList().set(1, trash);
+                                               //model.getRootNodes().refresh();
+                               }
+                               else{
+                                       GWT.log("", t);
+                                       GSS.get().displayError("Unable to fetch trash folder:"+t.getMessage());
+                                       trash = new TrashResource(GSS.get().getCurrentUserResource().getTrashPath());
+                                       model.getRootNodes().getList().set(1, trash);
+                                       //model.getRootNodes().refresh();
+                               }
+                       }
+               }
+               });
+       }
+       
+       public void updateRootNode(){
+               final String path = GSS.get().getCurrentUserResource().getFilesPath();
+               GetCommand<FolderResource> gf = new GetCommand<FolderResource>(FolderResource.class, path, null) {
+
+                       @Override
+                       public void onComplete() {
+                               myFolders = new MyFolderResource(getResult());
+                               model.getRootNodes().getList().set(0, myFolders);
+                               model.getRootNodes().refresh();
+                               tree.getRootTreeNode().setChildOpen(0, true);
+                               
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("Error fetching root folder", t);
+                               GSS.get().displayError("Unable to fetch root folder");
+                       }
+
+               };
+               DeferredCommand.addCommand(gf);
+       }
+       
+       public void updateMySharedNode(){
+               GetCommand<SharedResource> gs = new GetCommand<SharedResource>(SharedResource.class, GSS.get().getCurrentUserResource().getSharedPath(), null) {
+
+                       @Override
+                       public void onComplete() {
+                               myshared=getResult();
+                               model.getRootNodes().getList().set(2, myshared);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("Error fetching Shared Root folder", t);
+                               GSS.get().displayError("Unable to fetch Shared Root folder");
+                       }
+               };
+               DeferredCommand.addCommand(gs);
+       }
+       
+       public void updateOtherNode(){
+               GetCommand<OthersResource> go = new GetCommand<OthersResource>(OthersResource.class,
+                                       GSS.get().getCurrentUserResource().getOthersPath(), null) {
+
+                       @Override
+                       public void onComplete() {
+                               others = getResult();
+                               model.getRootNodes().getList().set(3, others);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("Error fetching Others Root folder", t);
+                               GSS.get().displayError("Unable to fetch Others Root folder");
+                       }
+               };
+               DeferredCommand.addCommand(go);
+       }
+       
+       
+       public RestResource getSelection(){
+               return selectionModel.getSelectedObject();
+       }
+       
+       public void clearSelection(){
+               if(GSS.get().getCurrentSelection().equals(getSelection()))
+                       GSS.get().setCurrentSelection(null);
+               selectionModel.setSelected(getSelection(), false);
+       }
+       
+       
+       /**
+        * Retrieve the myFolders.
+        *
+        * @return the myFolders
+        */
+       public MyFolderResource getMyFolders() {
+               return myFolders;
+       }
+       
+       
+       /**
+        * Retrieve the myshared.
+        *
+        * @return the myshared
+        */
+       public SharedResource getMyshared() {
+               return myshared;
+       }
+       
+       
+       /**
+        * Retrieve the trash.
+        *
+        * @return the trash
+        */
+       public TrashResource getTrash() {
+               return trash;
+       }
+       
+       
+       /**
+        * Retrieve the others.
+        *
+        * @return the others
+        */
+       public OthersResource getOthers() {
+               return others;
+       }
+       
+       
+       /**
+        * Retrieve the model.
+        *
+        * @return the model
+        */
+       public TreeViewModel getModel() {
+               return model;
+       }
+       
+       
+       
+       /**
+        * Retrieve the utils.
+        *
+        * @return the utils
+        */
+       public CellTreeViewUtils getUtils() {
+               return utils;
+       }
+       
+       public interface RefreshHandler{
+               void onRefresh();               
+       }
+       
+       
+       public boolean isTrashOrTrashFolderSelected(){
+               return (getSelection() instanceof TrashResource) || (getSelection() instanceof TrashFolderResource);
+       }
+       
+       public OtherUserResource getOtherUserResourceOfOtherFolder(OthersFolderResource res){
+               TreeNode n = utils.getNodeContainingResource(tree.getRootTreeNode().setChildOpen(3, true), res);
+               
+               if(n!=null){
+                       if(n.getValue() instanceof OtherUserResource)
+                               return (OtherUserResource) n.getValue();
+                       TreeNode parent = n.getParent();
+                       
+                       while (parent!=null){
+                               if(parent.getValue() instanceof OtherUserResource)
+                                       return (OtherUserResource) parent.getValue();
+                               parent = parent.getParent();
+                       }
+               }
+               return null;
+       }
+       
+       public void refreshCurrentNode(boolean clearSelection){
+               NodeInfo<RestResource> nodeInfo = (NodeInfo<RestResource>) getModel().getNodeInfo(selectionModel.getSelectedObject());
+       if(nodeInfo==null || nodeInfo.getValueUpdater()==null){
+               GSS.get().showFileList(getSelection(),clearSelection);
+       }
+       else{
+               if(!clearSelection)
+                       ((ClearSelection)nodeInfo.getValueUpdater()).setClearSelection(clearSelection);
+               nodeInfo.getValueUpdater().update(selectionModel.getSelectedObject());
+       }
+       }
+       
+}
diff --git a/src/org/gss_project/gss/web/client/CellTreeViewModel.java b/src/org/gss_project/gss/web/client/CellTreeViewModel.java
new file mode 100644 (file)
index 0000000..6b0a504
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import static com.google.gwt.query.client.GQuery.$;
+import org.gss_project.gss.web.client.CellTreeView.Images;
+import org.gss_project.gss.web.client.CellTreeView.RefreshHandler;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.MyFolderResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.OthersFolderResource;
+import org.gss_project.gss.web.client.rest.resource.OthersResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+import org.gss_project.gss.web.client.rest.resource.SharedFolderResource;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import gwtquery.plugins.draggable.client.DragAndDropManager;
+import gwtquery.plugins.draggable.client.DraggableOptions;
+import gwtquery.plugins.draggable.client.StopDragException;
+import gwtquery.plugins.draggable.client.DraggableOptions.CursorAt;
+import gwtquery.plugins.draggable.client.DraggableOptions.DragFunction;
+import gwtquery.plugins.draggable.client.DraggableOptions.RevertOption;
+import gwtquery.plugins.draggable.client.events.DragContext;
+import gwtquery.plugins.droppable.client.DroppableOptions;
+import gwtquery.plugins.droppable.client.DroppableOptions.DroppableFunction;
+import gwtquery.plugins.droppable.client.events.DragAndDropContext;
+import gwtquery.plugins.droppable.client.gwt.DragAndDropNodeInfo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Style.Cursor;
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.view.client.AsyncDataProvider;
+import com.google.gwt.view.client.HasData;
+import com.google.gwt.view.client.ListDataProvider;
+import com.google.gwt.view.client.ProvidesKey;
+import com.google.gwt.view.client.SingleSelectionModel;
+import com.google.gwt.view.client.TreeViewModel;
+
+
+
+/**
+ * @author kman
+ *
+ */
+public class CellTreeViewModel implements TreeViewModel{
+       
+       private final ListDataProvider<RestResource> rootNodes = new ListDataProvider<RestResource>();
+       private Map<String,FolderResource> folderCache=new HashMap<String, FolderResource>();
+       final Images images;
+       SingleSelectionModel<RestResource> selectionModel;
+       Map<String, MyFolderDataProvider> mymap = new HashMap<String, MyFolderDataProvider>();
+       Map<String, MyFolderDataProvider> sharedmap = new HashMap<String, MyFolderDataProvider>();
+       Map<String, MyFolderDataProvider> othersmap = new HashMap<String, MyFolderDataProvider>();
+       static interface Templates extends SafeHtmlTemplates {
+           Templates INSTANCE = GWT.create(Templates.class);
+
+           @Template(" <div id='dragHelper' class='{0}'></div>")
+           SafeHtml outerHelper(String cssClassName);
+         }
+
+       void configureDragOperation(final DraggableOptions options) {
+
+           // set a custom element as drag helper. The content of the helper will be
+           // set when the drag will start
+           options.setHelper($(Templates.INSTANCE.outerHelper(
+               "drag").asString()));
+           // opacity of the drag helper
+           options.setOpacity((float) 0.9);
+           // cursor during the drag operation
+           options.setCursor(Cursor.MOVE);
+           // the cell being greater than the helper, force the position of the
+           // helper on the mouse cursor.
+           options.setCursorAt(new CursorAt(10, 10, null, null));
+           // append the helper to the body element
+           options.setAppendTo("body");
+           options.setCancel("select");
+           // set the revert option
+           options.setRevert(RevertOption.ON_INVALID_DROP);
+           
+           options.setOnBeforeDragStart(new DragFunction() {
+                       
+                       @Override
+                       public void f(DragContext context) {
+                                RestResource value = context.getDraggableData();
+                            if(!CellTreeViewModel.this.selectionModel.isSelected(value)){
+                               throw new StopDragException();
+                             }
+                            if(value instanceof TrashResource || value instanceof SharedResource || value instanceof OthersResource || value instanceof OtherUserResource){
+                               throw new StopDragException();
+                             }
+                               
+                       }
+               });
+           // use a Function to fill the content of the helper
+           // we could also add a DragStartEventHandler on the DragAndDropTreeCell and
+           // DragAndDropCellList.
+           
+           options.setOnDragStart(new DragFunction() {
+             public void f(DragContext context) {
+               RestResourceWrapper memberInfo = context.getDraggableData();
+               context.getHelper().setInnerHTML(memberInfo.getName());
+             }
+           });
+
+         }
+
+       /**
+        * 
+        */
+       public CellTreeViewModel(final Images _images,SingleSelectionModel<RestResource> selectionModel ) {
+               super();
+               images=_images;
+               this.selectionModel=selectionModel;
+       }
+       
+       private final Cell<RestResource> departmentCell = new AbstractCell<RestResource>("contextmenu"){
+               
+               @Override
+               public void render(com.google.gwt.cell.client.Cell.Context arg0, RestResource arg1, SafeHtmlBuilder arg2) {
+                       String id = null;
+                       String html = null;
+                       String name = null;
+                       if(arg1 instanceof TrashFolderResource){
+                               html = AbstractImagePrototype.create(images.folderYellow()).getHTML();
+                               FolderResource res = ((RestResourceWrapper)arg1).getResource();
+                               name = res.getName();
+                               id = res.getParentName() +"."+name;
+                       }
+                       else if(arg1 instanceof RestResourceWrapper){
+                               FolderResource res = ((RestResourceWrapper)arg1).getResource();
+                               if(res.isShared())
+                                       html = AbstractImagePrototype.create(images.sharedFolder()).getHTML();
+                               else if(res.getParentName()==null){
+                                       html = AbstractImagePrototype.create(images.home()).getHTML();
+                               }
+                               else
+                                       html = AbstractImagePrototype.create(images.folderYellow()).getHTML();
+                               name = res.getName();
+                               if(res.getParentName() != null){                                        
+                                       id = res.getParentName()+"."+name;
+                               }else{                                  
+                                       id = name;
+                               }
+                               
+                       }
+                       else if(arg1 instanceof TrashResource){
+                               html = AbstractImagePrototype.create(images.trash()).getHTML();
+                               name="Trash";
+                               id = name;                              
+                       }
+                       
+                       else if(arg1 instanceof SharedResource){
+                               html = AbstractImagePrototype.create(images.myShared()).getHTML();
+                               name = "My Shared";
+                               id = name;
+                       }
+                       else if(arg1 instanceof OthersResource){
+                               html = AbstractImagePrototype.create(images.othersShared()).getHTML();
+                               name = "Other's Shared";
+                               id = "others";                          
+                       }
+                       else if(arg1 instanceof OtherUserResource){
+                               html = AbstractImagePrototype.create(images.permUser()).getHTML();
+                               name = ((OtherUserResource)arg1).getName();
+                               id = name;
+                       }
+                       arg2.appendHtmlConstant(html);
+                       arg2.append(FileList.Templates.INSTANCE.spanWithIdAndClass(id, "papala", name));
+               }
+               
+               public void onBrowserEvent(Cell.Context context, com.google.gwt.dom.client.Element parent, RestResource value, com.google.gwt.dom.client.NativeEvent event, com.google.gwt.cell.client.ValueUpdater<RestResource> valueUpdater) {
+                       if(event.getType().equals("contextmenu")){
+                               selectionModel.setSelected(value, true);
+                               GSS.get().setCurrentSelection(value);
+                               GSS.get().getTreeView().showPopup(event.getClientX(), event.getClientY());
+                       }
+               };
+               
+       };
+       
+       
+       @Override
+       public <T> NodeInfo<?> getNodeInfo(final T value) {
+               
+               if(value==null){
+                       DragAndDropNodeInfo n = new DragAndDropNodeInfo<RestResource>(getRootNodes(), departmentCell,
+                                   selectionModel, null);
+                       configureFolderDrop(n);
+               configureDragOperation(n.getDraggableOptions());
+                       return n;
+               }
+               else if (value instanceof MyFolderResource) {
+               // Second level.
+                       MyFolderDataProvider dataProvider = new MyFolderDataProvider(
+                   ((MyFolderResource) value),MyFolderResource.class);
+               DragAndDropNodeInfo<RestResource> n =  new DragAndDropNodeInfo<RestResource>(dataProvider, departmentCell,
+                   selectionModel, new ResourceValueUpdater());
+               mymap.put(((MyFolderResource) value).getUri(), dataProvider);
+               
+               // permission cell are not draggable
+               //n.setCellDroppableOnly();
+               configureFolderDrop(n);
+               configureDragOperation(n.getDraggableOptions());
+               
+               return n;
+               }
+               else if (value instanceof SharedResource) {
+               // Second level.
+                       MyFolderDataProvider dataProvider = new MyFolderDataProvider(
+                   ((SharedResource) value), SharedFolderResource.class);
+                       sharedmap.put(((SharedResource) value).getUri(), dataProvider);
+                       DragAndDropNodeInfo<RestResource> n = new DragAndDropNodeInfo<RestResource>(dataProvider, departmentCell,
+                   selectionModel, new ResourceValueUpdater());
+                        configureFolderDrop(n);
+                       configureDragOperation(n.getDraggableOptions());
+                       return n;
+               }
+               else if (value instanceof TrashResource) {
+               // Second level.
+                       ListDataProvider<RestResource> trashProvider = new ListDataProvider<RestResource>();
+                       List<RestResource> r = new ArrayList<RestResource>();
+                       for(FolderResource f : GSS.get().getTreeView().getTrash().getFolders()){
+                               r.add(new TrashFolderResource(f));
+                       }
+                       trashProvider.setList(r);
+                       DragAndDropNodeInfo<RestResource> n = new DragAndDropNodeInfo<RestResource>(trashProvider, departmentCell,
+                   selectionModel, new ResourceValueUpdater());
+                       configureFolderDrop(n);
+               configureDragOperation(n.getDraggableOptions());
+                       return n;
+               }
+               else if (value instanceof OthersResource) {
+               // Second level.
+                       OthersDataProvider dataProvider = new OthersDataProvider(
+                   ((OthersResource) value), SharedFolderResource.class);
+               DragAndDropNodeInfo<RestResource> n = new DragAndDropNodeInfo<RestResource>(dataProvider, departmentCell,
+                   selectionModel, null);
+               configureFolderDrop(n);
+               configureDragOperation(n.getDraggableOptions());
+               return n;
+               }
+               else if (value instanceof SharedFolderResource) {
+               // Second level.
+                       MyFolderDataProvider dataProvider = new MyFolderDataProvider(
+                   ((SharedFolderResource) value),SharedFolderResource.class);
+               DragAndDropNodeInfo<RestResource> n =  new DragAndDropNodeInfo<RestResource>(dataProvider, departmentCell,
+                   selectionModel, new ResourceValueUpdater());
+               sharedmap.put(((SharedFolderResource) value).getUri(), dataProvider);
+               configureFolderDrop(n);
+               configureDragOperation(n.getDraggableOptions());
+               return n;
+               }
+               else if (value instanceof OthersFolderResource) {
+               // Second level.
+                       MyFolderDataProvider dataProvider = new MyFolderDataProvider(
+                   ((OthersFolderResource) value),OthersFolderResource.class);
+               DragAndDropNodeInfo<RestResource> n =  new DragAndDropNodeInfo<RestResource>(dataProvider, departmentCell,
+                   selectionModel, new ResourceValueUpdater());
+               //nodeInfos.put(((OthersFolderResource) value).getUri(), n);
+               othersmap.put(((OthersFolderResource) value).getUri(), dataProvider);
+               configureFolderDrop(n);
+               configureDragOperation(n.getDraggableOptions());
+               return n;
+               }
+               else if (value instanceof OtherUserResource) {
+               // Second level.
+                       MyFolderDataProvider dataProvider = new MyFolderDataProvider(
+                   ((OtherUserResource) value),OthersFolderResource.class);
+               DragAndDropNodeInfo<RestResource> n =  new DragAndDropNodeInfo<RestResource>(dataProvider, departmentCell,
+                   selectionModel, new ResourceValueUpdater());
+               configureFolderDrop(n);
+               configureDragOperation(n.getDraggableOptions());
+               return n;
+               }
+               // TODO Auto-generated method stub
+               return null;
+       }
+       
+       private void configureFolderDrop(DragAndDropNodeInfo<RestResource> n){
+               DroppableOptions options = n.getDroppableOptions();
+        options.setDroppableHoverClass("droppableHover");
+        // use a DroppableFunction here. We can also add a DropHandler in the tree
+        // itself
+        options.setOnOver(new DroppableFunction() {
+                       
+                       @Override
+                       public void f(final DragAndDropContext context) {
+                               if(context.getDroppableData()!=null && context.getDroppableData() instanceof RestResource){
+                                       
+                                       GSS.get().getTreeView().getUtils().openNodeContainingResource((RestResource) context.getDroppableData(), new RefreshHandler() {
+                                               
+                                               @Override
+                                               public void onRefresh() {
+                                                       
+                                                       DragAndDropManager.getInstance().update(context);//initialize(context, GQueryUi.Event.create(com.google.gwt.user.client.Event.getCurrentEvent()));
+                                                       
+                                               }
+                                       });
+                                       
+                               }
+                       }
+               });
+        options.setOnDrop(new DroppableFunction() {
+
+          public void f(DragAndDropContext context) {
+                 
+                 DnDFolderPopupMenu popup ;
+                 if(context.getDraggableData() instanceof FileResource){
+                         if(context.getDroppableData() instanceof RestResourceWrapper)
+                                 popup = new DnDFolderPopupMenu(images, ((RestResourceWrapper) context.getDroppableData()).getResource(), Arrays.asList(context.getDraggableData()));
+                         else
+                                 popup = new DnDFolderPopupMenu(images, null, Arrays.asList(context.getDraggableData()));
+                 }
+                 
+                 else{
+                         if(context.getDroppableData() instanceof RestResourceWrapper)
+                                 popup = new DnDFolderPopupMenu(images, ((RestResourceWrapper) context.getDroppableData()).getResource(), context.getDraggableData());
+                         else
+                                 popup = new DnDFolderPopupMenu(images, null, context.getDraggableData());
+                 }
+                 
+                 int left = context.getDroppable().getAbsoluteLeft() + 40;
+              int top = context.getDroppable().getAbsoluteTop() + 20;
+              popup.setPopupPosition(left, top);
+                
+                 popup.show();
+          }
+        });
+       }
+
+       @Override
+       public boolean isLeaf(Object value) {
+               if(value instanceof RestResourceWrapper)
+                       return ((RestResourceWrapper)value).getResource().getFolders().size()==0;
+               else if(value instanceof TrashResource)
+                       return ((TrashResource)value).getFolders().size()==0;
+               else if(value instanceof SharedResource)
+                       return ((SharedResource)value).getFolders().size()==0;
+               else if(value instanceof OthersResource)
+                       return ((OthersResource)value).getOtherUsers().size()==0;
+               else if(value instanceof OtherUserResource)
+                       return ((OtherUserResource)value).getFolders().size()==0;
+               return false;
+       }
+       
+       /**
+        * Retrieve the selectionModel.
+        *
+        * @return the selectionModel
+        */
+       public SingleSelectionModel<RestResource> getSelectionModel() {
+               return selectionModel;
+       }
+       static interface ClearSelection{
+               public void setClearSelection(boolean clearSelection);
+       }
+       class ResourceValueUpdater implements  ValueUpdater<RestResource>,ClearSelection{
+               boolean clearSelection=true;
+               
+               
+               /**
+                * Modify the clearSelection.
+                *
+                * @param clearSelection the clearSelection to set
+                */
+               public void setClearSelection(boolean clearSelection) {
+                       this.clearSelection = clearSelection;
+               }
+               @Override
+               public void update(final RestResource value) {
+                       if(value instanceof MyFolderResource){
+                               GetCommand<FolderResource> gf = new GetCommand<FolderResource>(FolderResource.class, value.getUri(), null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               FolderResource rootResource = getResult();
+                                               //((MyFolderResource)value).getResource().setFiles(rootResource.getFiles());
+                                               ((MyFolderResource)value).setResource(rootResource);
+                                               if(GSS.get().getTreeView().getSelection().getUri().equals(value.getUri()))
+                                                       selectionModel.setSelected(value, true);
+                                               GSS.get().onResourceUpdate(value,clearSelection);
+                                               
+                                       }
+       
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("Error fetching root folder", t);
+                                               GSS.get().displayError("Unable to fetch root folder");
+                                       }
+       
+                               };
+                               DeferredCommand.addCommand(gf);
+                       }
+                       else if(value instanceof TrashResource){
+                               DeferredCommand.addCommand(new GetCommand<TrashResource>(TrashResource.class, GSS.get().getCurrentUserResource().getTrashPath(), null) {
+                                       @Override
+                                       public void onComplete() {
+                                               //trash = getResult();
+                                               ((TrashResource)value).setFolders(getResult().getFolders());
+                                               ((TrashResource)value).setFiles(getResult().getFiles());
+                                               for(RestResource r : getRootNodes().getList()){
+                                                       if(r instanceof TrashResource)
+                                                               getRootNodes().getList().set(getRootNodes().getList().indexOf(r),GSS.get().getTreeView().getTrash());
+                                               }
+                                               GSS.get().getTreeView().updateNodeChildren(GSS.get().getTreeView().getTrash());
+                                               //GSS.get().showFileList(true);
+                                               GSS.get().onResourceUpdate(value,clearSelection);
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               if(t instanceof RestException){
+                                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                                       // On IE status code 1223 may be returned instead of 204.
+                                                       if(statusCode == 204 || statusCode == 1223){
+                                                               ((TrashResource)value).setFolders(new ArrayList<FolderResource>());
+                                                               ((TrashResource)value).setFiles(new ArrayList<FileResource>());
+                                               }
+                                               else{
+                                                       GWT.log("", t);
+                                                       GSS.get().displayError("Unable to fetch trash folder:"+t.getMessage());
+                                                       //GSS.get().getTreeView().getTrash() = new TrashResource(GSS.get().getCurrentUserResource().getTrashPath());
+                                               }
+                                       }
+                               }
+                               });
+                       }
+                       else if(value instanceof OthersFolderResource){
+                               GetCommand<FolderResource> gf = new GetCommand<FolderResource>(FolderResource.class, value.getUri(), null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               FolderResource rootResource = getResult();
+                                               //((MyFolderResource)value).getResource().setFiles(rootResource.getFiles());
+                                               ((OthersFolderResource)value).setResource(rootResource);
+                                               if(GSS.get().getTreeView().getSelection().getUri().equals(value.getUri()))
+                                                       selectionModel.setSelected(value, true);
+                                               GSS.get().onResourceUpdate(value,clearSelection);
+                                               
+                                       }
+       
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("Error fetching root folder", t);
+                                               GSS.get().displayError("Unable to fetch root folder");
+                                       }
+       
+                               };
+                               DeferredCommand.addCommand(gf);
+                       }
+                       else if(value instanceof SharedFolderResource){
+                               GetCommand<FolderResource> gf = new GetCommand<FolderResource>(FolderResource.class, value.getUri(), null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               FolderResource rootResource = getResult();
+                                               //((MyFolderResource)value).getResource().setFiles(rootResource.getFiles());
+                                               ((SharedFolderResource)value).setResource(rootResource);
+                                               if(GSS.get().getTreeView().getSelection().getUri().equals(value.getUri()))
+                                                       selectionModel.setSelected(value, true);
+                                               GSS.get().onResourceUpdate(value,clearSelection);
+                                               
+                                       }
+       
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("Error fetching root folder", t);
+                                               GSS.get().displayError("Unable to fetch root folder");
+                                       }
+       
+                               };
+                               DeferredCommand.addCommand(gf);
+                       }
+                       else if(value instanceof SharedResource){
+                               GetCommand<SharedResource> gf = new GetCommand<SharedResource>(SharedResource.class, value.getUri(), null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               SharedResource rootResource = getResult();
+                                               ((SharedResource)value).setFolders(getResult().getFolders());
+                                               ((SharedResource)value).setFiles(getResult().getFiles());
+                                               
+                                               if(GSS.get().getTreeView().getSelection().getUri().equals(value.getUri()))
+                                                       selectionModel.setSelected(value, true);
+                                               GSS.get().onResourceUpdate(value,clearSelection);
+                                               
+                                       }
+       
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("Error fetching root folder", t);
+                                               GSS.get().displayError("Unable to fetch root folder");
+                                       }
+       
+                               };
+                               DeferredCommand.addCommand(gf);
+                       }
+                       else if(value instanceof OtherUserResource){
+                               GetCommand<OtherUserResource> gf = new GetCommand<OtherUserResource>(OtherUserResource.class, value.getUri(), null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               OtherUserResource rootResource = getResult();
+                                               ((OtherUserResource)value).setFolders(getResult().getFolders());
+                                               ((OtherUserResource)value).setFiles(getResult().getFiles());
+                                               
+                                               if(GSS.get().getTreeView().getSelection().getUri().equals(value.getUri()))
+                                                       selectionModel.setSelected(value, true);
+                                               GSS.get().onResourceUpdate(value,clearSelection);
+                                               
+                                       }
+       
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("Error fetching root folder", t);
+                                               GSS.get().displayError("Unable to fetch root folder");
+                                       }
+       
+                               };
+                               DeferredCommand.addCommand(gf);
+                       }
+                       
+               }
+               
+       }
+       class MyFolderDataProvider extends AsyncDataProvider<RestResource>{
+               private RestResource restResource;
+               private Class resourceClass;
+                 public MyFolderDataProvider(RestResource department, Class resourceClass) {
+                   super(new ProvidesKey<RestResource>() {
+
+                               @Override
+                               public Object getKey(RestResource item) {
+                                       return item.getUri();
+                               }});
+                   this.restResource = department;
+                   this.resourceClass=resourceClass;
+                 }
+
+                 @Override
+                 protected void onRangeChanged(final HasData<RestResource> view) {
+                       refresh(null);
+                 }
+                 
+               /**
+                * Retrieve the restResource.
+                *
+                * @return the restResource
+                */
+               public RestResource getRestResource() {
+                       return restResource;
+               }
+               
+               
+               /**
+                * Modify the restResource.
+                *
+                * @param restResource the restResource to set
+                */
+               public void setRestResource(RestResource restResource) {
+                       this.restResource = restResource;
+               }
+               List<RestResource> res =null;
+                 public void refresh(final RefreshHandler refresh){
+                         FolderResource cache = null;
+                         if(restResource instanceof RestResourceWrapper && !((RestResourceWrapper)restResource).getResource().isNeedsExpanding())
+                                 cache = ((RestResourceWrapper)restResource).getResource();
+                         GetCommand<FolderResource> gf = new GetCommand<FolderResource>(FolderResource.class, restResource.getUri(),cache ) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               if(restResource instanceof RestResourceWrapper){
+                                                       ((RestResourceWrapper)restResource).setResource(getResult());//restResource = getResult();
+                                                       ((RestResourceWrapper)restResource).getResource().setNeedsExpanding(false);
+                                               }
+                                               if(usedCachedVersion()&&res!=null){
+                                                       
+                                                               updateRowCount(res.size(), true);
+                                                               updateRowData(0,res);
+                                                       return;
+                                               }
+                                               String[] folderPaths = null;
+                                               if(resourceClass.equals(MyFolderResource.class))
+                                                       folderPaths=((MyFolderResource) restResource).getResource().getSubfolderPaths().toArray(new String[] {});
+                                               else if(resourceClass.equals(SharedFolderResource.class) && restResource instanceof SharedResource)
+                                                       folderPaths=((SharedResource) restResource).getSubfolderPaths().toArray(new String[] {});
+                                               else if(resourceClass.equals(SharedFolderResource.class)){
+                                                       folderPaths=((SharedFolderResource) restResource).getResource().getSubfolderPaths().toArray(new String[] {});
+                                                       GWT.log("------------>"+folderPaths);
+                                               }
+                                               else if(resourceClass.equals(TrashFolderResource.class))
+                                                       folderPaths=((TrashFolderResource) restResource).getResource().getSubfolderPaths().toArray(new String[] {});
+                                               else if(resourceClass.equals(OthersFolderResource.class) && restResource instanceof OtherUserResource)
+                                                       folderPaths=((OtherUserResource) restResource).getSubfolderPaths().toArray(new String[] {});
+                                               else if(resourceClass.equals(OthersFolderResource.class))
+                                                       folderPaths=((OthersFolderResource) restResource).getResource().getSubfolderPaths().toArray(new String[] {});
+                                               MultipleGetCommand.Cached[] cached = null;
+                                               if(restResource instanceof RestResourceWrapper)
+                                                       cached=((RestResourceWrapper)restResource).getResource().getCache();
+                                               MultipleGetCommand<FolderResource> gf2 = new MultipleGetCommand<FolderResource>(FolderResource.class,
+                                                                       folderPaths, cached) {
+
+                                                       @Override
+                                                       public void onComplete() {
+                                                               res = new ArrayList<RestResource>();
+                                                               for(FolderResource r : getResult()){
+                                                                       if(r.isDeleted()){
+                                                                               
+                                                                       }
+                                                                       else if(resourceClass.equals(MyFolderResource.class))
+                                                                               res.add(new MyFolderResource(r));
+                                                                       else if(resourceClass.equals(SharedFolderResource.class)){
+                                                                               res.add(new SharedFolderResource(r));
+                                                                       }
+                                                                       else if(resourceClass.equals(TrashFolderResource.class))
+                                                                               res.add(new TrashFolderResource(r));
+                                                                       else if(resourceClass.equals(OthersFolderResource.class))
+                                                                               res.add(new OthersFolderResource(r));
+                                                               }
+                                                               if(restResource instanceof RestResourceWrapper)
+                                                                       ((RestResourceWrapper)restResource).getResource().setFolders(getResult());
+                                                               updateRowCount(res.size(), true);
+                                                               updateRowData(0,res);
+                                                               if(refresh!=null)
+                                                                       refresh.onRefresh();
+                                                       }
+
+                                                       @Override
+                                                       public void onError(Throwable t) {
+                                                               GSS.get().displayError("Unable to fetch subfolders");
+                                                               GWT.log("Unable to fetch subfolders", t);
+                                                       }
+
+                                                       @Override
+                                                       public void onError(String p, Throwable throwable) {
+                                                               GWT.log("Path:"+p, throwable);
+                                                       }
+
+                                               };
+                                               DeferredCommand.addCommand(gf2);
+                                               
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               
+                                               GWT.log("Error fetching root folder", t);
+                                               GSS.get().displayError("Unable to fetch root folder");
+                                       }
+
+                               };
+                               DeferredCommand.addCommand(gf);
+                 }               
+       }
+       
+       
+       class OthersDataProvider extends AsyncDataProvider<RestResource>{
+               private RestResource restResource;
+               private Class resourceClass;
+                 public OthersDataProvider(RestResource department, Class resourceClass) {
+                   super(new ProvidesKey<RestResource>() {
+
+                               @Override
+                               public Object getKey(RestResource item) {
+                                       return item.getUri();
+                               }});
+                   this.restResource = department;
+                   this.resourceClass=resourceClass;
+                 }
+
+                 @Override
+                 protected void onRangeChanged(final HasData<RestResource> view) {
+                       refresh(null);
+                 }
+                 
+               /**
+                * Retrieve the restResource.
+                *
+                * @return the restResource
+                */
+               public RestResource getRestResource() {
+                       return restResource;
+               }
+               
+               
+               /**
+                * Modify the restResource.
+                *
+                * @param restResource the restResource to set
+                */
+               public void setRestResource(RestResource restResource) {
+                       this.restResource = restResource;
+               }
+               
+                 public void refresh(final RefreshHandler refresh){
+                         GetCommand<OthersResource> go = new GetCommand<OthersResource>(OthersResource.class,
+                          restResource.getUri(), null) {
+
+                                 @Override
+                                 public void onComplete() {
+                                         final OthersResource others = getResult();
+                          MultipleGetCommand<OtherUserResource> gogo = new MultipleGetCommand<OtherUserResource>(OtherUserResource.class,
+                                                  others.getOthers().toArray(new String[] {}), null) {
+
+                                  @Override
+                                  public void onComplete() {
+                                          List<OtherUserResource> res = getResult();
+                                          updateRowCount(res.size(), true);
+                                          List<RestResource> r = new ArrayList<RestResource>();
+                                          r.addAll(res);
+                                                                         updateRowData(0,r);
+                                  }
+
+                                  @Override
+                                  public void onError(Throwable t) {
+                                          GWT.log("Error fetching Others Root folder", t);
+                                          GSS.get().displayError("Unable to fetch Others Root folder");
+                                  }
+
+                                  @Override
+                                  public void onError(String p, Throwable throwable) {
+                                          GWT.log("Path:"+p, throwable);
+                                  }
+                          };
+                          DeferredCommand.addCommand(gogo);
+                                 }
+                       
+                                 @Override
+                                 public void onError(Throwable t) {
+                                         GWT.log("Error fetching Others Root folder", t);
+                                         GSS.get().displayError("Unable to fetch Others Root folder");
+                                 }
+                         };
+                         DeferredCommand.addCommand(go);
+                 }               
+       }
+
+
+       
+       /**
+        * Retrieve the rootNodes.
+        *
+        * @return the rootNodes
+        */
+       public ListDataProvider<RestResource> getRootNodes() {
+               return rootNodes;
+       }
+
+       
+       /**
+        * Retrieve the mymap.
+        *
+        * @return the mymap
+        */
+       public Map<String, MyFolderDataProvider> getMymap() {
+               return mymap;
+       }
+
+       
+       /**
+        * Retrieve the sharedmap.
+        *
+        * @return the sharedmap
+        */
+       public Map<String, MyFolderDataProvider> getSharedmap() {
+               return sharedmap;
+       }
+
+       
+       /**
+        * Retrieve the othersmap.
+        *
+        * @return the othersmap
+        */
+       public Map<String, MyFolderDataProvider> getOthersmap() {
+               return othersmap;
+       }
+       
+       
+       
+       
+       
+       
+}
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/client/CellTreeViewUtils.java b/src/org/gss_project/gss/web/client/CellTreeViewUtils.java
new file mode 100644 (file)
index 0000000..a4037ae
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.CellTreeView.RefreshHandler;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import com.google.gwt.user.cellview.client.CellTree;
+import com.google.gwt.user.cellview.client.TreeNode;
+
+
+/**
+ * @author kman
+ *
+ */
+public class CellTreeViewUtils {
+       CellTree tree;
+       /**
+        * 
+        */
+       public CellTreeViewUtils(CellTree tree) {
+               this.tree = tree;
+       }
+       
+       void refreshNodeContainingResource(RestResource r){
+               TreeNode node = tree.getRootTreeNode();
+               refreshNodeContainingResource(node,r);
+       }
+       
+       void refreshNodeContainingResource(String  uri){
+               TreeNode node = tree.getRootTreeNode();
+               refreshNodeContainingResource(node,uri);
+       }
+       
+       private void refreshNodeContainingResource(TreeNode node, RestResource resource){
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                       if(node.getChildValue(i).equals(resource)){
+                               if(node.getChildValue(i) instanceof RestResourceWrapper && ((RestResourceWrapper)node.getChildValue(i)).getResource().getFolders().size()==0)
+                                       return;
+                               node.setChildOpen(i, false, true);
+                               node.setChildOpen(i, true, true);
+                               return;
+                       }
+                       else if(node.isChildOpen(i)){
+                               TreeNode n = node.setChildOpen(i, true);
+                               if(n!=null)
+                                       refreshNodeContainingResource(n,resource);
+                       }
+               }
+               
+       }
+       
+       void refreshNodeContainingResource(TreeNode node, String uri){
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                       if(node.isChildOpen(i)){
+                               if(node.getChildValue(i) instanceof RestResource && ((RestResource)node.getChildValue(i)).getUri().equals(uri)){
+                                       if(node.getChildValue(i) instanceof RestResourceWrapper && ((RestResourceWrapper)node.getChildValue(i)).getResource().getFolders().size()==0)
+                                               return;
+                                       node.setChildOpen(i, false, true);
+                                       node.setChildOpen(i, true, true);
+                                       return;
+                               }
+                               else{
+                                       TreeNode n = node.setChildOpen(i, true);
+                                       if(n!=null)
+                                               refreshNodeContainingResource(n,uri);
+                               }
+                       }
+               }
+       }
+       public void openNodeContainingResource(RestResource resource){
+               TreeNode node = tree.getRootTreeNode();
+               openNodeContainingResource(node,resource);
+       }
+       private void openNodeContainingResource(TreeNode node, RestResource resource){
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                       
+                               if(node.getChildValue(i).equals(resource)){
+                                       if(node.getChildValue(i) instanceof RestResourceWrapper && ((RestResourceWrapper)node.getChildValue(i)).getResource().getFolders().size()==0)
+                                               return;
+                                       node.setChildOpen(i, true, true);
+                                       return;
+                               }
+                               else{
+                                       if(node.isChildOpen(i)){
+                                               TreeNode n = node.setChildOpen(i, true);
+                                               if(n!=null)
+                                                       openNodeContainingResource(n,resource);
+                                       }
+                               }
+                       
+               }
+       }
+       
+       public void openNodeContainingResource(RestResource resource, RefreshHandler handler){
+               TreeNode node = tree.getRootTreeNode();
+               openNodeContainingResource(node,resource,handler);
+       }
+       private void openNodeContainingResource(TreeNode node, RestResource resource, RefreshHandler handler){
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                               if(node.getChildValue(i).equals(resource)){
+                                       if(node.getChildValue(i) instanceof RestResourceWrapper && ((RestResourceWrapper)node.getChildValue(i)).getResource().getFolders().size()==0)
+                                               return;
+                                       //node.setChildOpen(i, false, true);
+                                       node.setChildOpen(i, true, true);
+                                       handler.onRefresh();
+                                       return;
+                               }
+                               else{
+                                       if(node.isChildOpen(i)){
+                                               TreeNode n = node.setChildOpen(i, true);
+                                               if(n!=null)
+                                                       openNodeContainingResource(n,resource, handler);
+                                       }
+                               }
+                       
+               }
+       }
+       
+       
+       
+       public boolean doesNodeContainsResource(TreeNode node, RestResource resource){
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                       if(node.isChildOpen(i)){
+                               if(node.getChildValue(i) instanceof RestResource && ((RestResource)node.getChildValue(i)).equals(resource)){
+                                       return true;
+                               }
+                               else if(node.isChildOpen(i)){
+                                       TreeNode n = node.setChildOpen(i, true);
+                                       if(n!=null)
+                                               return doesNodeContainsResource(n,resource);
+                               }
+                       }
+               }
+               return false;
+       }
+       
+       public boolean doesNodeContainsResource(TreeNode node, String resource){
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                       
+                               if(node.getChildValue(i) instanceof RestResource && ((RestResource)node.getChildValue(i)).getUri().equals(resource)){
+                                       return true;
+                               }
+                               else if(node.isChildOpen(i)){
+                                       TreeNode n = node.setChildOpen(i, true);
+                                       if(n!=null)
+                                               return doesNodeContainsResource(n,resource);
+                               }
+                       
+               }
+               return false;
+       }
+       
+       public TreeNode getNodeContainingResource(TreeNode node, RestResource resource){
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                       
+                               if(node.getChildValue(i) instanceof RestResource && ((RestResource)node.getChildValue(i)).getUri().equals(resource.getUri())){
+                                       return node;
+                               }
+                               else if(node.isChildOpen(i)){
+                                       TreeNode n = node.setChildOpen(i, true);
+                                       if(n!=null)
+                                               return getNodeContainingResource(n,resource);
+                               }
+                       
+               }
+               return null;
+       }
+       
+       public TreeNode getNodeContainingResource(TreeNode node, String resource){
+               if(node==null)
+                       return null;
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                       
+                               if(node.getChildValue(i) instanceof RestResource && ((RestResource)node.getChildValue(i)).getUri().equals(resource)){
+                                       return node;
+                               }
+                               else if(node.isChildOpen(i)){
+                                       TreeNode n = node.setChildOpen(i, true);
+                                       if(n!=null){
+                                               TreeNode result = getNodeContainingResource2(n,resource);
+                                               if(result !=null)
+                                                       return result;
+                                       }
+                               }
+                       
+               }
+               return null;
+       }
+       
+       public TreeNode getNodeContainingResource2(TreeNode node, String resource){
+               if(node==null)
+                       return null;
+               int count = node.getChildCount();
+               for(int i=0;i<count;i++){
+                               if(node.getChildValue(i) instanceof RestResource && ((RestResource)node.getChildValue(i)).getUri().equals(resource)){
+                                       return node.setChildOpen(i, node.isChildOpen(i));
+                               }
+                               else if(node.isChildOpen(i)){
+                                       TreeNode n = node.setChildOpen(i, true);
+                                       if(n!=null){
+                                               TreeNode result = getNodeContainingResource2(n,resource);
+                                               if(result !=null)
+                                                       return result;
+                                       }
+                               }
+                       
+               }
+               return null;
+       }
+       public boolean doesSharedNodeContainsResource( String resource){
+               if(tree.getRootTreeNode().isChildOpen(2)){
+                       TreeNode node = tree.getRootTreeNode().setChildOpen(2, true);
+                       return doesNodeContainsResource(node, resource);
+               }
+               return false;
+       }
+       
+       public boolean doesSharedNodeContainsResourceIn1stLevel( String resource){
+               if(tree.getRootTreeNode().isChildOpen(2)){
+                       TreeNode node = tree.getRootTreeNode().setChildOpen(2, true);
+                       int count = node.getChildCount();
+                       for(int i=0;i<count;i++){
+                               
+                                       if(node.getChildValue(i) instanceof RestResource && ((RestResource)node.getChildValue(i)).getUri().equals(resource)){
+                                               return true;
+                                       }
+                               
+                       }
+                       return false;
+               }
+               return false;
+       }
+       
+       public boolean doesSharedNodeContainsResourceIn2ndLevel( String resource){
+               if(tree.getRootTreeNode().isChildOpen(2)){
+                       TreeNode node = tree.getRootTreeNode().setChildOpen(2, true);
+                       int count = node.getChildCount();
+                       for(int i=0;i<count;i++){
+                               if(node.isChildOpen(i)){
+                                       TreeNode child = node.setChildOpen(i, true);
+                                       for(int j=0;j<child.getChildCount();j++){
+                                               if(child.getChildValue(j) instanceof RestResource && ((RestResource)child.getChildValue(j)).getUri().equals(resource)){
+                                                       return true;
+                                               }
+                                       }
+                               }
+                                       
+                               
+                       }
+                       return false;
+               }
+               return false;
+       }
+       
+       public boolean doesRootNodeContainsResource( String resource){
+               if(tree.getRootTreeNode().isChildOpen(0)){
+                       TreeNode node = tree.getRootTreeNode().setChildOpen(0, true);
+                       return doesNodeContainsResource(node, resource);
+               }
+               return false;
+       }
+       
+       public boolean doesSharedNodeContainsResource( RestResource resource){
+               if(tree.getRootTreeNode().isChildOpen(2)){
+                       TreeNode node = tree.getRootTreeNode().setChildOpen(2, true);
+                       return doesNodeContainsResource(node, resource);
+               }
+               return false;
+       }
+       
+       public boolean doesRootNodeContainsResource( RestResource resource){
+               if(tree.getRootTreeNode().isChildOpen(0)){
+                       TreeNode node = tree.getRootTreeNode().setChildOpen(0, true);
+                       return doesNodeContainsResource(node, resource);
+               }
+               return false;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/Configuration.java b/src/org/gss_project/gss/web/client/Configuration.java
new file mode 100644 (file)
index 0000000..c74bb52
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.i18n.client.Constants;
+
+
+/**
+ * This interface contains bindings for the compile-time configurable
+ * entities of the application.
+ *
+ * @author past
+ */
+public interface Configuration extends Constants {
+       /**
+        * @return the name of the service
+        */
+       @DefaultStringValue("GSS")
+       String serviceName();
+
+       /**
+        * @return the login URL
+        */
+       @DefaultStringValue("/gss/login")
+       String loginUrl();
+
+       /**
+        * @return the logout URL
+        */
+       @DefaultStringValue("/gss/login")
+       String logoutUrl();
+
+       /**
+        * @return the authentication cookie name
+        */
+       @DefaultStringValue("_gss_a")
+       String authCookie();
+
+       /**
+        * @return the webdav cookie name
+        */
+       @DefaultStringValue("_gss_wd")
+       String webdavCookie();
+
+       /**
+        * @return the separator string between username and token in the
+        * authentication cookie
+        */
+       @DefaultStringValue("|")
+       String cookieSeparator();
+
+       /**
+        * @return the relative path of the API root URL
+        */
+       @DefaultStringValue("rest/")
+       String apiPath();
+
+       /**
+        * @return the WebDAV URL
+        */
+       @DefaultStringValue("/webdav/")
+       String webdavUrl();
+
+       /**
+        * @return the token TTL note
+        */
+       @DefaultStringValue("")
+       String tokenTTLNote();
+
+       /**
+        * @return the version string
+        */
+       @DefaultStringValue("")
+       String version();
+
+}
diff --git a/src/org/gss_project/gss/web/client/Configuration.properties b/src/org/gss_project/gss/web/client/Configuration.properties
new file mode 100644 (file)
index 0000000..6eb1a67
--- /dev/null
@@ -0,0 +1,10 @@
+serviceName=Pithos
+loginUrl=login
+logoutUrl=/Shibboleth.sso/Logout
+authCookie=_gss_a
+webdavCookie=_gss_wd
+cookieSeparator=|
+apiPath=rest/
+webdavUrl=/webdav/
+tokenTTLNote=The token is valid for 30 days.
+version=1.5
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/client/ConfirmationDialog.java b/src/org/gss_project/gss/web/client/ConfirmationDialog.java
new file mode 100644 (file)
index 0000000..9fa7dcd
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+
+/**
+ * A dialog for requesting confirmation from the user.
+ *
+ * @author kman
+ */
+public abstract class ConfirmationDialog extends DialogBox {
+
+       /**
+        * The widget's constructor.
+        *
+        * @param message the message to display
+        * @param buttonLabel the label of the confirmation button
+        */
+       public ConfirmationDialog(String message, String buttonLabel) {
+               // Set the dialog's caption.
+               setText("Confirmation");
+               setAnimationEnabled(true);
+               // Create a VerticalPanel to contain the label and the buttons.
+               VerticalPanel outer = new VerticalPanel();
+               HorizontalPanel buttons = new HorizontalPanel();
+
+               HTML text = new HTML("<table><tr><td rowspan='2'> " +
+                               AbstractImagePrototype.create(MessagePanel.images.warn()).getHTML() +
+                               "</td><td>" + message + "</td></tr></table>");
+               text.setStyleName("gss-warnMessage");
+               outer.add(text);
+
+               // Create the 'Update' button, along with a listener that hides the
+               // dialog when the button is clicked and renames the file.
+               Button ok = new Button(buttonLabel, new ClickHandler() {
+
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               confirm();
+                               hide();
+                       }
+               });
+               ok.getElement().setId("confirmation.ok");
+               buttons.add(ok);
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);
+               // Create the 'Cancel' button, along with a listener that hides the
+               // dialog when the button is clicked.
+               Button cancel = new Button("Cancel", new ClickHandler() {
+
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               hide();
+                               cancel();
+                       }
+               });
+               cancel.getElement().setId("confirmation.cancel");
+               buttons.add(cancel);
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+               buttons.setSpacing(8);
+               buttons.setStyleName("gss-warnMessage");
+               outer.setStyleName("gss-warnMessage");
+               outer.add(buttons);
+               outer.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_CENTER);
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
+               setWidget(outer);
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+                       // Use the popup's key preview hooks to close the dialog when either
+                       // enter or escape is pressed.
+                       switch (evt.getKeyCode()) {
+                               case KeyCodes.KEY_ENTER:
+                                       hide();
+                                       confirm();
+                                       break;
+                               case KeyCodes.KEY_ESCAPE:
+                                       hide();
+                                       cancel();
+                                       break;
+                       }
+       }
+
+       public abstract void confirm();
+
+       public abstract void cancel();
+}
diff --git a/src/org/gss_project/gss/web/client/CredentialsDialog.java b/src/org/gss_project/gss/web/client/CredentialsDialog.java
new file mode 100644 (file)
index 0000000..970f25c
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.user.client.Window;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+
+/**
+ * A dialog box that displays the user credentials for use in other client
+ * applications, such as WebDAV clients.
+ *
+ * @author kman
+ */
+public class CredentialsDialog extends DialogBox {
+
+       private final String WIDTH_FIELD = "35em";
+       private final String WIDTH_TEXT = "42em";
+
+       private TextBox passwordBox;
+
+       /**
+        * The 'confirm reset password' dialog box.
+        */
+       private class ConfirmResetPasswordDialog extends DialogBox {
+
+               /**
+                * The widget's constructor.
+                *
+                * @param images the supplied images
+                */
+               private ConfirmResetPasswordDialog(MessagePanel.Images images) {
+                       // Set the dialog's caption.
+                       setText("Confirmation");
+                       setAnimationEnabled(true);
+                       // Create a VerticalPanel to contain the label and the buttons.
+                       VerticalPanel outer = new VerticalPanel();
+                       HorizontalPanel buttons = new HorizontalPanel();
+
+                       HTML text;
+                       text = new HTML("<table><tr><td>" +
+                                       AbstractImagePrototype.create(images.warn()).getHTML() +
+                                       "</td><td>" + "Are you sure you want to create a new " +
+                                       "WebDAV password?</td></tr></table>");
+                       text.setStyleName("gss-warnMessage");
+                       outer.add(text);
+
+                       // Create the 'Yes' button, along with a listener that hides the
+                       // dialog when the button is clicked and resets the password.
+                       Button ok = new Button("Yes", new ClickHandler() {
+                               @Override
+                               public void onClick(ClickEvent event) {
+                                       resetPassword(GSS.get().getCurrentUserResource().getUri());
+                                       hide();
+                               }
+                       });
+                       buttons.add(ok);
+                       buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);
+                       // Create the 'No' button, along with a listener that hides the
+                       // dialog when the button is clicked.
+                       Button cancel = new Button("No", new ClickHandler() {
+                               @Override
+                               public void onClick(ClickEvent event) {
+                                       hide();
+                               }
+                       });
+                       buttons.add(cancel);
+                       buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+                       buttons.setSpacing(8);
+                       buttons.setStyleName("gss-warnMessage");
+                       outer.setStyleName("gss-warnMessage");
+                       outer.add(buttons);
+                       outer.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_CENTER);
+                       outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
+                       setWidget(outer);
+               }
+
+               @Override
+               protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+                       super.onPreviewNativeEvent(preview);
+                       NativeEvent evt = preview.getNativeEvent();
+                       if (evt.getType().equals("keydown"))
+                               // Use the popup's key preview hooks to close the dialog when either
+                               // enter or escape is pressed.
+                               switch (evt.getKeyCode()) {
+                                       case KeyCodes.KEY_ENTER:
+                                       case KeyCodes.KEY_ESCAPE:
+                                               hide();
+                                               break;
+                               }
+               }
+
+       }
+
+       private class ReauthenticateDialog extends DialogBox {
+               /**
+                * The widget constructor.
+                */
+               public ReauthenticateDialog() {
+                       // Set the dialog's caption.
+                       setText("New Password Created");
+                       setAnimationEnabled(true);
+                       VerticalPanel outer = new VerticalPanel();
+
+                       // Create the text and set a style name so we can style it with CSS.
+                       HTML text = new HTML("<p>A new WebDAV password has been created." +
+                                       "</p><p>You will now be redirected to the initial screen" +
+                                       " for the changes to take effect. Choose \"Show " +
+                                       "Credentials\" again afterwards to see the new password.</p>");
+                       text.setStyleName("gss-AboutText");
+                       outer.add(text);
+
+                       // Create the 'OK' button, along with a listener that hides the
+                       // dialog when the button is clicked.
+                       Button confirm = new Button("Proceed", new ClickHandler() {
+                               @Override
+                               public void onClick(ClickEvent event) {
+                                       GSS.get().authenticateUser();
+                                       hide();
+                               }
+                       });
+                       outer.add(confirm);
+                       outer.setCellHorizontalAlignment(confirm, HasHorizontalAlignment.ALIGN_CENTER);
+                       outer.setSpacing(8);
+                       setWidget(outer);
+               }
+
+               @Override
+               protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+                       super.onPreviewNativeEvent(preview);
+                       NativeEvent evt = preview.getNativeEvent();
+                       if (evt.getType().equals("keydown"))
+                               // Use the popup's key preview hooks to close the dialog when
+                               // either enter or escape is pressed.
+                               switch (evt.getKeyCode()) {
+                                       case KeyCodes.KEY_ENTER:
+                                               GSS.get().authenticateUser();
+                                               hide();
+                                               break;
+                                       case KeyCodes.KEY_ESCAPE:
+                                               hide();
+                                               break;
+                               }
+               }
+
+       }
+
+       /**
+        * The widget constructor.
+        */
+       public CredentialsDialog(final MessagePanel.Images images) {
+               // Set the dialog's caption.
+               setText("User Credentials");
+               setAnimationEnabled(true);
+               // A VerticalPanel that contains the 'about' label and the 'OK' button.
+               VerticalPanel outer = new VerticalPanel();
+               Configuration conf = (Configuration) GWT.create(Configuration.class);
+               String service = conf.serviceName();
+        String path = Window.Location.getPath();
+        String baseUrl = GWT.getModuleBaseURL();
+        String homeUrl = baseUrl.substring(0, baseUrl.indexOf(path));
+               String webdavUrl = homeUrl + conf.webdavUrl();
+               String tokenNote = conf.tokenTTLNote();
+               // Create the text and set a style name so we can style it with CSS.
+               HTML text = new HTML("<p>These are the user credentials that are " +
+                               "required for interacting with " + service + ". You can copy" +
+                               " and paste the username and password in the WebDAV client " +
+                               "in order to use " + service + " through the WebDAV " +
+                               "interface, at:<br/> " + webdavUrl + "<br/>" + tokenNote +
+                               "</p>");
+               text.setStyleName("gss-AboutText");
+               text.setWidth(WIDTH_TEXT);
+               outer.add(text);
+               FlexTable table = new FlexTable();
+               table.setText(0, 0, "Username");
+               table.setText(1, 0, "Password");
+               table.setText(2, 0, "Token");
+               TextBox username = new TextBox();
+               final GSS app = GSS.get();
+               username.setText(app.getCurrentUserResource().getUsername());
+               username.setReadOnly(true);
+               username.setWidth(WIDTH_FIELD);
+               username.addClickHandler(new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               GSS.enableIESelection();
+                               ((TextBox) event.getSource()).selectAll();
+                               GSS.preventIESelection();
+                       }
+
+               });
+               table.setWidget(0, 1, username);
+               passwordBox = new TextBox();
+               passwordBox.setText(app.getWebDAVPassword());
+               passwordBox.setReadOnly(true);
+               passwordBox.setWidth(WIDTH_FIELD);
+               passwordBox.addClickHandler(new  ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               GSS.enableIESelection();
+                               ((TextBox) event.getSource()).selectAll();
+                               GSS.preventIESelection();
+                       }
+
+               });
+               table.setWidget(1, 1, passwordBox);
+
+               TextBox tokenBox = new TextBox();
+               tokenBox.setText(app.getToken());
+               tokenBox.setReadOnly(true);
+               tokenBox.setWidth(WIDTH_FIELD);
+               tokenBox.addClickHandler(new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               GSS.enableIESelection();
+                               ((TextBox) event.getSource()).selectAll();
+                               GSS.preventIESelection();
+                       }
+
+               });
+               table.setWidget(2, 1, tokenBox);
+
+               table.getFlexCellFormatter().setStyleName(0, 0, "props-labels");
+               table.getFlexCellFormatter().setStyleName(0, 1, "props-values");
+               table.getFlexCellFormatter().setStyleName(1, 0, "props-labels");
+               table.getFlexCellFormatter().setStyleName(1, 1, "props-values");
+               table.getFlexCellFormatter().setStyleName(2, 0, "props-labels");
+               table.getFlexCellFormatter().setStyleName(2, 1, "props-values");
+               outer.add(table);
+
+               // Create the 'OK' button, along with a listener that hides the dialog
+               // when the button is clicked.
+               Button confirm = new Button("Close", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               hide();
+                       }
+               });
+               outer.add(confirm);
+               outer.setCellHorizontalAlignment(confirm, HasHorizontalAlignment.ALIGN_CENTER);
+
+               // Create the 'Reset password' button, along with a listener that hides
+               // the dialog when the button is clicked.
+               Button resetPassword = new Button("Reset Password", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               ConfirmResetPasswordDialog dlg = new ConfirmResetPasswordDialog(images);
+                               dlg.center();
+                       }
+               });
+               outer.add(resetPassword);
+               outer.setCellHorizontalAlignment(resetPassword, HasHorizontalAlignment.ALIGN_CENTER);
+
+               outer.setSpacing(8);
+               setWidget(outer);
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+                       // Use the popup's key preview hooks to close the dialog when
+                       // either enter or escape is pressed.
+                       switch (evt.getKeyCode()) {
+                               case KeyCodes.KEY_ENTER:
+                               case KeyCodes.KEY_ESCAPE:
+                                       hide();
+                                       break;
+                       }
+       }
+
+
+       /**
+        * Generate an RPC request to reset WebDAV password.
+        *
+        * @param userId the Uri of the user whose password will be reset
+        */
+       private void resetPassword(String userUri) {
+
+               if (userUri == null || userUri.length() == 0) {
+                       GSS.get().displayError("Empty user Uri!");
+                       return;
+               }
+               GWT.log("resetPassword(" + userUri + ")", null);
+               PostCommand cg = new PostCommand(userUri + "?resetWebDAV", "", 200) {
+
+                       @Override
+                       public void onComplete() {
+                               ReauthenticateDialog dlg = new ReauthenticateDialog();
+                               dlg.center();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       if(statusCode == 405)
+                                               GSS.get().displayError("You don't have the necessary" +
+                                                               " permissions");
+                                       else if(statusCode == 404)
+                                               GSS.get().displayError("Resource does not exist");
+                                       else
+                                               GSS.get().displayError("Unable to reset password:" +
+                                                                       ((RestException)t).getHttpStatusText());
+                               }
+                               else
+                                       GSS.get().displayError("System error resetting password:" +
+                                                               t.getMessage());
+                       }
+               };
+               DeferredCommand.addCommand(cg);
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/DeleteFileDialog.java b/src/org/gss_project/gss/web/client/DeleteFileDialog.java
new file mode 100644 (file)
index 0000000..41ef745
--- /dev/null
@@ -0,0 +1,207 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.MessagePanel.Images;\r
+import org.gss_project.gss.web.client.rest.DeleteCommand;\r
+import org.gss_project.gss.web.client.rest.MultipleDeleteCommand;\r
+import org.gss_project.gss.web.client.rest.RestException;\r
+import org.gss_project.gss.web.client.rest.resource.FileResource;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.Event.NativePreviewEvent;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.DialogBox;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'delete file' dialog box.\r
+ */\r
+public class DeleteFileDialog extends DialogBox {\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        *\r
+        * @param images the supplied images\r
+        */\r
+       public DeleteFileDialog(Images images) {\r
+               // Set the dialog's caption.\r
+               setText("Confirmation");\r
+               setAnimationEnabled(true);\r
+               Object selection = GSS.get().getCurrentSelection();\r
+               // Create a VerticalPanel to contain the label and the buttons.\r
+               VerticalPanel outer = new VerticalPanel();\r
+               HorizontalPanel buttons = new HorizontalPanel();\r
+\r
+               HTML text;\r
+               if (selection instanceof FileResource)\r
+                       text = new HTML("<table><tr><td>" + AbstractImagePrototype.create(images.warn()).getHTML() + "</td><td>" + "Are you sure you want to <b>permanently</b> delete file '" + ((FileResource) selection).getName() + "'?</td></tr></table>");\r
+               else\r
+                       text = new HTML("<table><tr><td>" + AbstractImagePrototype.create(images.warn()).getHTML() + "</td><td>" + "Are you sure you want to <b>permanently</b> delete the selected files?</td></tr></table>");\r
+               text.setStyleName("gss-warnMessage");\r
+               outer.add(text);\r
+\r
+               // Create the 'Delete' button, along with a listener that hides the dialog\r
+               // when the button is clicked and deletes the file.\r
+               Button ok = new Button("Delete", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               deleteFile();\r
+                               hide();\r
+                       }\r
+               });\r
+               ok.getElement().setId("confirmation.ok");\r
+               buttons.add(ok);\r
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
+               // Create the 'Cancel' button, along with a listener that hides the\r
+               // dialog when the button is clicked.\r
+               Button cancel = new Button("Cancel", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               hide();\r
+                       }\r
+               });\r
+               cancel.getElement().setId("confirmation.cancel");\r
+               buttons.add(cancel);\r
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               buttons.setSpacing(8);\r
+               buttons.setStyleName("gss-warnMessage");\r
+               outer.setStyleName("gss-warnMessage");\r
+               outer.add(buttons);\r
+               outer.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_CENTER);\r
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
+               setWidget(outer);\r
+       }\r
+\r
+       /**\r
+        * Generate an RPC request to delete a file.\r
+        *\r
+        * @param userId the ID of the current user\r
+        */\r
+       private void deleteFile() {\r
+               Object selection = GSS.get().getCurrentSelection();\r
+               if (selection == null) {\r
+                       GSS.get().displayError("No file was selected");\r
+                       return;\r
+               }\r
+               if (selection instanceof FileResource) {\r
+                       FileResource file = (FileResource) selection;\r
+\r
+                       DeleteCommand df = new DeleteCommand(file.getUri()){\r
+\r
+                               @Override\r
+                               public void onComplete() {\r
+                                       GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());\r
+                                       GSS.get().getStatusPanel().updateStats();\r
+                               }\r
+\r
+                               @Override\r
+                               public void onError(Throwable t) {\r
+                                       GWT.log("", t);\r
+                                       if(t instanceof RestException){\r
+                                               int statusCode = ((RestException)t).getHttpStatusCode();\r
+                                               if(statusCode == 405)\r
+                                                       GSS.get().displayError("You don't have the necessary permissions");\r
+                                               else if(statusCode == 404)\r
+                                                       GSS.get().displayError("File not found");\r
+                                               else\r
+                                                       GSS.get().displayError("Unable to delete file: "+((RestException)t).getHttpStatusText());\r
+                                       }\r
+                                       else\r
+                                               GSS.get().displayError("System error unable to delete file: "+t.getMessage());\r
+                               }\r
+                       };\r
+\r
+                       DeferredCommand.addCommand(df);\r
+               }\r
+               else if(selection instanceof List){\r
+                       List<FileResource> files = (List<FileResource>) selection;\r
+                       List<String> fileIds = new ArrayList<String>();\r
+                       for(FileResource f : files)\r
+                               fileIds.add(f.getUri());\r
+\r
+                       MultipleDeleteCommand ed = new MultipleDeleteCommand(fileIds.toArray(new String[0])){\r
+\r
+                               @Override\r
+                               public void onComplete() {\r
+                                       GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());\r
+                               }\r
+\r
+                               @Override\r
+                               public void onError(Throwable t) {\r
+                                       GWT.log("", t);\r
+                                       GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());\r
+                               }\r
+\r
+                               @Override\r
+                               public void onError(String path, Throwable t) {\r
+                                       GWT.log("", t);\r
+                                       if(t instanceof RestException){\r
+                                               int statusCode = ((RestException)t).getHttpStatusCode();\r
+                                               if(statusCode == 405)\r
+                                                       GSS.get().displayError("You don't have the necessary permissions");\r
+                                               else if(statusCode == 404)\r
+                                                       GSS.get().displayError("File not found");\r
+                                               else\r
+                                                       GSS.get().displayError("Unable to delete file:"+((RestException)t).getHttpStatusText());\r
+                                       }\r
+                                       else\r
+                                               GSS.get().displayError("System error unable to delete file:"+t.getMessage());\r
+\r
+                               }\r
+                       };\r
+\r
+                       DeferredCommand.addCommand(ed);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
+               super.onPreviewNativeEvent(preview);\r
+\r
+               NativeEvent evt = preview.getNativeEvent();\r
+               if (evt.getType().equals("keydown"))\r
+                       // Use the popup's key preview hooks to close the dialog when either\r
+                       // enter or escape is pressed.\r
+                       switch (evt.getKeyCode()) {\r
+                               case KeyCodes.KEY_ENTER:\r
+                                       hide();\r
+                                       deleteFile();\r
+                                       break;\r
+                               case KeyCodes.KEY_ESCAPE:\r
+                                       hide();\r
+                                       break;\r
+                       }\r
+       }\r
+\r
+\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/DeleteFolderDialog.java b/src/org/gss_project/gss/web/client/DeleteFolderDialog.java
new file mode 100644 (file)
index 0000000..9e9b0be
--- /dev/null
@@ -0,0 +1,168 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.MessagePanel.Images;\r
+import org.gss_project.gss.web.client.rest.DeleteCommand;\r
+import org.gss_project.gss.web.client.rest.RestException;\r
+import org.gss_project.gss.web.client.rest.resource.FolderResource;\r
+import org.gss_project.gss.web.client.rest.resource.RestResource;\r
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;\r
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.Event.NativePreviewEvent;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.DialogBox;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'delete folder' dialog box.\r
+ */\r
+public class DeleteFolderDialog extends DialogBox {\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        * @param images the supplied images\r
+        */\r
+       public DeleteFolderDialog(Images images) {\r
+               // Set the dialog's caption.\r
+               setText("Confirmation");\r
+               setAnimationEnabled(true);\r
+               FolderResource folder = ((RestResourceWrapper) GSS.get().getTreeView().getSelection()).getResource();\r
+               // Create a VerticalPanel to contain the HTML label and the buttons.\r
+               VerticalPanel outer = new VerticalPanel();\r
+               HorizontalPanel buttons = new HorizontalPanel();\r
+\r
+               HTML text = new HTML("<table><tr><td rowspan='2'>" + AbstractImagePrototype.create(images.warn()).getHTML() +\r
+                                       "</td><td>" + "Are you sure you want to <b>permanently</b> delete folder '" + folder.getName() +\r
+                                       "'?</td></tr></table>");\r
+               text.setStyleName("gss-warnMessage");\r
+               outer.add(text);\r
+\r
+               // Create the 'Delete' button, along with a listener that hides the dialog\r
+               // when the button is clicked and deletes the folder.\r
+               Button ok = new Button("Delete", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               deleteFolder();\r
+                               hide();\r
+                       }\r
+               });\r
+               ok.getElement().setId("confirmation.ok");\r
+               buttons.add(ok);\r
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
+               // Create the 'Cancel' button, along with a listener that hides the\r
+               // dialog when the button is clicked.\r
+               Button cancel = new Button("Cancel", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               hide();\r
+                       }\r
+               });\r
+               cancel.getElement().setId("confirmation.cancel");\r
+               buttons.add(cancel);\r
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               buttons.setSpacing(8);\r
+               buttons.setStyleName("gss-warnMessage");\r
+               outer.setStyleName("gss-warnMessage");\r
+               outer.add(buttons);\r
+               outer.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_CENTER);\r
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
+               setWidget(outer);\r
+       }\r
+\r
+       /**\r
+        * Generate an RPC request to delete a folder.\r
+        *\r
+        * @param userId the ID of the current user\r
+        */\r
+       private void deleteFolder() {\r
+               RestResource folder = GSS.get().getTreeView().getSelection();\r
+               if (folder == null) {\r
+                       GSS.get().displayError("No folder was selected");\r
+                       return;\r
+               }\r
+               if(!(folder instanceof RestResourceWrapper))\r
+                       return;\r
+\r
+               DeleteCommand df = new DeleteCommand(folder.getUri()){\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               FolderResource fres = ((RestResourceWrapper) GSS.get().getTreeView().getSelection()).getResource();\r
+                               if((RestResourceWrapper) GSS.get().getTreeView().getSelection() instanceof TrashFolderResource)\r
+                                       GSS.get().getTreeView().updateTrashNode();\r
+                               else\r
+                                       GSS.get().getTreeView().updateNodeChildrenForRemove(fres.getParentURI());\r
+                               GSS.get().getTreeView().clearSelection();\r
+                               GSS.get().showFileList(true);\r
+                               \r
+                               GSS.get().getStatusPanel().updateStats();\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               if(t instanceof RestException){\r
+                                       int statusCode = ((RestException)t).getHttpStatusCode();\r
+                                       if(statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary permissions");\r
+                                       else if(statusCode == 404)\r
+                                               GSS.get().displayError("Folder not found");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to delete folder: "+((RestException)t).getHttpStatusText());\r
+                               }\r
+                               else\r
+                                       GSS.get().displayError("System error unable to delete folder: "+t.getMessage());\r
+                       }\r
+               };\r
+\r
+               DeferredCommand.addCommand(df);\r
+       }\r
+\r
+       @Override\r
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
+               super.onPreviewNativeEvent(preview);\r
+\r
+               NativeEvent evt = preview.getNativeEvent();\r
+               if (evt.getType().equals("keydown"))\r
+                       // Use the popup's key preview hooks to close the dialog when either\r
+                       // enter or escape is pressed.\r
+                       switch (evt.getKeyCode()) {\r
+                               case KeyCodes.KEY_ENTER:\r
+                                       hide();\r
+                                       deleteFolder();\r
+                                       break;\r
+                               case KeyCodes.KEY_ESCAPE:\r
+                                       hide();\r
+                                       break;\r
+                       }\r
+       }\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/DeleteGroupDialog.java b/src/org/gss_project/gss/web/client/DeleteGroupDialog.java
new file mode 100644 (file)
index 0000000..a61efa1
--- /dev/null
@@ -0,0 +1,156 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.MessagePanel.Images;\r
+import org.gss_project.gss.web.client.rest.DeleteCommand;\r
+import org.gss_project.gss.web.client.rest.RestException;\r
+import org.gss_project.gss.web.client.rest.resource.GroupResource;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.Event.NativePreviewEvent;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.DialogBox;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.TreeItem;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'delete group' dialog box.\r
+ */\r
+public class DeleteGroupDialog extends DialogBox {\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        * @param images the supplied images\r
+        */\r
+       public DeleteGroupDialog(final Images images) {\r
+               // Use this opportunity to set the dialog's caption.\r
+               setText("Delete group");\r
+               setAnimationEnabled(true);\r
+               final GroupResource group = (GroupResource) GSS.get().getCurrentSelection();\r
+               // Create a VerticalPanel to contain the 'about' label and the 'OK'\r
+               // button.\r
+               final VerticalPanel outer = new VerticalPanel();\r
+               final HorizontalPanel buttons = new HorizontalPanel();\r
+\r
+               // Create the 'about' text and set a style name so we can style it with\r
+               // CSS.\r
+               final HTML text = new HTML("<table><tr><td>" + AbstractImagePrototype.create(images.warn()).getHTML() + "</td><td>" + "Are you sure you want to delete group '" + group.getName() + "'?</td></tr></table>");\r
+               text.setStyleName("gss-warnMessage");\r
+               outer.add(text);\r
+\r
+               // Create the 'Quit' button, along with a listener that hides the dialog\r
+               // when the button is clicked and quits the application.\r
+               final Button ok = new Button("OK", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               deleteGroup();\r
+                               hide();\r
+                       }\r
+               });\r
+               ok.getElement().setId("deleteGroup.button.ok");\r
+               buttons.add(ok);\r
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
+               // Create the 'Cancel' button, along with a listener that hides the\r
+               // dialog\r
+               // when the button is clicked.\r
+               final Button cancel = new Button("Cancel", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               hide();\r
+                       }\r
+               });\r
+               cancel.getElement().setId("deleteGroup.button.cancel");\r
+               buttons.add(cancel);\r
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               buttons.setSpacing(8);\r
+               buttons.setStyleName("gss-warnMessage");\r
+               outer.setStyleName("gss-warnMessage");\r
+               outer.add(buttons);\r
+               outer.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_CENTER);\r
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
+               setWidget(outer);\r
+       }\r
+\r
+       /**\r
+        * Generate an RPC request to delete a group.\r
+        *\r
+        * @param userId the ID of the current user\r
+        */\r
+       private void deleteGroup() {\r
+               final TreeItem group = GSS.get().getGroups().getCurrent();\r
+               if (group == null) {\r
+                       GSS.get().displayError("No group was selected!");\r
+                       return;\r
+               }\r
+               DeleteCommand dg = new DeleteCommand(((GroupResource)group.getUserObject()).getUri()){\r
+                       @Override\r
+                       public void onComplete() {\r
+                               GSS.get().getGroups().updateGroups();\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               if(t instanceof RestException){\r
+                                       int statusCode = ((RestException)t).getHttpStatusCode();\r
+                                       if(statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary permissions");\r
+                                       else if(statusCode == 404)\r
+                                               GSS.get().displayError("Group not found");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to delete group:"+((RestException)t).getHttpStatusText());\r
+                               }\r
+                               else\r
+                                       GSS.get().displayError("System error unable to delete group:"+t.getMessage());\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(dg);\r
+       }\r
+\r
+\r
+       @Override\r
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
+               super.onPreviewNativeEvent(preview);\r
+\r
+               NativeEvent evt = preview.getNativeEvent();\r
+               if (evt.getType().equals("keydown"))\r
+                       // Use the popup's key preview hooks to close the dialog when either\r
+                       // enter or escape is pressed.\r
+                       switch (evt.getKeyCode()) {\r
+                               case KeyCodes.KEY_ENTER:\r
+                                       hide();\r
+                                       deleteGroup();\r
+                                       break;\r
+                               case KeyCodes.KEY_ESCAPE:\r
+                                       hide();\r
+                                       break;\r
+                       }\r
+       }\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/DeleteUserDialog.java b/src/org/gss_project/gss/web/client/DeleteUserDialog.java
new file mode 100644 (file)
index 0000000..fc26ead
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.MessagePanel.Images;
+import org.gss_project.gss.web.client.rest.DeleteCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.TreeItem;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class DeleteUserDialog extends DialogBox {
+
+       /**
+        * The widget's constructor.
+        * @param images the supplied images
+        */
+       public DeleteUserDialog(final Images images) {
+               // Use this opportunity to set the dialog's caption.
+               setText("Delete user");
+               setAnimationEnabled(true);
+               final GroupUserResource group = (GroupUserResource) GSS.get().getCurrentSelection();
+               // Create a VerticalPanel to contain the 'about' label and the 'OK'
+               // button.
+               final VerticalPanel outer = new VerticalPanel();
+               final HorizontalPanel buttons = new HorizontalPanel();
+
+               // Create the 'about' text and set a style name so we can style it with
+               // CSS.
+               final HTML text = new HTML("<table><tr><td>" + AbstractImagePrototype.create(images.warn()).getHTML() + "</td><td>" + "Are you sure you want to remove user '" + group.getName() + "'?</td></tr></table>");
+               text.setStyleName("gss-warnMessage");
+               outer.add(text);
+
+               // Create the 'Quit' button, along with a listener that hides the dialog
+               // when the button is clicked and quits the application.
+               final Button ok = new Button("OK", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               deleteUser();
+                               hide();
+                       }
+               });
+               ok.getElement().setId("deleteUser.button.ok");
+               buttons.add(ok);
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);
+               // Create the 'Cancel' button, along with a listener that hides the
+               // dialog
+               // when the button is clicked.
+               final Button cancel = new Button("Cancel", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               hide();
+                       }
+               });
+               cancel.getElement().setId("confirmation.button.cancel");
+               buttons.add(cancel);
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+               buttons.setSpacing(8);
+               buttons.setStyleName("gss-warnMessage");
+               outer.setStyleName("gss-warnMessage");
+               outer.add(buttons);
+               outer.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_CENTER);
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
+               setWidget(outer);
+       }
+
+       /**
+        * Generate an RPC request to delete a group.
+        *
+        * @param userId the ID of the current user
+        */
+       private void deleteUser() {
+               final TreeItem user = GSS.get().getGroups().getCurrent();
+               final TreeItem group = user.getParentItem();
+               if (group == null) {
+                       GSS.get().displayError("No user was selected!");
+                       return;
+               }
+               final GroupUserResource memberR = (GroupUserResource) user.getUserObject();
+               DeleteCommand du = new DeleteCommand(memberR.getUri()){
+
+                       @Override
+                       public void onComplete() {
+                               GSS.get().getGroups().updateGroups();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       if(statusCode == 405)
+                                               GSS.get().displayError("You don't have the necessary permissions");
+                                       else if(statusCode == 404)
+                                               GSS.get().displayError("User not found");
+                                       else
+                                               GSS.get().displayError("Unable to delete user:"+((RestException)t).getHttpStatusText());
+                               }
+                               else
+                                       GSS.get().displayError("System error unable to delete user:"+t.getMessage());
+                       }
+               };
+               DeferredCommand.addCommand(du);
+
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+               // Use the popup's key preview hooks to close the dialog when either
+               // enter or escape is pressed.
+               switch (evt.getKeyCode()) {
+                       case KeyCodes.KEY_ENTER:
+                               hide();
+                               deleteUser();
+                               break;
+                       case KeyCodes.KEY_ESCAPE:
+                               hide();
+                               break;
+               }
+       }
+
+}
+
diff --git a/src/org/gss_project/gss/web/client/DisplayHelper.java b/src/org/gss_project/gss/web/client/DisplayHelper.java
new file mode 100644 (file)
index 0000000..9619b0b
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import java.util.List;
+
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.ListBox;
+
+
+/**
+ * A helper class with static methods that manipulate display
+ * widgets in various useful ways, not available in GWT.
+ *
+ * @author past
+ */
+public class DisplayHelper {
+
+       /**
+        * A flag that denotes that no selection should be made while
+        * displaying the rows of a table.
+        */
+       public static final int NO_SELECTION = -1;
+
+       /**
+        * Clear any current selection in the specified ListBox.
+        */
+       public static void clearSelections(ListBox listBox) {
+               for (int i=0; i<listBox.getItemCount(); i++)
+                       if (listBox.isItemSelected(i))
+                               listBox.setItemSelected(i, false);
+       }
+
+       /**
+        * Select the item in the listBox whose value matches the provided
+        * value.
+        */
+       public static void selectMatch(ListBox listBox, String value) {
+               for (int i=0; i<listBox.getItemCount(); i++)
+                       if (listBox.getValue(i).equals(value))
+                               listBox.setItemSelected(i, true);
+                       else
+                               listBox.setItemSelected(i, false);
+       }
+
+       /**
+        * Select the items in the listBox whose value matches the provided
+        * value list. Every value that is matched in the listBox is removed
+        * from the value list, in order to let the caller know what values
+        * were not matched. Therefore the caller must be prepared for the
+        * value list to be modified.
+        *
+        * @param listBox the ListBox
+        * @param values the list of values to be selected
+        */
+       public static void selectMultiMatch(ListBox listBox, List values) {
+               for (int i=0; i<listBox.getItemCount(); i++)
+                       if (values.contains(listBox.getValue(i))) {
+                               listBox.setItemSelected(i, true);
+                               values.remove(listBox.getValue(i));
+                       } else
+                               listBox.setItemSelected(i, false);
+       }
+
+       public static native void log(String message) /*-{
+               var logger = $wnd.console;
+               if (logger && logger.debug)
+                       logger.debug(message);
+               else if (logger && logger.log)
+                       logger.log(message);
+       }-*/;
+
+       /**
+        * Make the specified row look like selected or not, according to the
+        * <code>selected</code> flag.
+        *
+        * @param row the row number in the list of entries (i.e. ignoring the header line)
+        * @param selected the flag that denotes whether the <code>styleName</code> should
+        *                              be added or removed
+        * @param styleName the name of the CSS style
+        */
+       public static void styleRow(final FlexTable table, final int row, final boolean selected, String styleName) {
+               if (row != -1)
+                       if (selected)
+                               table.getRowFormatter().addStyleName(row + 1, styleName);
+                       else
+                               table.getRowFormatter().removeStyleName(row + 1, styleName);
+       }
+
+       /**
+        * Select the specified row in the table. This entails modifying its style
+        * as well as the style of the previously selected row.
+        *
+        * @param table the FlexTable widget
+        * @param row the newly selected row
+        * @param previousRow the previously selected row
+        * @param styleName the name of the CSS style
+        * @return the newly selected row
+        */
+       public static int selectRow(final FlexTable table, final int row, final int previousRow, String styleName) {
+               // Reset the style of the previously selected row.
+               styleRow(table, previousRow, false, styleName);
+               // Select the row that was clicked.
+               styleRow(table, row, true, styleName);
+               return row;
+       }
+       /**
+        * The implementation of this trim method also checks for
+        * no brake space characters (nbsp) = '\00A0'
+        * and removes them
+        *
+        * @param input
+        * @return the new trimmed string without whitespace or no brake space
+        */
+       public static native String trim(String input) /*-{
+    if(input.length == 0)
+       return input;
+       if((input[0]||input[input.length-1]) != '\u0020' && (input[0]||input[input.length-1]) != '\u00A0')
+       return input;
+    var r1 = input.replace(/^(\s*)/, '');
+    var r2 = r1.replace(/\s*$/, '');
+    return r2;
+  }-*/;
+
+}
diff --git a/src/org/gss_project/gss/web/client/DnDFolderPopupMenu.java b/src/org/gss_project/gss/web/client/DnDFolderPopupMenu.java
new file mode 100644 (file)
index 0000000..dc6691e
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import org.gss_project.gss.web.client.rest.MultiplePostCommand;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * @author kman
+ */
+public class DnDFolderPopupMenu extends PopupPanel {
+
+        public DnDFolderPopupMenu(final CellTreeView.Images newImages, final FolderResource target, final Object toCopy) {
+                // The popup's constructor's argument is a boolean specifying that it
+                // auto-close itself when the user clicks outside of it.
+                super(true);
+                setAnimationEnabled(true);
+                // A dummy command that we will execute from unimplemented leaves.
+                final Command cancelCmd = new Command() {
+
+                        @Override
+                        public void execute() {
+                                hide();
+                        }
+                };
+
+                final MenuBar contextMenu = new MenuBar(true);
+                final CellTreeView folders = GSS.get().getTreeView();
+
+                contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Move</span>", true, new Command() {
+
+                                @Override
+                                public void execute() {
+                                        if (toCopy instanceof RestResourceWrapper){
+                                                moveFolder(target, ((RestResourceWrapper) toCopy).getResource());
+                                        }
+                                        else if(toCopy instanceof List){
+                                               List<FileResource> files = GSS.get().getFileList().getSelectedFiles();
+                                                moveFiles(target, files);
+                                        }
+                                        hide();
+                                }
+
+                        }).setVisible(target != null);
+
+                contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new Command() {
+
+                        @Override
+                        public void execute() {
+                                if (toCopy instanceof RestResourceWrapper)
+                                        copyFolder(target, ((RestResourceWrapper) toCopy).getResource());
+                                else if(toCopy instanceof List){
+                                       List<FileResource> files = GSS.get().getFileList().getSelectedFiles();
+                                    copyFiles(target, files);
+                                }
+                                hide();
+                        }
+
+                }).setVisible(target != null);
+
+                contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.trash()).getHTML() + "&nbsp;Delete (Trash)</span>", true, new Command() {
+
+                        @Override
+                        public void execute() {
+                               GWT.log("EXECUTE TRASH:"+toCopy.getClass().getName());
+                                if (toCopy instanceof RestResourceWrapper){
+                                        trashFolder(((RestResourceWrapper) toCopy).getResource());
+                                }
+                                else if(toCopy instanceof List){
+                                       List<FileResource> files = GSS.get().getFileList().getSelectedFiles();
+                                    trashFiles(files);
+                                }
+                                hide();
+                        }
+
+                }).setVisible(target == null);
+                contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Cancel</span>", true, cancelCmd);
+
+                add(contextMenu);
+
+        }
+
+        private void copyFolder(final FolderResource target, FolderResource toCopy) {
+                String atarget = target.getUri();
+                atarget = atarget.endsWith("/") ? atarget : atarget + '/';
+                atarget = atarget + toCopy.getName();
+                PostCommand cf = new PostCommand(toCopy.getUri() + "?copy=" + atarget, "", 200) {
+
+                        @Override
+                        public void onComplete() {
+                                       GSS.get().getTreeView().updateNodeChildren(new RestResourceWrapper(target));
+                                                               GSS.get().getStatusPanel().updateStats();
+                        }
+
+                        @Override
+                        public void onError(Throwable t) {
+                                GWT.log("", t);
+                                if (t instanceof RestException) {
+                                        int statusCode = ((RestException) t).getHttpStatusCode();
+                                        if (statusCode == 405)
+                                                GSS.get().displayError("You don't have the necessary permissions");
+
+                                        else if (statusCode == 409)
+                                                GSS.get().displayError("A folder with the same name already exists");
+                                        else if (statusCode == 413)
+                                                GSS.get().displayError("Your quota has been exceeded");
+                                        else
+                                                GSS.get().displayError("Unable to copy folder:" + ((RestException)t).getHttpStatusText());
+                                } else
+                                        GSS.get().displayError("System error copying folder:" + t.getMessage());
+                        }
+                };
+                DeferredCommand.addCommand(cf);
+        }
+
+        private void moveFolder(final FolderResource target, final FolderResource toCopy) {
+                String atarget = target.getUri();
+                atarget = atarget.endsWith("/") ? atarget : atarget + '/';
+                atarget = atarget + toCopy.getName();
+
+                PostCommand cf = new PostCommand(toCopy.getUri() + "?move=" + atarget, "", 200) {
+
+                        @Override
+                        public void onComplete() {
+                               GWT.log("[MOVE]"+target.getUri()+"   "+ toCopy.getParentURI());
+                               GSS.get().getTreeView().updateNodeChildren(new RestResourceWrapper(target));
+                                                       GSS.get().getTreeView().updateNodeChildrenForRemove(toCopy.getParentURI());
+                                                       GSS.get().getStatusPanel().updateStats();
+                        }
+
+                        @Override
+                        public void onError(Throwable t) {
+                                GWT.log("", t);
+                                if (t instanceof RestException) {
+                                        int statusCode = ((RestException) t).getHttpStatusCode();
+                                        if (statusCode == 405)
+                                                GSS.get().displayError("You don't have the necessary permissions");
+
+                                        else if (statusCode == 409)
+                                                GSS.get().displayError("A folder with the same name already exists");
+                                        else if (statusCode == 413)
+                                                GSS.get().displayError("Your quota has been exceeded");
+                                        else
+                                                GSS.get().displayError("Unable to copy folder:" + ((RestException)t).getHttpStatusText());
+                                } else
+                                        GSS.get().displayError("System error copying folder:" + t.getMessage());
+                        }
+                };
+                DeferredCommand.addCommand(cf);
+        }
+
+        private void copyFiles(final FolderResource ftarget, List<FileResource> files) {
+                List<String> fileIds = new ArrayList<String>();
+                String target = ftarget.getUri();
+                target = target.endsWith("/") ? target : target + '/';
+                for (FileResource fileResource : files) {
+                        String fileTarget = target + URL.encodeComponent(fileResource.getName());
+                        fileIds.add(fileResource.getUri() + "?copy=" + fileTarget);
+                }
+                int index = 0;
+                executeCopyOrMoveFiles(index, fileIds);
+
+        }
+
+        private void moveFiles(final FolderResource ftarget, List<FileResource> files) {
+                List<String> fileIds = new ArrayList<String>();
+                String target = ftarget.getUri();
+                target = target.endsWith("/") ? target : target + '/';
+                for (FileResource fileResource : files) {
+                        String fileTarget = target + URL.encodeComponent(fileResource.getName());
+                        fileIds.add(fileResource.getUri() + "?move=" + fileTarget);
+                }
+                int index = 0;
+                executeCopyOrMoveFiles(index, fileIds);
+
+        }
+
+        private void trashFolder(final FolderResource folder){
+                PostCommand tot = new PostCommand(folder.getUri()+"?trash=","",200){
+
+                        @Override
+                        public void onComplete() {
+                               GSS.get().getTreeView().updateNodeChildrenForRemove(folder.getParentURI());
+                               GSS.get().getTreeView().updateTrashNode();
+                                /*for(TreeItem item : items)
+                                        GSS.get().getFolders().updateFolder((DnDTreeItem) item);
+                                GSS.get().getFolders().update(GSS.get().getFolders().getTrashItem());
+                               
+                                GSS.get().showFileList(true);
+                                */
+                        }
+
+                        @Override
+                        public void onError(Throwable t) {
+                                GWT.log("", t);
+                                if(t instanceof RestException){
+                                        int statusCode = ((RestException)t).getHttpStatusCode();
+                                        if(statusCode == 405)
+                                                GSS.get().displayError("You don't have the necessary permissions");
+                                        else if(statusCode == 404)
+                                                GSS.get().displayError("Folder does not exist");
+                                        else
+                                                GSS.get().displayError("Unable to trash folder:"+((RestException)t).getHttpStatusText());
+                                }
+                                else
+                                        GSS.get().displayError("System error trashing folder:"+t.getMessage());
+                        }
+                };
+                DeferredCommand.addCommand(tot);
+        }
+
+        private void trashFiles(List<FileResource> files){
+                final List<String> fileIds = new ArrayList<String>();
+                for(FileResource f : files)
+                        fileIds.add(f.getUri()+"?trash=");
+                MultiplePostCommand tot = new MultiplePostCommand(fileIds.toArray(new String[0]),200){
+
+                        @Override
+                        public void onComplete() {
+                                GSS.get().showFileList(true);
+                        }
+
+                        @Override
+                        public void onError(String p, Throwable t) {
+                                GWT.log("", t);
+                                if(t instanceof RestException){
+                                        int statusCode = ((RestException)t).getHttpStatusCode();
+                                        if(statusCode == 405)
+                                                GSS.get().displayError("You don't have the necessary permissions");
+                                        else if(statusCode == 404)
+                                                GSS.get().displayError("File does not exist");
+                                        else
+                                                GSS.get().displayError("Unable to trash file:"+((RestException)t).getHttpStatusText());
+                                }
+                                else
+                                        GSS.get().displayError("System error trashing file:"+t.getMessage());
+                        }
+                };
+                DeferredCommand.addCommand(tot);
+        }
+
+
+        private void executeCopyOrMoveFiles(final int index, final List<String> paths) {
+                if (index >= paths.size()) {
+                        GSS.get().showFileList(true);
+                        GSS.get().getStatusPanel().updateStats();
+                        return;
+                }
+                PostCommand cf = new PostCommand(paths.get(index), "", 200) {
+
+                        @Override
+                        public void onComplete() {
+                                executeCopyOrMoveFiles(index + 1, paths);
+                        }
+
+                        @Override
+                        public void onError(Throwable t) {
+                                GWT.log("", t);
+                                if (t instanceof RestException) {
+                                        int statusCode = ((RestException) t).getHttpStatusCode();
+                                        if (statusCode == 405)
+                                                GSS.get().displayError("You don't have the necessary permissions");
+                                        else if (statusCode == 404)
+                                                GSS.get().displayError("File not found");
+                                        else if (statusCode == 409)
+                                                GSS.get().displayError("A file with the same name already exists");
+                                        else if (statusCode == 413)
+                                                GSS.get().displayError("Your quota has been exceeded");
+                                        else
+                                                GSS.get().displayError("Unable to copy file:" + ((RestException)t).getHttpStatusText());
+                                } else
+                                        GSS.get().displayError("System error copying file:" + t.getMessage());
+
+                        }
+                };
+                DeferredCommand.addCommand(cf);
+        }
+
+}
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/client/EditMenu.java b/src/org/gss_project/gss/web/client/EditMenu.java
new file mode 100644 (file)
index 0000000..aab1515
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.commands.CopyCommand;
+import org.gss_project.gss.web.client.commands.CutCommand;
+import org.gss_project.gss.web.client.commands.DeleteCommand;
+import org.gss_project.gss.web.client.commands.PasteCommand;
+import org.gss_project.gss.web.client.commands.ToTrashCommand;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.List;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * The 'Edit' menu implementation.
+ */
+public class EditMenu extends PopupPanel implements ClickHandler {
+
+       /**
+        * The widget's images.
+        */
+       private final Images images;
+
+       private final MenuBar contextMenu  = new MenuBar(true);
+
+       /**
+        * An image bundle for this widget's images.
+        */
+       public interface Images extends ClientBundle, FileMenu.Images, MessagePanel.Images {
+
+               /**
+                * Will bundle the file 'editcut.png' residing in the package
+                * 'org.gss_project.gss.web.resources'.
+                *
+                * @return the image prototype
+                */
+               @Source("org/gss_project/gss/resources/editcut.png")
+               ImageResource cut();
+
+               /**
+                * Will bundle the file 'editcopy.png' residing in the package
+                * 'org.gss_project.gss.web.resources'.
+                *
+                * @return the image prototype
+                */
+               @Source("org/gss_project/gss/resources/editcopy.png")
+               ImageResource copy();
+
+               /**
+                * Will bundle the file 'editpaste.png' residing in the package
+                * 'org.gss_project.gss.web.resources'.
+                *
+                * @return the image prototype
+                */
+               @Source("org/gss_project/gss/resources/editpaste.png")
+               ImageResource paste();
+
+               /**
+                * Will bundle the file 'editdelete.png' residing in the package
+                * 'org.gss_project.gss.web.resources'.
+                *
+                * @return the image prototype
+                */
+               @Override
+               @Source("org/gss_project/gss/resources/editdelete.png")
+               ImageResource delete();
+
+               /**
+                * Will bundle the file 'translate.png' residing in the package
+                * 'org.gss_project.gss.web.resources'.
+                *
+                * @return the image prototype
+                */
+               @Source("org/gss_project/gss/resources/translate.png")
+               ImageResource selectAll();
+
+               /**
+                * Will bundle the file 'border_remove.png' residing in the package
+                * 'org.gss_project.gss.web.resources'.
+                *
+                * @return the image prototype
+                */
+               @Source("org/gss_project/gss/resources/border_remove.png")
+               ImageResource unselectAll();
+       }
+
+       /**
+        * The widget's constructor.
+        *
+        * @param newImages the image bundle passed on by the parent object
+        */
+       public EditMenu(final Images newImages) {
+               // The popup's constructor's argument is a boolean specifying that it
+               // auto-close itself when the user clicks outside of it.
+               super(true);
+               setAnimationEnabled(true);
+               images = newImages;
+               createMenu();
+               add(contextMenu);
+       }
+
+       @Override
+       public void onClick(ClickEvent event) {
+               final EditMenu menu = new EditMenu(images);
+               final int left = event.getRelativeElement().getAbsoluteLeft();
+               final int top = event.getRelativeElement().getAbsoluteTop() + event.getRelativeElement().getOffsetHeight();
+               menu.setPopupPosition(left, top);
+               menu.show();
+       }
+
+       public MenuBar createMenu() {
+               contextMenu.clearItems();
+               contextMenu.setAutoOpen(false);
+
+               final Command selectAllCommand = new Command() {
+
+                       @Override
+                       public void execute() {
+                               hide();
+                               if(GSS.get().isFileListShowing())
+                                       GSS.get().getFileList().selectAllRows();
+                               else if(GSS.get().isSearchResultsShowing())
+                                       GSS.get().getSearchResults().selectAllRows();
+                       }
+               };
+               final Command unselectAllCommand = new Command() {
+
+                       @Override
+                       public void execute() {
+                               hide();
+                               if(GSS.get().isFileListShowing())
+                                       GSS.get().getFileList().clearSelectedRows();
+                               else if(GSS.get().isSearchResultsShowing())
+                                       GSS.get().getSearchResults().clearSelectedRows();
+                       }
+               };
+
+               boolean cutcopyVisible = GSS.get().getCurrentSelection() != null && (GSS.get().getCurrentSelection() instanceof RestResourceWrapper
+                                       || GSS.get().getCurrentSelection() instanceof FileResource || GSS       .get().getCurrentSelection() instanceof GroupUserResource || GSS        .get().getCurrentSelection() instanceof List);
+               String cutLabel = "Cut";
+               String copyLabel ="Copy";
+               String pasteLabel = "Paste";
+               if(GSS.get().getCurrentSelection() != null)
+                       if(GSS.get().getCurrentSelection() instanceof RestResourceWrapper){
+                               cutLabel = "Cut Folder";
+                               copyLabel = "Copy Folder";
+                       }
+                       else if(GSS.get().getCurrentSelection() instanceof FileResource){
+                               cutLabel = "Cut File";
+                               copyLabel = "Copy File";
+                       }
+                       else if(GSS.get().getCurrentSelection() instanceof List){
+                               cutLabel = "Cut Files";
+                               copyLabel = "Copy Files";
+                       }
+               if(GSS.get().getClipboard().getItem() != null)
+                       if(GSS.get().getClipboard().getItem().getFile() != null)
+                               pasteLabel = "Paste File";
+                       else if(GSS.get().getClipboard().getItem().getFiles() != null)
+                               pasteLabel = "Paste Files";
+                       else if(GSS.get().getClipboard().getItem().getRestResourceWrapper() != null)
+                               pasteLabel = "Paste Folder";
+               MenuItem cutItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.cut()).getHTML() + "&nbsp;"+cutLabel+"</span>", true, new CutCommand(this));
+               cutItem.getElement().setId("topMenu.edit.cut");
+               contextMenu.addItem(cutItem).setVisible(cutcopyVisible);
+               
+               MenuItem copyItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.copy()).getHTML() + "&nbsp;"+copyLabel+"</span>", true, new CopyCommand(this));
+               copyItem.getElement().setId("topMenu.edit.copy");
+               contextMenu.addItem(copyItem).setVisible(cutcopyVisible);
+
+               MenuItem pasteItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.paste()).getHTML() + "&nbsp;"+pasteLabel+"</span>", true, new PasteCommand(this));                            
+               pasteItem.getElement().setId("topMenu.edit.paste");
+               if (GSS.get().getClipboard().getItem() != null)
+                       if(GSS.get().isUserListVisible() && GSS.get().getClipboard().getItem().getUser() == null){
+                               contextMenu.addItem(pasteItem);
+                       }
+                       else if(!GSS.get().isUserListVisible() && GSS.get().getClipboard().getItem().getUser() != null){
+                               //do not show paste
+                       }
+                       else if (GSS.get().getTreeView().getSelection() instanceof RestResourceWrapper){
+                               contextMenu.addItem(pasteItem);
+                       }
+               MenuItem moveToTrashItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(this));
+               moveToTrashItem.getElement().setId("topMenu.edit.moveToTrash");
+               contextMenu     .addItem(moveToTrashItem)
+                                       .setVisible(cutcopyVisible);
+               
+               MenuItem deleteItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, images));
+               deleteItem.getElement().setId("topMenu.edit.delete");
+               contextMenu     .addItem(deleteItem)
+                                       .setVisible(cutcopyVisible);
+               
+               MenuItem selectAllItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.selectAll()).getHTML() + "&nbsp;Select All</span>", true, selectAllCommand);
+               selectAllItem.getElement().setId("topMenu.edit.selectAll");
+               contextMenu.addItem(selectAllItem);
+               
+               MenuItem unSelectAllItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.unselectAll()).getHTML() + "&nbsp;Unselect All</span>", true, unselectAllCommand);
+               unSelectAllItem.getElement().setId("topMenu.edit.unSelectAll");
+               contextMenu.addItem(unSelectAllItem);
+               return contextMenu;
+       }
+
+
+
+}
diff --git a/src/org/gss_project/gss/web/client/FileContextMenu.java b/src/org/gss_project/gss/web/client/FileContextMenu.java
new file mode 100644 (file)
index 0000000..d279dd3
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.commands.CopyCommand;
+import org.gss_project.gss.web.client.commands.CutCommand;
+import org.gss_project.gss.web.client.commands.DeleteCommand;
+import org.gss_project.gss.web.client.commands.PasteCommand;
+import org.gss_project.gss.web.client.commands.PropertiesCommand;
+import org.gss_project.gss.web.client.commands.RefreshCommand;
+import org.gss_project.gss.web.client.commands.RestoreTrashCommand;
+import org.gss_project.gss.web.client.commands.ToTrashCommand;
+import org.gss_project.gss.web.client.commands.UploadFileCommand;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;
+
+import java.util.List;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.ContextMenuEvent;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * The 'File Context' menu implementation.
+ */
+public class FileContextMenu extends PopupPanel implements ClickHandler {
+
+       /**
+        * The widget's images.
+        */
+       private final Images images;
+
+       private MenuItem cutItem;
+
+       private MenuItem copyItem;
+
+       private MenuItem pasteItem;
+
+       private MenuItem updateItem;
+
+       private MenuItem sharingItem;
+
+       private MenuItem propItem;
+
+       private MenuItem trashItem;
+
+       private MenuItem deleteItem;
+
+       private MenuItem downloadItem;
+
+       private MenuItem saveAsItem;
+
+       /**
+        * The image bundle for this widget's images that reuses images defined in
+        * other menus.
+        */
+       public interface Images extends ClientBundle,FileMenu.Images, EditMenu.Images {
+
+               @Source("org/gss_project/gss/resources/mimetypes/document.png")
+               ImageResource fileContextMenu();
+
+               @Source("org/gss_project/gss/resources/doc_versions.png")
+               ImageResource versions();
+
+               @Override
+               @Source("org/gss_project/gss/resources/group.png")
+               ImageResource sharing();
+
+               @Override
+               @Source("org/gss_project/gss/resources/border_remove.png")
+               ImageResource unselectAll();
+
+               @Source("org/gss_project/gss/resources/demo.png")
+               ImageResource viewImage();
+}
+
+       public static native String getDate()/*-{
+               return (new Date()).toUTCString();
+       }-*/;
+
+       /**
+        * The widget's constructor.
+        *
+        * @param newImages the image bundle passed on by the parent object
+        */
+       public FileContextMenu(Images newImages, boolean isTrash, boolean isEmpty) {
+               // The popup's constructor's argument is a boolean specifying that it
+               // auto-close itself when the user clicks outside of it.
+               super(true);
+               GSS gss = GSS.get();
+               setAnimationEnabled(true);
+               images = newImages;
+
+               // The command that does some validation before downloading a file.
+               Command downloadCmd = new Command() {
+
+                       @Override
+                       public void execute() {
+                               hide();
+                               GSS.get().getTopPanel().getFileMenu().preDownloadCheck();
+                       }
+               };
+
+               pasteItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.paste()).getHTML() + "&nbsp;Paste</span>", true, new PasteCommand(this));
+               pasteItem.getElement().setId("FileContextMenu.paste");
+               RestResource sel = GSS.get().getTreeView().getSelection();
+               MenuBar contextMenu = new MenuBar(true);
+               if (isEmpty) {
+                       contextMenu.addItem(pasteItem);
+                       if (sel != null)
+                               /*TODO:CELLTREE
+                               if (GSS.get().getTreeView().isFileItem(GSS.get().getTreeView().getCurrent()))
+                                       contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                               else if (GSS.get().getTreeView().isMySharedItem(GSS.get().getTreeView().getCurrent()) || GSS    .get()
+                                                                                                                                                                                                                       .getTreeView()
+                                                                                                                                                                                                                       .isOthersSharedItem(GSS .get()
+                                                                                                                                                                                                                                                                       .getTreeView()
+                                                                                                                                                                                                                                                                       .getCurrent()))
+                                       if(sel instanceof FolderResource)
+                                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                       */
+                       if(sel instanceof RestResourceWrapper && !(sel instanceof TrashFolderResource)){
+                               MenuItem upload = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                               upload.getElement().setId("fileContextMenu.upload");
+                               contextMenu.addItem(upload);
+                       }
+                       MenuItem refresh = new MenuItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                       refresh.getElement().setId("fileContextMenu.refresh");
+                       contextMenu.addItem(refresh);
+                       
+               } else if (isTrash) {
+                       MenuItem restore = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.versions()).getHTML() + "&nbsp;Restore</span>", true, new RestoreTrashCommand(this));
+                       restore.getElement().setId("fileContextMenu.restore");
+                       contextMenu.addItem(restore);
+                       
+                       MenuItem delete = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, images));
+                       delete.getElement().setId("fileContextMenu.delete");
+                       contextMenu.addItem(delete);
+               } else {
+                       final Command unselectAllCommand = new Command() {
+
+                               @Override
+                               public void execute() {
+                                       hide();
+                                       if(GSS.get().isFileListShowing())
+                                               GSS.get().getFileList().clearSelectedRows();
+                                       else if(GSS.get().isSearchResultsShowing())
+                                               GSS.get().getSearchResults().clearSelectedRows();
+                               }
+                       };
+                       cutItem = new MenuItem("<span id='fileContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(this));
+                       cutItem.getElement().setId("fileContextMenu.cut");
+                       
+                       copyItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(this));
+                       copyItem.getElement().setId("fileContextMenu.copy");
+                       
+                       updateItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                       updateItem.getElement().setId("fileContextMenu.upload");
+
+                       trashItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(this));
+                       trashItem.getElement().setId("fileContextMenu.moveToTrash");
+                       
+                       deleteItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, images));
+                       deleteItem.getElement().setId("fileContextMenu.delete");
+
+                       sharingItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, images, 1));
+                       sharingItem.getElement().setId("fileContextMenu.sharing");
+                       
+                       propItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(this, images, 0));
+                       propItem.getElement().setId("fileContextMenu.properties");
+
+                       
+                       if(sel!=null && sel instanceof FolderResource)
+                               contextMenu.addItem(updateItem);
+                       String[] link = {"", ""};
+                       gss.getTopPanel().getFileMenu().createDownloadLink(link, false);
+                       downloadItem = new MenuItem("<span>" + link[0] + AbstractImagePrototype.create(newImages.download()).getHTML() + " Download" + link[1] + "</span>", true, downloadCmd);
+                       downloadItem.getElement().setId("fileContextMenu.download");
+                       contextMenu.addItem(downloadItem);
+                       
+                       gss.getTopPanel().getFileMenu().createDownloadLink(link, true);
+                       saveAsItem = new MenuItem("<span>" + link[0] + AbstractImagePrototype.create(newImages.download()).getHTML() + " Save As" + link[1] + "</span>", true, downloadCmd);
+                       saveAsItem.getElement().setId("fileContextMenu.saveAs");
+                       contextMenu.addItem(saveAsItem);
+                       contextMenu.addItem(cutItem);
+                       contextMenu.addItem(copyItem);
+                       if(sel!=null && sel instanceof FolderResource)
+                               contextMenu.addItem(pasteItem);
+                       MenuItem unSelect = new MenuItem("<span>" + AbstractImagePrototype.create(images.unselectAll()).getHTML() + "&nbsp;Unselect</span>", true, unselectAllCommand);
+                       unSelect.getElement().setId("fileContextMenu.unSelect");
+                       contextMenu.addItem(unSelect);
+                       
+                       contextMenu.addItem(trashItem);
+                       contextMenu.addItem(deleteItem);
+                       
+                       MenuItem refresh = new MenuItem("<span id='fileContextMenu.refresh'>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                       refresh.getElement().setId("fileContextMenu.refresh");
+                       contextMenu.addItem(refresh);
+                       
+                       contextMenu.addItem(sharingItem);
+                       contextMenu.addItem(propItem);
+               }
+               add(contextMenu);
+               if (gss.getClipboard().hasFileItem())
+                       pasteItem.setVisible(true);
+               else
+                       pasteItem.setVisible(false);
+       }
+
+       void onMultipleSelection() {
+               updateItem.setVisible(false);
+               downloadItem.setVisible(false);
+               saveAsItem.setVisible(false);
+               sharingItem.setVisible(false);
+       }
+       @Override
+       public void onClick(ClickEvent event) {
+               if (GSS.get().getCurrentSelection() != null)
+                       if (GSS.get().getCurrentSelection() instanceof FileResource) {
+                               FileResource res = (FileResource) GSS.get().getCurrentSelection();
+                               FileContextMenu menu;
+                               if (res.isDeleted())
+                                       menu = new FileContextMenu(images, true, false);
+                               else
+                                       menu = new FileContextMenu(images, false, false);
+                               int left = event.getRelativeElement().getAbsoluteLeft();
+                               int top = event.getRelativeElement().getAbsoluteTop() + event.getRelativeElement().getOffsetHeight();
+                               menu.setPopupPosition(left, top);
+                               menu.show();
+                       } else if (GSS.get().getCurrentSelection() instanceof List) {
+                               FileContextMenu menu;
+                               /*TODO: CELLTREE
+                               if (GSS.get().getTreeView().isTrashItem(GSS.get().getTreeView().getCurrent()))
+                                       menu = new FileContextMenu(images, true, false);
+                               else {
+                                       menu = new FileContextMenu(images, false, false);
+                                       menu.onMultipleSelection();
+                               }
+                               */
+                               menu = new FileContextMenu(images, false, false);
+                               menu.onMultipleSelection();
+                               int left = event.getRelativeElement().getAbsoluteLeft();
+                               int top = event.getRelativeElement().getAbsoluteTop() + event.getRelativeElement().getOffsetHeight();
+                               menu.setPopupPosition(left, top);
+                               menu.show();
+                       }
+       }
+
+       
+       public void onContextEvent(ContextMenuEvent event) {
+               if (GSS.get().getCurrentSelection() != null)
+                       if (GSS.get().getCurrentSelection() instanceof FileResource) {
+                               FileResource res = (FileResource) GSS.get().getCurrentSelection();
+                               FileContextMenu menu;
+                               if (res.isDeleted())
+                                       menu = new FileContextMenu(images, true, false);
+                               else
+                                       menu = new FileContextMenu(images, false, false);
+                               int left = event.getNativeEvent().getClientX();
+                               int top = event.getNativeEvent().getClientY();
+                               menu.setPopupPosition(left, top);
+                               menu.show();
+
+                       } else if (GSS.get().getCurrentSelection() instanceof List) {
+                               FileContextMenu menu;
+                               /*TODO: CELLTREE
+                               if (GSS.get().getTreeView().isTrashItem(GSS.get().getTreeView().getCurrent()))
+                                       menu = new FileContextMenu(images, true, false);
+                               else {
+                                       menu = new FileContextMenu(images, false, false);
+                                       menu.onMultipleSelection();
+                               }
+                               */
+                               int left = event.getNativeEvent().getClientX();
+                               int top = event.getNativeEvent().getClientY();
+                               //menu.setPopupPosition(left, top);
+                               //menu.show();
+                       }
+       }
+
+       public FileContextMenu onEvent(Event event) {
+               FileContextMenu menu=null;
+               if (GSS.get().getCurrentSelection() != null)
+                       if (GSS.get().getCurrentSelection() instanceof FileResource) {
+                               FileResource res = (FileResource) GSS.get().getCurrentSelection();
+
+                               if (res.isDeleted())
+                                       menu = new FileContextMenu(images, true, false);
+                               else
+                                       menu = new FileContextMenu(images, false, false);
+                               int left = event.getClientX();
+                               int top = event.getClientY();
+                               menu.setPopupPosition(left, top);
+                               menu.show();
+                       } else if (GSS.get().getCurrentSelection() instanceof List) {
+                               /*TODO: CELLTREE
+                               if (GSS.get().getTreeView().isTrashItem(GSS.get().getTreeView().getSelection()))
+                                       menu = new FileContextMenu(images, true, false);
+                               else {
+                                       menu = new FileContextMenu(images, false, false);
+                                       menu.onMultipleSelection();
+                               }*/
+                               menu = new FileContextMenu(images, false, false);
+                               menu.onMultipleSelection();
+                               int left = event.getClientX();
+                               int top = event.getClientY();
+                               menu.setPopupPosition(left, top);
+                               menu.show();
+                       }
+               return menu;
+       }
+
+       public FileContextMenu onEmptyEvent(Event event) {
+               FileContextMenu menu=null;
+               /*TODO: CELLTREE
+               if (GSS.get().getTreeView().isTrashItem(GSS.get().getTreeView().getCurrent()))
+                       menu = new FileContextMenu(images, true, true);
+               else if(((DnDTreeItem)GSS.get().getTreeView().getCurrent()).getFolderResource() != null)
+                       menu = new FileContextMenu(images, false, true);
+               else return menu;
+               */
+               menu = new FileContextMenu(images, false, true);
+               int left = event.getClientX();
+               int top = event.getClientY();
+               menu.setPopupPosition(left, top);
+               menu.show();
+               return menu;
+       }
+
+
+}
diff --git a/src/org/gss_project/gss/web/client/FileList.java b/src/org/gss_project/gss/web/client/FileList.java
new file mode 100644 (file)
index 0000000..945d290
--- /dev/null
@@ -0,0 +1,997 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import static com.google.gwt.query.client.GQuery.$;
+
+import org.gss_project.gss.web.client.commands.UploadFileCommand;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.RestCommand;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.OthersFolderResource;
+import org.gss_project.gss.web.client.rest.resource.OthersResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+import gwtquery.plugins.draggable.client.DraggableOptions;
+import gwtquery.plugins.draggable.client.StopDragException;
+import gwtquery.plugins.draggable.client.DraggableOptions.DragFunction;
+import gwtquery.plugins.draggable.client.DraggableOptions.RevertOption;
+import gwtquery.plugins.draggable.client.events.DragContext;
+import gwtquery.plugins.draggable.client.events.DragStartEvent;
+import gwtquery.plugins.draggable.client.events.DragStopEvent;
+import gwtquery.plugins.draggable.client.events.DragStartEvent.DragStartEventHandler;
+import gwtquery.plugins.draggable.client.events.DragStopEvent.DragStopEventHandler;
+import gwtquery.plugins.droppable.client.gwt.DragAndDropCellTable;
+import gwtquery.plugins.droppable.client.gwt.DragAndDropColumn;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.ImageResourceCell;
+import com.google.gwt.cell.client.SafeHtmlCell;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.RepeatingCommand;
+import com.google.gwt.dom.client.Style.Cursor;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.cellview.client.CellTable;
+import com.google.gwt.user.cellview.client.GssSimplePager;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.view.client.ListDataProvider;
+import com.google.gwt.view.client.MultiSelectionModel;
+import com.google.gwt.view.client.ProvidesKey;
+import com.google.gwt.view.client.SelectionChangeEvent;
+import com.google.gwt.view.client.SelectionChangeEvent.Handler;
+
+/**
+ * A composite that displays the list of files in a particular folder.
+ */
+public class FileList extends Composite {
+       ListDataProvider<FileResource> provider = new ListDataProvider<FileResource>();
+       interface TableResources extends DragAndDropCellTable.Resources {
+           @Source({CellTable.Style.DEFAULT_CSS, "GssCellTable.css"})
+           TableStyle cellTableStyle();
+         }
+       
+       static interface Templates extends SafeHtmlTemplates {
+           Templates INSTANCE = GWT.create(Templates.class);
+
+           @Template("<div id='dragHelper' style='border:1px solid black; background-color:#ffffff; color:black; width:150px;z-index:100'></div>")
+           SafeHtml outerHelper();
+
+        @Template("<span id='{0}'>{0}</span>")
+        public SafeHtml filenameSpan(String filename);
+
+        @Template("<a href='{0}' title='{1}' rel='lytebox[mnf]' onclick='myLytebox.start(this, false, false); return false;'>(view)</a>")
+        public SafeHtml viewLink(String link, String title);
+
+        @Template("<table><tr><td rowspan='3'>{0}</td><td style='font-size:95%;' id='{1}'>{1}</td></tr><tr><td>{2}</td></tr></table>")
+        public SafeHtml rendelContactCell(String imageHtml, String name, String fileSize);
+
+        @Template("<span id='{0}' class='{1}'>{2}</span>")
+        public SafeHtml spanWithIdAndClass(String id, String cssClass, String content);
+         }
+       
+       
+       /**
+          * The styles applied to the table.
+          */
+         interface TableStyle extends CellTable.Style {
+         }
+
+       private String showingStats = "";
+
+       private int startIndex = 0;
+
+       /**
+        * A constant that denotes the completion of an IncrementalCommand.
+        */
+       public static final boolean DONE = false;
+
+       
+       
+       private final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
+
+       /**
+        * Specifies that the images available for this composite will be the ones
+        * available in FileContextMenu.
+        */
+       public interface Images extends ClientBundle,FileContextMenu.Images, CellTreeView.Images {
+
+               @Source("org/gss_project/gss/resources/blank.gif")
+               ImageResource blank();
+
+               @Source("org/gss_project/gss/resources/asc.png")
+               ImageResource asc();
+
+               @Source("org/gss_project/gss/resources/desc.png")
+               ImageResource desc();
+
+               @Source("org/gss_project/gss/resources/mimetypes/document_shared.png")
+               ImageResource documentShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/kcmfontinst.png")
+               ImageResource wordprocessor();
+
+               @Source("org/gss_project/gss/resources/mimetypes/log.png")
+               ImageResource spreadsheet();
+
+               @Source("org/gss_project/gss/resources/mimetypes/kpresenter_kpr.png")
+               ImageResource presentation();
+
+               @Source("org/gss_project/gss/resources/mimetypes/acroread.png")
+               ImageResource pdf();
+
+               @Source("org/gss_project/gss/resources/mimetypes/image.png")
+               ImageResource image();
+
+               @Source("org/gss_project/gss/resources/mimetypes/video2.png")
+               ImageResource video();
+
+               @Source("org/gss_project/gss/resources/mimetypes/knotify.png")
+               ImageResource audio();
+
+               @Source("org/gss_project/gss/resources/mimetypes/html.png")
+               ImageResource html();
+
+               @Source("org/gss_project/gss/resources/mimetypes/txt.png")
+               ImageResource txt();
+
+               @Source("org/gss_project/gss/resources/mimetypes/ark2.png")
+               ImageResource zip();
+
+               @Source("org/gss_project/gss/resources/mimetypes/kcmfontinst_shared.png")
+               ImageResource wordprocessorShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/log_shared.png")
+               ImageResource spreadsheetShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/kpresenter_kpr_shared.png")
+               ImageResource presentationShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/acroread_shared.png")
+               ImageResource pdfShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/image_shared.png")
+               ImageResource imageShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/video2_shared.png")
+               ImageResource videoShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/knotify_shared.png")
+               ImageResource audioShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/html_shared.png")
+               ImageResource htmlShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/txt_shared.png")
+               ImageResource txtShared();
+
+               @Source("org/gss_project/gss/resources/mimetypes/ark2_shared.png")
+               ImageResource zipShared();
+
+       }
+       
+       DragStopEventHandler dragStop = new DragStopEventHandler() {
+               
+               @Override
+               public void onDragStop(DragStopEvent event) {
+                       GWT.log("DRAG STOPPED");
+                       
+               }
+       };
+       
+       private static class ContactCell extends AbstractCell<org.gss_project.gss.web.client.rest.resource.FileResource> {
+
+           /**
+            * The html of the image used for contacts.
+            * 
+            */
+           private final String imageHtml;
+
+           public ContactCell(ImageResource image) {
+             this.imageHtml = AbstractImagePrototype.create(image).getHTML();
+           }
+
+           
+
+               
+
+           @Override
+           public void render(Context context, FileResource value, SafeHtmlBuilder sb) {
+             // Value can be null, so do a null check..
+             if (value == null) {
+               return;
+             }
+
+          sb.append(Templates.INSTANCE.rendelContactCell(imageHtml, value.getName(), value.getFileSizeAsString()));
+           }
+
+
+         }
+       /**
+        * Retrieve the celltable.
+        *
+        * @return the celltable
+        */
+       public DragAndDropCellTable<FileResource> getCelltable() {
+               return celltable;
+       }
+       
+       
+       /**
+        * The number of files in this folder.
+        */
+       int folderFileCount;
+
+       /**
+        * Total folder size
+        */
+       long folderTotalSize;
+
+       /**
+        * A cache of the files in the list.
+        */
+       private List<FileResource> files;
+
+       /**
+        * The widget's image bundle.
+        */
+       private final Images images;
+       
+       private FileContextMenu menuShowing;
+       private DragAndDropCellTable<FileResource> celltable;
+       private final MultiSelectionModel<FileResource> selectionModel;
+       private final List<SortableHeader> allHeaders = new ArrayList<SortableHeader>();
+       SortableHeader nameHeader;
+       GssSimplePager pagerBottom;
+       GssSimplePager pagerTop;
+       Button uploadButtonBottom;
+       Button uploadButtonTop;
+       /**
+        * Construct the file list widget. This entails setting up the widget
+        * layout, fetching the number of files in the current folder from the
+        * server and filling the local file cache of displayed files with data from
+        * the server, as well.
+        *
+        * @param _images
+        */
+       public FileList(Images _images) {
+               images = _images;
+               DragAndDropCellTable.Resources resources = GWT.create(TableResources.class);
+               ProvidesKey<FileResource> keyProvider = new ProvidesKey<FileResource>(){
+
+                       @Override
+                       public Object getKey(FileResource item) {
+                               return item.getUri();
+                       }
+                       
+               };
+               celltable = new DragAndDropCellTable<FileResource>(GSS.VISIBLE_FILE_COUNT,resources,keyProvider);
+               
+               DragAndDropColumn<FileResource, ImageResource> status = new DragAndDropColumn<FileResource, ImageResource>(new ImageResourceCell(){
+                       @Override
+                 public boolean handlesSelection() {
+                           return false;
+                         }
+               }) {
+                 @Override
+                 public ImageResource getValue(FileResource entity) {
+                   return getFileIcon(entity);
+                 }
+                 
+              };
+           celltable.addColumn(status,"");
+           
+           initDragOperation(status);
+               final DragAndDropColumn<FileResource,SafeHtml> nameColumn = new DragAndDropColumn<FileResource,SafeHtml>(new SafeHtmlCell()) {
+
+                       @Override
+                       public SafeHtml getValue(FileResource object) {
+                               SafeHtmlBuilder sb = new SafeHtmlBuilder();
+                sb.append(Templates.INSTANCE.filenameSpan(object.getName()));
+                               if (object.getContentType().endsWith("png") || object.getContentType().endsWith("gif") || object.getContentType().endsWith("jpeg") ){
+                                       sb.appendHtmlConstant("&nbsp;").append(Templates.INSTANCE.viewLink(GSS.get().getTopPanel().getFileMenu().getDownloadURL(object), object.getOwner() + " : " + object.getPath() + object.getName()));
+                               }
+                               
+                               return sb.toSafeHtml();
+                       }
+                       
+               };
+               initDragOperation(nameColumn);
+               celltable.addColumn(nameColumn,nameHeader = new SortableHeader("Name"));
+               allHeaders.add(nameHeader);
+               //nameHeader.setSorted(true);
+               //nameHeader.toggleReverseSort();
+               nameHeader.setUpdater(new FileValueUpdater(nameHeader, "name"));
+               celltable.redrawHeaders();
+               
+               
+           
+           
+           SortableHeader aheader;
+           DragAndDropColumn<FileResource,String> aColumn;
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               return GSS.get().findUserFullName(object.getOwner());
+                       }                       
+               },aheader = new SortableHeader("Owner"));
+               initDragOperation(aColumn);
+               allHeaders.add(aheader);
+               aheader.setUpdater(new FileValueUpdater(aheader, "owner"));
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               // TODO Auto-generated method stub
+                               return object.getPath();
+                       }                       
+               },aheader = new SortableHeader("Path"));
+               initDragOperation(aColumn);
+               allHeaders.add(aheader);
+               
+               aheader.setUpdater(new FileValueUpdater(aheader, "path"));      
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               if(object.isVersioned())
+                                       return object.getVersion().toString();
+                               return "-";
+                       }                       
+               },aheader = new SortableHeader("Version"));
+               initDragOperation(aColumn);
+               allHeaders.add(aheader);
+               aheader.setUpdater(new FileValueUpdater(aheader, "version"));
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               // TODO Auto-generated method stub
+                               return object.getFileSizeAsString();
+                       }                       
+               },aheader = new SortableHeader("Size"));
+               initDragOperation(aColumn);
+               allHeaders.add(aheader);
+               aheader.setUpdater(new FileValueUpdater(aheader, "size"));      
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               return formatter.format(object.getModificationDate());
+                       }                       
+               },aheader = new SortableHeader("Last Modified"));
+               allHeaders.add(aheader);
+               aheader.setUpdater(new FileValueUpdater(aheader, "date"));
+              
+               
+               provider.addDataDisplay(celltable);
+               celltable.addDragStopHandler(dragStop);
+               celltable.addDragStartHandler(new DragStartEventHandler() {
+
+                     public void onDragStart(DragStartEvent event) {
+                       FileResource value = event.getDraggableData();
+                       
+                       com.google.gwt.dom.client.Element helper = event.getHelper();
+                       SafeHtmlBuilder sb = new SafeHtmlBuilder();
+                       sb.appendHtmlConstant("<b>");
+                       DisplayHelper.log(value.getName());
+                       if(getSelectedFiles().size()==1)
+                               sb.appendEscaped(value.getName());
+                       else
+                               sb.appendEscaped(getSelectedFiles().size()+" files");
+                       sb.appendHtmlConstant("</b>");
+                       helper.setInnerHTML(sb.toSafeHtml().asString());
+
+                     }
+                   });
+               
+               
+               
+               
+               
+               
+               VerticalPanel vp = new VerticalPanel();
+               vp.setWidth("100%");
+               pagerTop = new GssSimplePager(GssSimplePager.TextLocation.CENTER);
+               pagerTop.setDisplay(celltable); 
+               uploadButtonTop=new Button("<span id='topMenu.file.upload'>" + AbstractImagePrototype.create(images.fileUpdate()).getHTML() + "&nbsp;Upload</span>");
+               uploadButtonTop.addClickHandler(new ClickHandler() {
+                       
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               new UploadFileCommand(null).execute();
+                       }
+               });
+               HorizontalPanel topPanel = new HorizontalPanel();
+               topPanel.add(pagerTop);
+               topPanel.add(uploadButtonTop);
+               vp.add(topPanel);
+               celltable.setWidth("100%");
+               vp.add(celltable);
+               pagerBottom = new GssSimplePager(GssSimplePager.TextLocation.CENTER);
+               pagerBottom.setDisplay(celltable);
+               HorizontalPanel bottomPanel = new HorizontalPanel();
+               bottomPanel.add(pagerBottom);
+               uploadButtonBottom=new Button("<span id='topMenu.file.upload'>" + AbstractImagePrototype.create(images.fileUpdate()).getHTML() + "&nbsp;Upload</span>");
+               uploadButtonBottom.addClickHandler(new ClickHandler() {
+                       
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               new UploadFileCommand(null).execute();
+                       }
+               });
+               bottomPanel.add(uploadButtonBottom);
+               vp.add(bottomPanel);
+               vp.setCellWidth(celltable, "100%");
+               
+               initWidget(vp);
+               pagerBottom.setVisible(false);
+               pagerTop.setVisible(false);
+
+               celltable.setStyleName("gss-List");
+               selectionModel = new MultiSelectionModel<FileResource>(keyProvider);
+               
+
+                Handler selectionHandler = new SelectionChangeEvent.Handler() { 
+             @Override 
+             public void onSelectionChange(com.google.gwt.view.client.SelectionChangeEvent event) {
+                if(getSelectedFiles().size()==1)
+                        GSS.get().setCurrentSelection(getSelectedFiles().get(0));
+                else
+                        GSS.get().setCurrentSelection(getSelectedFiles());
+             }
+         };
+         selectionModel.addSelectionChangeHandler(selectionHandler);
+         
+               celltable.setSelectionModel(selectionModel,GSSSelectionEventManager.<FileResource>createDefaultManager());
+               celltable.setPageSize(GSS.VISIBLE_FILE_COUNT);
+               
+               //celltable.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+               Scheduler.get().scheduleIncremental(new RepeatingCommand() {
+
+                       @Override
+                       public boolean execute() {
+                               return fetchRootFolder();
+                       }
+               });
+               sinkEvents(Event.ONCONTEXTMENU);
+               sinkEvents(Event.ONMOUSEUP);
+               sinkEvents(Event.ONMOUSEDOWN);
+               sinkEvents(Event.ONCLICK);
+               sinkEvents(Event.ONKEYDOWN);
+               sinkEvents(Event.ONDBLCLICK);
+               GSS.preventIESelection();
+       }
+       
+       //public native void fireClickEvent(Element element) /*-{
+         //  var evObj = $doc.createEvent('MouseEvents');
+           //evObj.initEvent('click', true, true);
+           //element.dispatchEvent(evObj);
+       //}-*/;
+       
+       
+       
+        public List<FileResource> getSelectedFiles() {
+         return new ArrayList<FileResource>(selectionModel.getSelectedSet());
+        }
+       
+        private void initDragOperation(DragAndDropColumn<?, ?> column) {
+
+                   // retrieve draggableOptions on the column
+                   DraggableOptions draggableOptions = column.getDraggableOptions();
+                   // use template to construct the helper. The content of the div will be set
+                   // after
+                   draggableOptions.setHelper($(Templates.INSTANCE.outerHelper().asString()));
+                   //draggableOptions.setZIndex(100);
+                   // opacity of the helper
+                   draggableOptions.setAppendTo("body"); 
+                   //draggableOptions.setOpacity((float) 0.8);
+                   draggableOptions.setContainment("document");
+                   // cursor to use during the drag operation
+                   draggableOptions.setCursor(Cursor.MOVE);
+                   // set the revert option
+                   draggableOptions.setRevert(RevertOption.ON_INVALID_DROP);
+                   // prevents dragging when user click on the category drop-down list
+                   draggableOptions.setCancel("select");
+                   
+                   
+                   draggableOptions.setOnBeforeDragStart(new DragFunction() {
+                               
+                               @Override
+                               public void f(DragContext context) {
+                                        FileResource value = context.getDraggableData();
+                                    if(!selectionModel.isSelected(value)){
+                                       throw new StopDragException();
+                                     }
+                                       
+                               }
+                       });
+                 }
+       
+        public void showContextMenu(Event event){
+                menuShowing = new FileContextMenu(images, false, true);
+                       menuShowing=menuShowing.onEmptyEvent(event);
+        }
+       @Override
+       public void onBrowserEvent(Event event) {
+               
+               if (files == null || files.size() == 0) {
+                       if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
+                               menuShowing = new FileContextMenu(images, false, true);
+                               menuShowing=menuShowing.onEmptyEvent(event);
+                               event.preventDefault();
+                               event.cancelBubble(true);
+                       }
+                       return;
+               }
+               if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() != 0) {
+                       GWT.log("*****GOING TO SHOW CONTEXT MENU ****", null);
+                       menuShowing =  new FileContextMenu(images, false, false);
+                       menuShowing=menuShowing.onEvent(event);
+                       event.cancelBubble(true);
+                       event.preventDefault();
+               } else if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
+                       menuShowing = new FileContextMenu(images, false, true);
+                       menuShowing=menuShowing.onEmptyEvent(event);
+                       event.cancelBubble(true);
+                       event.preventDefault();
+               } else if (DOM.eventGetType(event) == Event.ONDBLCLICK)
+                       if (getSelectedFiles().size() == 1) {
+                               GSS app = GSS.get();
+                               FileResource file = getSelectedFiles().get(0);
+                               String dateString = RestCommand.getDate();
+                               String resource = file.getUri().substring(app.getApiPath().length() - 1, file.getUri().length());
+                               String sig = app.getCurrentUserResource().getUsername() + " " +
+                                               RestCommand.calculateSig("GET", dateString, resource,
+                                               RestCommand.base64decode(app.getToken()));
+                               Window.open(file.getUri() + "?Authorization=" + URL.encodeComponent(sig) + "&Date=" + URL.encodeComponent(dateString), "_blank", "");
+                               event.preventDefault();
+                               return;
+                       }
+               super.onBrowserEvent(event);
+       }
+
+       /**
+        * Retrieve the root folder for the current user.
+        *
+        * @return true if the retrieval was successful
+        */
+       protected boolean fetchRootFolder() {
+               UserResource user = GSS.get().getCurrentUserResource();
+               if (user == null)
+                       return !DONE;
+               // Update cache and clear selection.
+               updateFileCache(true);
+               return DONE;
+       }
+
+
+       /**
+        * Update the display of the file list.
+        */
+       void update(boolean sort) {
+               int count = folderFileCount;
+               int max = startIndex + GSS.VISIBLE_FILE_COUNT;
+               if (max > count)
+                       max = count;
+               folderTotalSize = 0;
+               
+               copyListAndContinue(files);
+               for(FileResource f : files){
+                       folderTotalSize += f.getContentLength();
+               }
+               if (folderFileCount == 0) {
+                       showingStats = "no files";
+               } else if (folderFileCount < GSS.VISIBLE_FILE_COUNT) {
+                       if (folderFileCount == 1)
+                               showingStats = "1 file";
+                       else
+                               showingStats = folderFileCount + " files";
+                       showingStats += " (" + FileResource.getFileSizeAsString(folderTotalSize) + ")";
+               } else {
+                       showingStats = "" + (startIndex + 1) + " - " + max + " of " + count + " files" + " (" + FileResource.getFileSizeAsString(folderTotalSize) + ")";
+               }
+               showCellTable();
+               updateCurrentlyShowingStats();
+
+       }
+
+       /**
+        * Return the proper icon based on the MIME type of the file.
+        *
+        * @param file
+        * @return the icon
+        */
+       private ImageResource getFileIcon(FileResource file) {
+               String mimetype = file.getContentType();
+               boolean shared = false;
+               if(GSS.get().getTreeView().getSelection()!=null && (GSS.get().getTreeView().getSelection() instanceof OtherUserResource || GSS.get().getTreeView().getSelection() instanceof OthersFolderResource)){
+                       OtherUserResource otherUser = null;
+                       if(GSS.get().getTreeView().getSelection() instanceof OtherUserResource)
+                               otherUser = (OtherUserResource) GSS.get().getTreeView().getSelection();
+                       else if (GSS.get().getTreeView().getSelection() instanceof OthersFolderResource){
+                               otherUser = GSS.get().getTreeView().getOtherUserResourceOfOtherFolder((OthersFolderResource) GSS.get().getTreeView().getSelection());
+                       }
+                       if(otherUser ==null)
+                               shared=false;
+                       else{
+                               String uname = otherUser.getUsername();
+                               if(uname==null)
+                                       uname = GSS.get().getTreeView().getOthers().getUsernameOfUri(otherUser.getUri());
+                               if(uname != null)
+                                       shared = file.isShared();
+                       }
+               }
+               else
+                       shared = file.isShared();
+               if (mimetype == null)
+                       return shared ? images.documentShared() : images.document();
+               mimetype = mimetype.toLowerCase();
+               if (mimetype.startsWith("application/pdf"))
+                       return shared ? images.pdfShared() : images.pdf();
+               else if (mimetype.endsWith("excel"))
+                       return shared ? images.spreadsheetShared() : images.spreadsheet();
+               else if (mimetype.endsWith("msword"))
+                       return shared ? images.wordprocessorShared() : images.wordprocessor();
+               else if (mimetype.endsWith("powerpoint"))
+                       return shared ? images.presentationShared() : images.presentation();
+               else if (mimetype.startsWith("application/zip") ||
+                                       mimetype.startsWith("application/gzip") ||
+                                       mimetype.startsWith("application/x-gzip") ||
+                                       mimetype.startsWith("application/x-tar") ||
+                                       mimetype.startsWith("application/x-gtar"))
+                       return shared ? images.zipShared() : images.zip();
+               else if (mimetype.startsWith("text/html"))
+                       return shared ? images.htmlShared() : images.html();
+               else if (mimetype.startsWith("text/plain"))
+                       return shared ? images.txtShared() : images.txt();
+               else if (mimetype.startsWith("image/"))
+                       return shared ? images.imageShared() : images.image();
+               else if (mimetype.startsWith("video/"))
+                       return shared ? images.videoShared() : images.video();
+               else if (mimetype.startsWith("audio/"))
+                       return shared ? images.audioShared() : images.audio();
+               return shared ? images.documentShared() : images.document();
+       }
+
+       /**
+        * Update status panel with currently showing file stats.
+        */
+       public void updateCurrentlyShowingStats() {
+               GSS.get().getStatusPanel().updateCurrentlyShowing(showingStats);
+       }
+       
+       public void updateFileCache(boolean clearSelection){
+               if(clearSelection){
+                       clearSelectedRows();
+               }
+               
+               final RestResource folderItem = GSS.get().getTreeView().getSelection();
+               // Validation.
+               if (folderItem == null || folderItem.equals(GSS.get().getTreeView().getOthers())) {
+                       setFiles(new ArrayList<FileResource>());
+                       update(true);
+                       return;
+               }
+               else if (folderItem instanceof RestResourceWrapper) {
+                       setFiles(((RestResourceWrapper) folderItem).getResource().getFiles());
+                       update(true);
+               }
+               else if (folderItem instanceof SharedResource) {
+                       setFiles(((SharedResource) folderItem).getFiles());
+                       update(true);
+               }
+               else if (folderItem instanceof OtherUserResource) {
+                       setFiles(((OtherUserResource) folderItem).getFiles());
+                       update(true);
+               }
+               else if (folderItem instanceof TrashResource) {
+                       setFiles(((TrashResource) folderItem).getFiles());
+                       update(true);
+               }
+       }
+       
+
+       /**
+        * Fill the file cache with data.
+        */
+       public void setFiles(final List<FileResource> _files) {
+               if (_files.size() > 0 && ! (GSS.get().getTreeView().getSelection() instanceof TrashResource)) {
+                       files = new ArrayList<FileResource>();
+                       for (FileResource fres : _files)
+                               if (!fres.isDeleted())
+                                       files.add(fres);
+               }
+               else
+                       files = _files;
+               Collections.sort(files, new Comparator<FileResource>() {
+
+                       @Override
+                       public int compare(FileResource arg0, FileResource arg1) {
+                               return arg0.getName().compareTo(arg1.getName());
+                       }
+
+               });
+               folderFileCount = files.size();
+               
+               nameHeader.setSorted(true);
+               nameHeader.toggleReverseSort();
+               for (SortableHeader otherHeader : allHeaders) {
+                 if (otherHeader != nameHeader) {
+                   otherHeader.setSorted(false);
+                   otherHeader.setReverseSort(true);
+                 }
+               }
+               //
+       }
+
+       
+
+       
+       /**
+        * Does the list contains the requested filename
+        *
+        * @param fileName
+        * @return true/false
+        */
+       public boolean contains(String fileName) {
+               for (int i = 0; i < files.size(); i++)
+                       if (files.get(i).getName().equals(fileName))
+                               return true;
+               return false;
+       }
+
+       public void clearSelectedRows() {
+               Iterator<FileResource> it = selectionModel.getSelectedSet().iterator();
+               while(it.hasNext()){
+                       selectionModel.setSelected(it.next(),false);
+               }
+       }
+       
+
+       /**
+        *
+        */
+       public void selectAllRows() {
+               Iterator<FileResource> it = provider.getList().iterator();
+               while(it.hasNext()){
+                       selectionModel.setSelected(it.next(),true);
+               }
+
+
+       }
+
+       
+       private void sortFiles(final String sortingProperty, final boolean sortingType){
+               Collections.sort(files, new Comparator<FileResource>() {
+
+            @Override
+            public int compare(FileResource arg0, FileResource arg1) {
+                    AbstractImagePrototype descPrototype = AbstractImagePrototype.create(images.desc());
+                    AbstractImagePrototype ascPrototype = AbstractImagePrototype.create(images.asc());
+                    if (sortingType){
+                            if (sortingProperty.equals("version")) {
+                                    return arg0.getVersion().compareTo(arg1.getVersion());
+                            } else if (sortingProperty.equals("owner")) {
+                                    return arg0.getOwner().compareTo(arg1.getOwner());
+                            } else if (sortingProperty.equals("date")) {
+                                    return arg0.getModificationDate().compareTo(arg1.getModificationDate());
+                            } else if (sortingProperty.equals("size")) {
+                                    return arg0.getContentLength().compareTo(arg1.getContentLength());
+                            } else if (sortingProperty.equals("name")) {
+                                    return arg0.getName().compareTo(arg1.getName());
+                            } else if (sortingProperty.equals("path")) {
+                                    return arg0.getUri().compareTo(arg1.getUri());
+                            } else {
+                                    return arg0.getName().compareTo(arg1.getName());
+                            }
+                    }
+                    else if (sortingProperty.equals("version")) {
+                            
+                            return arg1.getVersion().compareTo(arg0.getVersion());
+                    } else if (sortingProperty.equals("owner")) {
+                            
+                            return arg1.getOwner().compareTo(arg0.getOwner());
+                    } else if (sortingProperty.equals("date")) {
+                            
+                            return arg1.getModificationDate().compareTo(arg0.getModificationDate());
+                    } else if (sortingProperty.equals("size")) {
+                            
+                            return arg1.getContentLength().compareTo(arg0.getContentLength());
+                    } else if (sortingProperty.equals("name")) {
+                            
+                            return arg1.getName().compareTo(arg0.getName());
+                    } else if (sortingProperty.equals("path")) {
+                            
+                            return arg1.getUri().compareTo(arg0.getUri());
+                    } else {
+                            
+                            return arg1.getName().compareTo(arg0.getName());
+                    }
+            }
+
+               });
+       }
+       
+       final class FileValueUpdater implements ValueUpdater<String>{
+               private String property;
+               private SortableHeader header;
+               /**
+                * 
+                */
+               public FileValueUpdater(SortableHeader header,String property) {
+                       this.property=property;
+                       this.header=header;
+               }
+               @Override
+               public void update(String value) {
+                       header.setSorted(true);
+                       header.toggleReverseSort();
+
+               for (SortableHeader otherHeader : allHeaders) {
+                 if (otherHeader != header) {
+                   otherHeader.setSorted(false);
+                   otherHeader.setReverseSort(true);
+                 }
+               }
+               celltable.redrawHeaders();
+               sortFiles(property, header.getReverseSort());
+               FileList.this.update(true);                     
+               }
+               
+       }
+       /**
+        * Creates a new ArrayList<FileResources> from the given files ArrayList 
+        * in order that the input files remain untouched 
+        * and continues to find user's full names of each FileResource element
+        * in the new ArrayList
+        *    
+        * @param filesInput
+        */
+       private void copyListAndContinue(List<FileResource> filesInput){
+               List<FileResource> copiedFiles = new ArrayList<FileResource>();         
+               for(FileResource file : filesInput) {
+                       copiedFiles.add(file);
+               }
+               handleFullNames(copiedFiles);
+       }
+       
+       /**
+        * Examines whether or not the user's full name exists in the 
+        * userFullNameMap in the GSS.java for every element of the input list.
+        * If the user's full name does not exist in the map then a command is being made.  
+        * 
+        * @param filesInput
+        */
+       private void handleFullNames(List<FileResource> filesInput){            
+               if(filesInput.size() == 0){
+                       showCellTable();
+                       return;
+               }               
+
+               if(GSS.get().findUserFullName(filesInput.get(0).getOwner()) == null){
+                       findFullNameAndUpdate(filesInput);              
+                       return;
+               }
+                               
+               if(filesInput.size() >= 1){
+                       filesInput.remove(filesInput.get(0));
+                       if(filesInput.isEmpty()){
+                               showCellTable();                                
+                       }else{
+                               handleFullNames(filesInput);
+                       }
+               }               
+       }
+       
+       /**
+        * Makes a command to search for full name from a given username. 
+        * Only after the completion of the command the celltable is shown
+        * or the search for the next full name continues.
+        *  
+        * @param filesInput
+        */
+       private void findFullNameAndUpdate(final List<FileResource> filesInput){                
+               String aUserName = filesInput.get(0).getOwner();
+               String path = GSS.get().getApiPath() + "users/" + aUserName; 
+
+               GetCommand<UserSearchResource> gg = new GetCommand<UserSearchResource>(UserSearchResource.class, path, false,null) {
+                       @Override
+                       public void onComplete() {
+                               final UserSearchResource result = getResult();
+                               for (UserResource user : result.getUsers()){
+                                       String username = user.getUsername();
+                                       String userFullName = user.getName();
+                                       GSS.get().putUserToMap(username, userFullName);
+                                       if(filesInput.size() >= 1){
+                                               filesInput.remove(filesInput.get(0));
+                                               if(filesInput.isEmpty()){
+                                                       showCellTable();
+                                               }else{
+                                                       handleFullNames(filesInput);
+                                               }                                                                                               
+                                       }                                                                       
+                               }
+                       }
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               GSS.get().displayError("Unable to fetch user's full name from the given username " + filesInput.get(0).getOwner());
+                               if(filesInput.size() >= 1){
+                                       filesInput.remove(filesInput.get(0));
+                                       handleFullNames(filesInput);                                    
+                               }
+                       }
+               };
+               DeferredCommand.addCommand(gg);
+       
+       }
+       /**
+        * Shows the files in the cellTable 
+        */
+
+       private void showCellTable(){
+               if(files.size()>GSS.VISIBLE_FILE_COUNT){
+                       pagerBottom.setVisible(true);
+                       pagerTop.setVisible(true);
+               }
+               else{
+                       pagerTop.setVisible(false);
+                       pagerBottom.setVisible(false);
+               }
+               RestResource selectedItem = GSS.get().getTreeView().getSelection();
+               boolean uploadVisible = !(selectedItem != null && (selectedItem instanceof TrashResource || selectedItem instanceof TrashFolderResource || selectedItem instanceof SharedResource || selectedItem instanceof OthersResource || selectedItem instanceof OtherUserResource));
+               uploadButtonBottom.setVisible(uploadVisible&&files.size()>=GSS.VISIBLE_FILE_COUNT);
+               uploadButtonTop.setVisible(uploadVisible&&files.size()>=GSS.VISIBLE_FILE_COUNT);
+               provider.setList(files);
+               
+               provider.refresh();
+               
+               //celltable.redraw();
+               celltable.redrawHeaders();              
+       }
+
+       
+}
diff --git a/src/org/gss_project/gss/web/client/FileMenu.java b/src/org/gss_project/gss/web/client/FileMenu.java
new file mode 100644 (file)
index 0000000..2a4eca4
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.commands.EmptyTrashCommand;
+import org.gss_project.gss.web.client.commands.NewFolderCommand;
+import org.gss_project.gss.web.client.commands.PropertiesCommand;
+import org.gss_project.gss.web.client.commands.RefreshCommand;
+import org.gss_project.gss.web.client.commands.UploadFileCommand;
+import org.gss_project.gss.web.client.rest.RestCommand;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.OthersResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+
+import java.util.List;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * The 'File' menu implementation.
+ */
+public class FileMenu extends PopupPanel implements ClickHandler {
+
+       /**
+        * The widget's images.
+        */
+       private final Images images;
+
+       /**
+        * An image bundle for this widgets images.
+        */
+       public interface Images extends ClientBundle,FilePropertiesDialog.Images {
+
+               @Source("org/gss_project/gss/resources/folder_new.png")
+               ImageResource folderNew();
+
+               @Source("org/gss_project/gss/resources/folder_outbox.png")
+               ImageResource fileUpdate();
+
+               @Source("org/gss_project/gss/resources/view_text.png")
+               ImageResource viewText();
+
+               @Override
+               @Source("org/gss_project/gss/resources/folder_inbox.png")
+               ImageResource download();
+
+               @Source("org/gss_project/gss/resources/trashcan_empty.png")
+               ImageResource emptyTrash();
+
+               @Source("org/gss_project/gss/resources/internet.png")
+               ImageResource sharing();
+
+               @Source("org/gss_project/gss/resources/refresh.png")
+               ImageResource refresh();
+}
+
+       final MenuBar contextMenu = new MenuBar(true);
+
+       /**
+        * The widget's constructor.
+        *
+        * @param _images the image bundle passed on by the parent object
+        */
+       public FileMenu(final Images _images) {
+               // The popup's constructor's argument is a boolean specifying that it
+               // auto-close itself when the user clicks outside of it.
+               super(true);
+               setAnimationEnabled(true);
+               images = _images;
+               add(contextMenu);
+
+       }
+
+       @Override
+       public void onClick(ClickEvent event) {
+               final FileMenu menu = new FileMenu(images);
+               final int left = event.getRelativeElement().getAbsoluteLeft();
+               final int top = event.getRelativeElement().getAbsoluteTop() + event.getRelativeElement().getOffsetHeight();
+               menu.setPopupPosition(left, top);
+               menu.show();
+
+       }
+
+
+       /**
+        * Do some validation before downloading a file.
+        */
+       void preDownloadCheck() {
+               Object selection = GSS.get().getCurrentSelection();
+               if (selection == null || !(selection instanceof FileResource)) {
+                       GSS.get().displayError("You have to select a file first");
+                       return;
+               }
+       }
+
+       /**
+        * Create a download link for the respective menu item, if the currently
+        * selected object is a file.
+        *
+        * @param link a String array with two elements that is modified so that the
+        *            first position contains the opening tag and the second one the
+        *            closing tag
+        * @param forceDownload If true, link will be such that browser should ask for filename
+        *                              and save location
+        */
+       void createDownloadLink(String[] link, boolean forceDownload) {
+               String downloadURL = getDownloadURL();
+               if (!downloadURL.isEmpty()) {
+                       link[0] = "<a id ='topMenu.file.download' class='hidden-link' href='" + downloadURL
+                                       + (forceDownload ? "&dl=1" : "") + "' target='_blank'>";
+                       link[1] = "</a>";
+               }
+       }
+
+       public String getDownloadURL() {
+               GSS app = GSS.get();
+               Object selection = app.getCurrentSelection();
+               if (selection != null && selection instanceof FileResource) {
+                       FileResource file = (FileResource) selection;
+                       return getDownloadURL(file);
+               }
+               return "";
+       }
+
+       public String getDownloadURL(FileResource file) {
+               GSS app = GSS.get();
+               if (file != null) {
+                       String dateString = RestCommand.getDate();
+                       String resource = file.getUri().substring(app.getApiPath().length()-1,file.getUri().length());
+                       String sig = app.getCurrentUserResource().getUsername()+" "+RestCommand.calculateSig("GET", dateString, resource, RestCommand.base64decode(app.getToken()));
+                       return file.getUri() + "?Authorization=" + URL.encodeComponent(sig) + "&Date="+URL.encodeComponent(dateString);
+               }
+               return "";
+       }
+
+       public MenuBar createMenu() {
+               contextMenu.clearItems();
+               contextMenu.setAutoOpen(false);
+               final Command downloadCmd = new Command() {
+
+                       @Override
+                       public void execute() {
+                               hide();
+                               preDownloadCheck();
+                       }
+               };
+               //
+               RestResource selectedItem = GSS.get().getTreeView().getSelection();
+               boolean downloadVisible = GSS.get().getCurrentSelection() != null && GSS.get().getCurrentSelection() instanceof FileResource;
+               boolean propertiesVisible = !(selectedItem != null && (selectedItem instanceof TrashResource || selectedItem instanceof TrashFolderResource || selectedItem instanceof SharedResource || selectedItem instanceof OthersResource || selectedItem instanceof OtherUserResource 
+                                       //|| folders.isOthersShared(selectedItem) || selectedItem.getUserObject() instanceof GroupUserResource 
+                                       || GSS.get().getCurrentSelection() instanceof List));
+               boolean newFolderVisible = !(selectedItem != null && (selectedItem instanceof TrashResource || selectedItem instanceof TrashFolderResource || selectedItem instanceof SharedResource || selectedItem instanceof OthersResource || selectedItem instanceof OtherUserResource));
+               boolean uploadVisible = !(selectedItem != null && (selectedItem instanceof TrashResource || selectedItem instanceof TrashFolderResource || selectedItem instanceof SharedResource || selectedItem instanceof OthersResource || selectedItem instanceof OtherUserResource));
+               if(newFolderVisible){
+                       MenuItem newFolderItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(this, images));
+                       newFolderItem.getElement().setId("topMenu.file.newFolder");
+                       contextMenu.addItem(newFolderItem);                     
+               }
+               if(uploadVisible){
+                       MenuItem uploadItem = new MenuItem("<span id='topMenu.file.upload'>" + AbstractImagePrototype.create(images.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));                        
+                       contextMenu.addItem(uploadItem);
+               }
+               if (downloadVisible) {
+                       String[] link = {"", ""};
+                       createDownloadLink(link, false);
+                       
+                       MenuItem downloadItem = new MenuItem("<span>" + link[0] + AbstractImagePrototype.create(images.download()).getHTML() + "&nbsp;Download" + link[1] + "</span>", true, downloadCmd);
+                       contextMenu.addItem(downloadItem);
+                       
+                       createDownloadLink(link, true);
+                       
+                       MenuItem saveAsItem = new MenuItem("<span>" + link[0] + AbstractImagePrototype.create(images.download()).getHTML() + "&nbsp;Save As" + link[1] + "</span>", true, downloadCmd);                 
+                       contextMenu.addItem(saveAsItem);
+               }
+               MenuItem emptyTrashItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.emptyTrash()).getHTML() + "&nbsp;Empty Trash</span>", true, new EmptyTrashCommand(this));
+               emptyTrashItem.getElement().setId("topMenu.file.emptyTrash");
+               contextMenu.addItem(emptyTrashItem);
+               
+               MenuItem refreshItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+               refreshItem.getElement().setId("topMenu.file.refresh");
+               contextMenu.addItem(refreshItem);
+               
+               MenuItem sharingItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, images, 1));
+               sharingItem.getElement().setId("topMenu.file.sharing");
+               contextMenu.addItem(sharingItem)
+                                       .setVisible(propertiesVisible);
+               
+               MenuItem propertiesItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(this, images, 0));
+               propertiesItem.getElement().setId("topMenu.file.properties");
+               contextMenu.addItem(propertiesItem)
+                                       .setVisible(propertiesVisible);
+               return contextMenu;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/FilePropertiesDialog.java b/src/org/gss_project/gss/web/client/FilePropertiesDialog.java
new file mode 100644 (file)
index 0000000..266adfe
--- /dev/null
@@ -0,0 +1,535 @@
+/*\r
+ * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.rest.PostCommand;\r
+import org.gss_project.gss.web.client.rest.RestException;\r
+import org.gss_project.gss.web.client.rest.resource.FileResource;\r
+import org.gss_project.gss.web.client.rest.resource.GroupResource;\r
+import org.gss_project.gss.web.client.rest.resource.PermissionHolder;\r
+\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.event.dom.client.ChangeEvent;\r
+import com.google.gwt.event.dom.client.ChangeHandler;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.i18n.client.DateTimeFormat;\r
+import com.google.gwt.json.client.JSONArray;\r
+import com.google.gwt.json.client.JSONBoolean;\r
+import com.google.gwt.json.client.JSONObject;\r
+import com.google.gwt.json.client.JSONString;\r
+import com.google.gwt.resources.client.ClientBundle;\r
+import com.google.gwt.resources.client.ImageResource;\r
+import com.google.gwt.user.client.Command;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.CheckBox;\r
+import com.google.gwt.user.client.ui.DecoratedTabPanel;\r
+import com.google.gwt.user.client.ui.DisclosurePanel;\r
+import com.google.gwt.user.client.ui.FlexTable;\r
+import com.google.gwt.user.client.ui.FlowPanel;\r
+import com.google.gwt.user.client.ui.FocusPanel;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.Label;\r
+import com.google.gwt.user.client.ui.TextBox;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'File properties' dialog box implementation.\r
+ *\r
+ * @author past\r
+ */\r
+public class FilePropertiesDialog extends AbstractPropertiesDialog {\r
+\r
+       final PermissionsList permList;\r
+\r
+       private CheckBox readForAll;\r
+\r
+       /**\r
+        * An image bundle for this widgets images.\r
+        */\r
+       public interface Images extends ClientBundle,MessagePanel.Images {\r
+\r
+               @Source("org/gss_project/gss/resources/edit_user.png")\r
+               ImageResource permUser();\r
+\r
+               @Source("org/gss_project/gss/resources/groupevent.png")\r
+               ImageResource permGroup();\r
+\r
+               @Source("org/gss_project/gss/resources/editdelete.png")\r
+               ImageResource delete();\r
+\r
+               @Source("org/gss_project/gss/resources/db_update.png")\r
+               ImageResource restore();\r
+\r
+               @Source("org/gss_project/gss/resources/folder_inbox.png")\r
+               ImageResource download();\r
+       }\r
+\r
+       /**\r
+        * The widget that holds the name of the file.\r
+        */\r
+       private TextBox name = new TextBox();\r
+\r
+       private final CheckBox versioned = new CheckBox();\r
+\r
+       final FileResource file;\r
+\r
+       private String userFullName;\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        *\r
+        * @param images the dialog's ImageBundle\r
+        * @param groups\r
+        * @param bodies\r
+        */\r
+       public FilePropertiesDialog(final Images images, final List<GroupResource> groups, List<FileResource> bodies, String _userFullName) {\r
+\r
+               // Set the dialog's caption.\r
+               setText("File properties");\r
+\r
+               file = (FileResource) GSS.get().getCurrentSelection();\r
+               userFullName = _userFullName;\r
+               permList = new PermissionsList(images, file.getPermissions(), file.getOwner());\r
+\r
+               GWT.log("FILE PERMISSIONS:"+file.getPermissions());\r
+               // Outer contains inner and buttons.\r
+               final VerticalPanel outer = new VerticalPanel();\r
+               final FocusPanel focusPanel = new FocusPanel(outer);\r
+               // Inner contains generalPanel and permPanel.\r
+               inner = new DecoratedTabPanel();\r
+               inner.setAnimationEnabled(true);\r
+               final VerticalPanel generalPanel = new VerticalPanel();\r
+               final VerticalPanel permPanel = new VerticalPanel();\r
+               final HorizontalPanel buttons = new HorizontalPanel();\r
+               final HorizontalPanel permButtons = new HorizontalPanel();\r
+               final HorizontalPanel permForAll = new HorizontalPanel();\r
+               final HorizontalPanel pathPanel = new HorizontalPanel();\r
+               final VerticalPanel verPanel = new VerticalPanel();\r
+               final HorizontalPanel vPanel = new HorizontalPanel();\r
+               final HorizontalPanel vPanel2 = new HorizontalPanel();\r
+\r
+               versioned.setValue(file.isVersioned());\r
+               versioned.getElement().setId("filePropertiesDialog.chechBox.versioned");\r
+               inner.add(generalPanel, "General");\r
+               inner.add(permPanel, "Sharing");\r
+               inner.add(verPanel, "Versions");\r
+               inner.selectTab(0);\r
+\r
+               final Label fileNameNote = new Label("Please note that slashes ('/') are not allowed in file names.", true);\r
+               fileNameNote.setVisible(false);\r
+               fileNameNote.setStylePrimaryName("gss-readForAllNote");\r
+\r
+               final FlexTable generalTable = new FlexTable();\r
+               generalTable.setText(0, 0, "Name");\r
+               generalTable.setText(1, 0, "Folder");\r
+               generalTable.setText(2, 0, "Owner");\r
+               generalTable.setText(3, 0, "Last modified");\r
+               generalTable.setText(4, 0, "Tags");\r
+               name.setWidth("100%");\r
+               name.setText(file.getName());\r
+               name.getElement().setId("filePropertiesDialog.textBox.name");\r
+               generalTable.setWidget(0, 1, name);\r
+               name.addChangeHandler(new ChangeHandler() {\r
+\r
+                       @Override\r
+                       public void onChange(ChangeEvent event) {\r
+                               if(name.getText().contains("/"))\r
+                                       fileNameNote.setVisible(true);\r
+                               else\r
+                                       fileNameNote.setVisible(false);\r
+\r
+                       }\r
+               });\r
+\r
+               if(file.getFolderName() != null)\r
+                       generalTable.setText(1, 1, file.getFolderName());\r
+               else\r
+                       generalTable.setText(1, 1, "-");\r
+               generalTable.setWidget(0, 2, fileNameNote);\r
+               generalTable.setText(2, 1,userFullName);\r
+\r
+               final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");\r
+               generalTable.setText(3, 1, formatter.format(file.getModificationDate()));\r
+               // Get the tags.\r
+               StringBuffer tagsBuffer = new StringBuffer();\r
+               Iterator i = file.getTags().iterator();\r
+               while (i.hasNext()) {\r
+                       String tag = (String) i.next();\r
+                       tagsBuffer.append(tag).append(", ");\r
+               }\r
+               if (tagsBuffer.length() > 1)\r
+                       tagsBuffer.delete(tagsBuffer.length() - 2, tagsBuffer.length() - 1);\r
+               initialTagText = tagsBuffer.toString();\r
+               tags.setWidth("100%");\r
+               tags.getElement().setId("filePropertiesDialog.textBox.tags");\r
+               tags.setText(initialTagText);\r
+               generalTable.setWidget(4, 1, tags);\r
+               generalTable.getFlexCellFormatter().setStyleName(0, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(2, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(3, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(4, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(0, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(1, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(2, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(3, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(4, 1, "props-values");\r
+               generalTable.setCellSpacing(4);\r
+\r
+               // Create the 'OK' button, along with a listener that hides the dialog\r
+               // when the button is clicked.\r
+               final Button ok = new Button("OK", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               if(name.getText().contains("/"))\r
+                                       fileNameNote.setVisible(true);\r
+                               else{\r
+                                       fileNameNote.setVisible(false);\r
+                                       accept();\r
+                                       closeDialog();\r
+                               }               \r
+                       }\r
+               });\r
+               ok.getElement().setId("filePropertiesDialog.button.ok");                \r
+               buttons.add(ok);\r
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
+               // Create the 'Cancel' button, along with a listener that hides the\r
+               // dialog when the button is clicked.\r
+               final Button cancel = new Button("Cancel", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               closeDialog();\r
+                       }\r
+               });\r
+               cancel.getElement().setId("filePropertiesDialog.button.cancel");\r
+               buttons.add(cancel);\r
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               buttons.setSpacing(8);\r
+               buttons.addStyleName("gss-TabPanelBottom");\r
+\r
+               generalPanel.add(generalTable);\r
+\r
+               // Asynchronously retrieve the tags defined by this user.\r
+               DeferredCommand.addCommand(new Command() {\r
+\r
+                       @Override\r
+                       public void execute() {\r
+                               updateTags();\r
+                       }\r
+               });\r
+\r
+               DisclosurePanel allTags = new DisclosurePanel("All tags");\r
+               allTagsContent = new FlowPanel();\r
+               allTagsContent.setWidth("100%");\r
+               allTags.setContent(allTagsContent);\r
+               generalPanel.add(allTags);\r
+               generalPanel.setSpacing(4);\r
+\r
+               final Button add = new Button("Add Group", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               PermissionsAddDialog dlg = new PermissionsAddDialog(groups, permList, false);\r
+                               dlg.center();\r
+                       }\r
+               });\r
+               add.getElement().setId("filePropertiesDialog.button.addGroup");\r
+               permButtons.add(add);\r
+               permButtons.setCellHorizontalAlignment(add, HasHorizontalAlignment.ALIGN_CENTER);\r
+\r
+               final Button addUser = new Button("Add User", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               PermissionsAddDialog dlg = new PermissionsAddDialog(groups, permList, true);\r
+                               dlg.center();\r
+                       }\r
+               });\r
+               add.getElement().setId("filePropertiesDialog.button.addUser");\r
+               permButtons.add(addUser);\r
+               permButtons.setCellHorizontalAlignment(addUser, HasHorizontalAlignment.ALIGN_CENTER);\r
+\r
+               permButtons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               permButtons.setSpacing(8);\r
+               permButtons.addStyleName("gss-TabPanelBottom");\r
+\r
+               final Label readForAllNote = new Label("When this option is enabled, the file will be readable" +\r
+                                       " by everyone. By checking this option, you are certifying that you have the right to " +\r
+                                       "distribute this file and that it does not violate the Terms of Use.", true);\r
+               readForAllNote.setVisible(false);\r
+               readForAllNote.setStylePrimaryName("gss-readForAllNote");\r
+\r
+               readForAll = new CheckBox();\r
+               readForAll.getElement().setId("filePropertiesDialog.checkBox.public");\r
+               readForAll.setValue(file.isReadForAll());\r
+               readForAll.addClickHandler(new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               readForAllNote.setVisible(readForAll.getValue());\r
+                       }\r
+\r
+               });\r
+\r
+               permPanel.add(permList);\r
+               permPanel.add(permButtons);\r
+               // Only show the read for all permission if the user is the owner.\r
+               if (file.getOwner().equals(GSS.get().getCurrentUserResource().getUsername())) {\r
+                       permForAll.add(new Label("Public"));\r
+                       permForAll.add(readForAll);\r
+                       permForAll.setSpacing(8);\r
+                       permForAll.addStyleName("gss-TabPanelBottom");\r
+                       permForAll.add(readForAllNote);\r
+                       permPanel.add(permForAll);\r
+               }\r
+\r
+               TextBox path = new TextBox();\r
+               path.setWidth("100%");\r
+               path.addClickHandler(new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               GSS.enableIESelection();\r
+                               ((TextBox) event.getSource()).selectAll();\r
+                               GSS.preventIESelection();\r
+                       }\r
+\r
+               });\r
+               path.setText(file.getUri());\r
+               path.getElement().setId("filePropertiesDialog.textBox.link");\r
+               path.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");\r
+               path.setWidth("100%");\r
+               path.setReadOnly(true);\r
+               pathPanel.setWidth("100%");\r
+               pathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);\r
+               pathPanel.add(new Label("Link"));\r
+               pathPanel.setSpacing(8);\r
+               pathPanel.addStyleName("gss-TabPanelBottom");\r
+               pathPanel.add(path);\r
+               permPanel.add(pathPanel);\r
+\r
+               VersionsList verList = new VersionsList(this, images, bodies);\r
+               verPanel.add(verList);\r
+\r
+               vPanel.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               vPanel.setSpacing(8);\r
+               vPanel.addStyleName("gss-TabPanelBottom");\r
+               vPanel.add(new Label("Versioned"));\r
+\r
+               vPanel.add(versioned);\r
+               verPanel.add(vPanel);\r
+               vPanel2.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               vPanel2.setSpacing(8);\r
+               vPanel2.addStyleName("gss-TabPanelBottom");\r
+               Button removeVersionsButton = new Button(AbstractImagePrototype.create(images.delete()).getHTML(), new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               ConfirmationDialog confirm = new ConfirmationDialog("Really " +\r
+                                               "remove all previous versions?", "Remove") {\r
+\r
+                                       @Override\r
+                                       public void cancel() {\r
+                                       }\r
+\r
+                                       @Override\r
+                                       public void confirm() {\r
+                                               FilePropertiesDialog.this.closeDialog();\r
+                                               removeAllOldVersions();\r
+                                       }\r
+\r
+                               };\r
+                               confirm.center();\r
+                       }\r
+\r
+               });\r
+               HTML removeAllVersion = new HTML("<span>Remove all previous versions?</span>");\r
+               vPanel2.add(removeAllVersion);\r
+               vPanel2.add(removeVersionsButton);\r
+               verPanel.add(vPanel2);\r
+               if(!file.isVersioned())\r
+                       vPanel2.setVisible(false);\r
+               outer.add(inner);\r
+               outer.add(buttons);\r
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
+               outer.addStyleName("gss-TabPanelBottom");\r
+\r
+               focusPanel.setFocus(true);\r
+               setWidget(outer);\r
+       }\r
+\r
+\r
+       /**\r
+        * Accepts any change and updates the file\r
+        *\r
+        */\r
+       @Override\r
+       protected void accept() {\r
+               String newFilename = null;\r
+               permList.updatePermissionsAccordingToInput();\r
+               Set<PermissionHolder> perms = permList.getPermissions();\r
+               JSONObject json = new JSONObject();\r
+               if (!name.getText().equals(file.getName())) {\r
+                       newFilename = name.getText();\r
+                       json.put("name", new JSONString(newFilename));\r
+               }\r
+               if (versioned.getValue() != file.isVersioned())\r
+                       json.put("versioned", JSONBoolean.getInstance(versioned.getValue()));\r
+               //only update the read for all perm if the user is the owner\r
+               if (readForAll.getValue() != file.isReadForAll())\r
+                       if (file.getOwner().equals(GSS.get().getCurrentUserResource().getUsername()))\r
+                               json.put("readForAll", JSONBoolean.getInstance(readForAll.getValue()));\r
+               int i = 0;\r
+               if (permList.hasChanges()) {\r
+                       GWT.log("Permissions change", null);\r
+                       JSONArray perma = new JSONArray();\r
+\r
+                       for (PermissionHolder p : perms) {\r
+                               JSONObject po = new JSONObject();\r
+                               if (p.getUser() != null)\r
+                                       po.put("user", new JSONString(p.getUser()));\r
+                               if (p.getGroup() != null)\r
+                                       po.put("group", new JSONString(p.getGroup()));\r
+                               po.put("read", JSONBoolean.getInstance(p.isRead()));\r
+                               po.put("write", JSONBoolean.getInstance(p.isWrite()));\r
+                               po.put("modifyACL", JSONBoolean.getInstance(p.isModifyACL()));\r
+                               perma.set(i, po);\r
+                               i++;\r
+                       }\r
+                       json.put("permissions", perma);\r
+               }\r
+               JSONArray taga = new JSONArray();\r
+               i = 0;\r
+               if (!tags.getText().equals(initialTagText)) {\r
+                       String[] tagset = tags.getText().split(",");\r
+                       for (String t : tagset) {\r
+                               JSONString to = new JSONString(t);\r
+                               taga.set(i, to);\r
+                               i++;\r
+                       }\r
+                       json.put("tags", taga);\r
+               }\r
+               String jsonString = json.toString();\r
+               if(jsonString.equals("{}")){\r
+                       GWT.log("NO CHANGES", null);\r
+                       return;\r
+               }\r
+               final String newFilenameFinal = newFilename;\r
+               PostCommand cf = new PostCommand(file.getUri() + "?update=", jsonString, 200) {\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               GSS.get().getTreeView().refreshCurrentNode(false);\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               if (t instanceof RestException) {\r
+                                       int statusCode = ((RestException) t).getHttpStatusCode();\r
+                                       if (statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary permissions");\r
+                                       else if (statusCode == 404)\r
+                                               GSS.get().displayError("User in permissions does not exist");\r
+                                       else if (statusCode == 409)\r
+                                               GSS.get().displayError("A file with the same name already exists");\r
+                                       else if (statusCode == 413)\r
+                                               GSS.get().displayError("Your quota has been exceeded");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to modify file:" + ((RestException) t).getHttpStatusText());\r
+                               } else\r
+                                       GSS.get().displayError("System error modifying file:" + t.getMessage());\r
+                       }\r
+\r
+               };\r
+               DeferredCommand.addCommand(cf);\r
+\r
+       }\r
+\r
+       private void removeAllOldVersions() {\r
+               JSONObject json = new JSONObject();\r
+               json.put("versioned", JSONBoolean.getInstance(false));\r
+               GWT.log(json.toString(), null);\r
+               PostCommand cf = new PostCommand(file.getUri() + "?update=", json.toString(), 200) {\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               toggleVersioned(true);\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               if (t instanceof RestException) {\r
+                                       int statusCode = ((RestException) t).getHttpStatusCode();\r
+                                       if (statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary permissions");\r
+                                       else if (statusCode == 404)\r
+                                               GSS.get().displayError("User in permissions does not exist");\r
+                                       else if (statusCode == 409)\r
+                                               GSS.get().displayError("A folder with the same name already exists");\r
+                                       else if (statusCode == 413)\r
+                                               GSS.get().displayError("Your quota has been exceeded");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to modify file:" + ((RestException) t).getHttpStatusText());\r
+                               } else\r
+                                       GSS.get().displayError("System error moifying file:" + t.getMessage());\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(cf);\r
+       }\r
+\r
+       private void toggleVersioned(boolean versionedValue) {\r
+               JSONObject json = new JSONObject();\r
+               json.put("versioned", JSONBoolean.getInstance(versionedValue));\r
+               GWT.log(json.toString(), null);\r
+               PostCommand cf = new PostCommand(file.getUri() + "?update=", json.toString(), 200) {\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               GSS.get().getTreeView().refreshCurrentNode(false);\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               if (t instanceof RestException) {\r
+                                       int statusCode = ((RestException) t).getHttpStatusCode();\r
+                                       if (statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary permissions");\r
+                                       else if (statusCode == 404)\r
+                                               GSS.get().displayError("User in permissions does not exist");\r
+                                       else if (statusCode == 409)\r
+                                               GSS.get().displayError("A folder with the same name already exists");\r
+                                       else if (statusCode == 413)\r
+                                               GSS.get().displayError("Your quota has been exceeded");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to modify file:" + ((RestException) t).getHttpStatusText());\r
+                               } else\r
+                                       GSS.get().displayError("System error moifying file:" + t.getMessage());\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(cf);\r
+       }\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/FileTable.java b/src/org/gss_project/gss/web/client/FileTable.java
new file mode 100644 (file)
index 0000000..3f3f028
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+
+
+/**
+ * @author kman
+ *
+ */
+public class FileTable extends Grid{
+
+       /**
+        *
+        */
+       public FileTable() {
+               super();
+               // TODO Auto-generated constructor stub
+       }
+
+       /**
+        * @param rows
+        * @param columns
+        */
+       public FileTable(int rows, int columns) {
+               super(rows, columns);
+               // TODO Auto-generated constructor stub
+       }
+
+       public int getRowForEvent2(Event event) {
+           Element td = getEventTargetCell(event);
+           if (td == null)
+                       return -1;
+
+           Element tr = DOM.getParent(td);
+           Element body = DOM.getParent(tr);
+           int row = DOM.getChildIndex(body, tr);
+           return row;
+         }
+       
+       public static void copyRow(FileTable sourceTable, FileTable targetTable, int sourceRow, int targetRow) {
+               targetTable.insertRow(targetRow);
+               for (int col = 0; col < sourceTable.getCellCount(sourceRow); col++) {
+                       HTML html = new HTML(sourceTable.getHTML(sourceRow, col));
+                       targetTable.setWidget(targetRow, col, html);
+               }
+               copyRowStyle(sourceTable, targetTable, sourceRow, targetRow);
+       }
+
+       private static void copyRowStyle(FileTable sourceTable, FileTable targetTable, int sourceRow, int targetRow) {
+               String rowStyle = sourceTable.getRowFormatter().getStyleName(sourceRow);
+               targetTable.getRowFormatter().setStyleName(targetRow, rowStyle);
+       }
+
+       public static int getWidgetRow(Widget widget, FileTable table) {
+           for (int row = 0; row < table.getRowCount(); row++)
+                       for (int col = 0; col < table.getCellCount(row); col++) {
+                           Widget w = table.getWidget(row, col);
+                           if (w == widget)
+                                       return row;
+                         }
+           throw new RuntimeException("Unable to determine widget row");
+         }
+
+}
diff --git a/src/org/gss_project/gss/web/client/FileUploadDialog.java b/src/org/gss_project/gss/web/client/FileUploadDialog.java
new file mode 100644 (file)
index 0000000..d8c91b9
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+import org.gss_project.gss.web.client.rest.resource.UploadStatusResource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.FileUpload;
+import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
+import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
+import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
+import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.Hidden;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * The 'File upload' dialog box implementation.
+ */
+public class FileUploadDialog extends DialogBox implements Updateable {
+
+       protected int prgBarInterval = 1500;
+
+       private ProgressBar progressBar;
+
+       protected RepeatingTimer repeater = new RepeatingTimer(this, prgBarInterval);
+
+       public static final boolean DONE = true;
+
+       /**
+        * The Form element that performs the file upload.
+        */
+       private final FormPanel form = new FormPanel();
+
+       private final FileUpload upload = new FileUpload();
+
+       protected final Label filenameLabel = new Label("");
+
+       protected List<FileResource> files;
+
+       protected boolean cancelEvent = false;
+
+       protected String fileNameToUse;
+
+       protected FolderResource folder;
+
+       /**
+        * The widget's constructor.
+        */
+       public FileUploadDialog() {
+               // Set the dialog's caption.
+               setText("File upload");
+               setAnimationEnabled(true);
+               // Since we're going to add a FileUpload widget, we'll need to set the
+               // form to use the POST method, and multipart MIME encoding.
+               form.setEncoding(FormPanel.ENCODING_MULTIPART);
+               form.setMethod(FormPanel.METHOD_POST);
+
+               // Create a panel to hold all of the form widgets.
+               VerticalPanel panel = new VerticalPanel();
+               form.setWidget(panel);
+               final HTML info = new HTML("You may select a file to upload. Install" +
+                               " <a href='http://gears.google.com/' target='_blank'>Google " +
+                               "Gears</a><br> for uploading multiple files simultaneously.");
+               info.addStyleName("gss-uploadNote");
+               panel.add(info);
+               final Hidden date = new Hidden("Date", "");
+               panel.add(date);
+               final Hidden auth = new Hidden("Authorization", "");
+               panel.add(auth);
+               // Add an informative label with the folder name.
+               Object selection = GSS.get().getTreeView().getSelection();
+               folder = ((RestResourceWrapper) selection).getResource();
+               upload.setName("file");
+               filenameLabel.setText("");
+               filenameLabel.setVisible(false);
+               filenameLabel.setStyleName("props-labels");
+               HorizontalPanel fileUloadPanel = new HorizontalPanel();
+               fileUloadPanel.add(filenameLabel);
+               fileUloadPanel.add(upload);
+               upload.getElement().setId("fileUploadDiallog.uploadPanel");
+               Grid generalTable = new Grid(2, 2);
+               generalTable.setText(0, 0, "Folder");
+               generalTable.setText(1, 0, "File");
+               generalTable.setText(0, 1, folder.getName());
+               generalTable.setWidget(1, 1, fileUloadPanel);
+               generalTable.getCellFormatter().setStyleName(0, 0, "props-labels");
+               generalTable.getCellFormatter().setStyleName(1, 0, "props-labels");
+               generalTable.getCellFormatter().setStyleName(0, 1, "props-values");
+               generalTable.getCellFormatter().setStyleName(1, 1, "props-values");
+               generalTable.setCellSpacing(4);
+
+               panel.add(generalTable);
+
+               // Create a panel to hold the buttons.
+               HorizontalPanel buttons = new HorizontalPanel();
+
+               // Create the 'upload' button, along with a listener that submits the
+               // form.
+               final Button submit = new Button("Upload", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               prepareAndSubmit();
+                       }
+               });
+               submit.getElement().setId("fileUploadDialog.button.upload");
+               buttons.add(submit);
+               buttons.setCellHorizontalAlignment(submit, HasHorizontalAlignment.ALIGN_CENTER);
+               // Create the 'Cancel' button, along with a listener that hides the
+               // dialog when the button is clicked.
+               final Button cancel = new Button("Cancel", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               repeater.finish();
+                               hide();
+                       }
+               });
+               cancel.getElement().setId("fileUploadDialog.button.cancel");
+               buttons.add(cancel);
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+               buttons.setSpacing(8);
+               buttons.addStyleName("gss-DialogBox");
+
+               // Add an event handler to the form.
+               form.addSubmitHandler(new SubmitHandler() {
+
+                       @Override
+                       public void onSubmit(SubmitEvent event) {
+                               GSS app = GSS.get();
+                               // This event is fired just before the form is submitted. We can
+                               // take this opportunity to perform validation.
+                               if (upload.getFilename().length() == 0) {
+                                       app.displayError("You must select a file!");
+                                       event.cancel();
+                                       hide();
+                               } else {
+
+                                       canContinue();
+                                       GWT.log("Cancel:" + cancelEvent, null);
+                                       if (cancelEvent) {
+                                               cancelEvent = false;
+                                               app.displayError("The specified file name already exists in this folder");
+                                               event.cancel();
+                                               hide();
+                                       } else {
+
+                                               fileNameToUse = getFilename(upload.getFilename());
+                                               String apath;
+                                               FileResource selectedFile = getFileForName(fileNameToUse);
+                                               if (selectedFile == null ) {
+                                                       //we are going to create a file
+                                                       apath = folder.getUri();
+                                                       if (!apath.endsWith("/"))
+                                                               apath = apath + "/";
+                                                       apath = apath + encodeComponent(fileNameToUse);
+                                               } else
+                                                       apath = selectedFile.getUri();
+                                               form.setAction(apath);
+                                               String dateString = RestCommand.getDate();
+                                               String resource = apath.substring(app.getApiPath().length() - 1, apath.length());
+                                               String sig = RestCommand.calculateSig("POST", dateString, resource, RestCommand.base64decode(app.getToken()));
+                                               date.setValue(dateString);
+                                               auth.setValue(app.getCurrentUserResource().getUsername() + " " + sig);
+                                               GWT.log("FolderPATH:" + folder.getUri(), null);
+                                               submit.setEnabled(false);
+                                               upload.setVisible(false);
+                                               filenameLabel.setText(fileNameToUse);
+                                               filenameLabel.setVisible(true);
+                                               repeater.start();
+                                               progressBar.setVisible(true);
+                                       }
+                               }
+
+                       }
+               });
+               form.addSubmitCompleteHandler(new SubmitCompleteHandler() {
+
+                       @Override
+                       public void onSubmitComplete(SubmitCompleteEvent event) {
+                               // When the form submission is successfully completed, this
+                               // event is fired. Assuming the service returned a response
+                               // of type text/html, we can get the result text here (see
+                               // the FormPanel documentation for further explanation).
+                               String results = event.getResults();
+
+                               // Unfortunately the results are never empty, even in
+                               // the absense of errors, so we have to check for '<pre></pre>'.
+                               if (!results.equalsIgnoreCase("<pre></pre>")) {
+                                       GWT.log(results, null);
+                                       GSS.get().displayError(results);
+                               }
+                               progressBar.setProgress(100);
+                               cancelUpload();
+                               GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());
+                               GSS.get().getStatusPanel().updateStats();
+
+                       }
+               });
+
+
+               panel.add(buttons);
+               progressBar = new ProgressBar(50, ProgressBar.SHOW_TIME_REMAINING);
+               panel.add(progressBar);
+               progressBar.setVisible(false);
+               panel.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
+               panel.setCellHorizontalAlignment(progressBar, HasHorizontalAlignment.ALIGN_CENTER);
+               panel.addStyleName("gss-DialogBox");
+               addStyleName("gss-DialogBox");
+               setWidget(form);
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+                       // Use the popup's key preview hooks to close the dialog when either
+                       // enter or escape is pressed.
+                       switch (evt.getKeyCode()) {
+                               case KeyCodes.KEY_ENTER:
+                                       prepareAndSubmit();
+                                       break;
+                               case KeyCodes.KEY_ESCAPE:
+                                       cancelUpload();
+                                       break;
+                       }
+       }
+
+
+
+       /**
+        * Cancels the file upload.
+        */
+       private void cancelUpload() {
+               repeater.finish();
+               hide();
+       }
+
+       /**
+        * Make any last minute checks and start the upload.
+        */
+       public void prepareAndSubmit() {
+               final String fname = getFilename(upload.getFilename());
+               if (getFileForName(fname) == null) {
+                       //we are going to create a file, so we check to see if there is a trashed file with the same name
+                       FileResource same = null;
+                       for (FileResource fres : folder.getFiles())
+                               if (fres.isDeleted() && fres.getName().equals(fname))
+                                       same = fres;
+                       if (same == null)
+                               form.submit();
+                       else {
+                               final FileResource sameFile = same;
+                               GWT.log("Same deleted file", null);
+                               ConfirmationDialog confirm = new ConfirmationDialog("A file with " +
+                                               "the same name exists in the trash. If you continue,<br/>the trashed " +
+                                               "file  '" + fname + "' will be renamed automatically for you.", "Continue") {
+
+                                       @Override
+                                       public void cancel() {
+                                               FileUploadDialog.this.hide();
+                                       }
+
+                                       @Override
+                                       public void confirm() {
+                                               updateTrashedFile(getBackupFilename(fname), sameFile);
+                                       }
+
+                               };
+                               confirm.center();
+                       }
+               }
+               else {
+                       // We are going to update an existing file, so show a confirmation dialog.
+                       ConfirmationDialog confirm = new ConfirmationDialog("Are you sure " +
+                                       "you want to update " + fname + "?", "Update") {
+
+                               @Override
+                               public void cancel() {
+                                       FileUploadDialog.this.hide();
+                               }
+
+                               @Override
+                               public void confirm() {
+                                       form.submit();
+                               }
+
+                       };
+                       confirm.center();
+               }
+       }
+
+       /**
+        * Returns the file name from a potential full path argument. Apparently IE
+        * insists on sending the full path name of a file when uploading, forcing
+        * us to trim the extra path info. Since this is only observed on Windows we
+        * get to check for a single path separator value.
+        *
+        * @param name the potentially full path name of a file
+        * @return the file name without extra path information
+        */
+       protected String getFilename(String name) {
+               int pathSepIndex = name.lastIndexOf("\\");
+               if (pathSepIndex == -1) {
+                       pathSepIndex = name.lastIndexOf("/");
+                       if (pathSepIndex == -1)
+                               return name;
+               }
+               return name.substring(pathSepIndex + 1);
+       }
+
+       /**
+        * Check whether the file name exists in selected folder.
+        *
+        * @return
+        */
+       private boolean canContinue() {
+               if (files == null)
+                       return false;
+               String fileName = getFilename(upload.getFilename());
+               if (getFileForName(fileName) == null) {
+                       // For file creation, check to see if the file already exists.
+                       GWT.log("filename to upload:" + fileName, null);
+                       for (FileResource dto : files) {
+                               GWT.log("Check:" + dto.getName() + "/" + fileName, null);
+                               if (!dto.isDeleted() && dto.getName().equals(fileName)) {
+                                       cancelEvent = true;
+                                       return true;
+                               }
+                       }
+               }
+               return true;
+       }
+
+       class RepeatingTimer extends Timer {
+
+               private Updateable updateable;
+
+               private int interval = 1500;
+
+               private boolean running = true;
+
+               RepeatingTimer(Updateable _updateable, int _interval) {
+                       updateable = _updateable;
+                       interval = _interval;
+               }
+
+               @Override
+               public void run() {
+                       updateable.update();
+               }
+
+               public void start() {
+                       running = true;
+
+                       scheduleRepeating(interval);
+               }
+
+               public void finish() {
+                       running = false;
+                       cancel();
+               }
+
+               public int getInterval() {
+                       return interval;
+               }
+
+               public void setInterval(int anInterval) {
+                       if (interval != anInterval) {
+                               interval = anInterval;
+                               if (running) {
+                                       finish();
+                                       start();
+                               }
+                       }
+               }
+       }
+
+       @Override
+       public void update() {
+               String apath = folder.getUri();
+               if (!apath.endsWith("/"))
+                       apath = apath + "/";
+               apath = apath + encodeComponent(fileNameToUse) + "?progress=" + encodeComponent(fileNameToUse);
+               GetCommand eg = new GetCommand<UploadStatusResource>(UploadStatusResource.class, apath, false, null) {
+
+                       @Override
+                       public void onComplete() {
+                               UploadStatusResource res = getResult();
+                               progressBar.setProgress(res.percent());
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                       }
+
+               };
+               DeferredCommand.addCommand(eg);
+       }
+
+       protected String getBackupFilename(String filename) {
+               List<FileResource> filesInSameFolder = new ArrayList<FileResource>();
+               for (FileResource deleted : folder.getFiles())
+                       if (deleted.isDeleted())
+                               filesInSameFolder.add(deleted);
+               int i = 1;
+               for (FileResource same : filesInSameFolder)
+                       if (same.getName().startsWith(filename)) {
+                               String toCheck = same.getName().substring(filename.length(), same.getName().length());
+                               if (toCheck.startsWith(" ")) {
+                                       int test = -1;
+                                       try {
+                                               test = Integer.valueOf(toCheck.replace(" ", ""));
+                                       } catch (NumberFormatException e) {
+                                               // Do nothing since string is not a number.
+                                       }
+                                       if (test >= i)
+                                               i = test + 1;
+                               }
+                       }
+
+               return filename + " " + i;
+       }
+
+       /**
+        * Rename the conflicting trashed file with the supplied new name.
+        */
+       private void updateTrashedFile(String newName, FileResource trashedFile) {
+               JSONObject json = new JSONObject();
+               json.put("name", new JSONString(newName));
+               PostCommand cf = new PostCommand(trashedFile.getUri() + "?update=", json.toString(), 200) {
+
+                       @Override
+                       public void onComplete() {
+                               form.submit();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GSS app = GSS.get();
+                               GWT.log("", t);
+                               if (t instanceof RestException) {
+                                       int statusCode = ((RestException) t).getHttpStatusCode();
+                                       if (statusCode == 405)
+                                               app.displayError("You don't have the necessary permissions");
+                                       else if (statusCode == 404)
+                                               app.displayError("User in permissions does not exist");
+                                       else if (statusCode == 409)
+                                               app.displayError("A file with the same name already exists");
+                                       else if (statusCode == 413)
+                                               app.displayError("Your quota has been exceeded");
+                                       else
+                                               app.displayError("Unable to modify file:" + ((RestException) t).getHttpStatusText());
+                               } else
+                                       app.displayError("System error modifying file:" + t.getMessage());
+                       }
+
+               };
+               DeferredCommand.addCommand(cf);
+       }
+
+       protected FileResource getFileForName(String name){
+               for (FileResource f : folder.getFiles())
+                       if (!f.isDeleted() && f.getName().equals(name))
+                               return f;
+               return null;
+       }
+
+
+       /**
+        * Same as URL.encodeComponent, but also
+        * encode apostrophe since browsers aren't consistent about it
+        * (FF encodes, IE does not).
+        */
+       private String encodeComponent(String decodedURLComponent) {
+               String retv = URL.encodeComponent(decodedURLComponent);
+               retv = retv.replaceAll("'", "%27");
+               return retv;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFiles the files to set
+        */
+       public void setFiles(List<FileResource> newFiles) {
+               files = newFiles;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/FileUploadGearsDialog.java b/src/org/gss_project/gss/web/client/FileUploadGearsDialog.java
new file mode 100644 (file)
index 0000000..66779af
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.gears.client.Factory;
+import com.google.gwt.gears.client.desktop.Desktop;
+import com.google.gwt.gears.client.desktop.File;
+import com.google.gwt.gears.client.desktop.OpenFilesHandler;
+import com.google.gwt.gears.client.httprequest.HttpRequest;
+import com.google.gwt.gears.client.httprequest.ProgressEvent;
+import com.google.gwt.gears.client.httprequest.ProgressHandler;
+import com.google.gwt.gears.client.httprequest.RequestCallback;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * The 'File upload' dialog box implementation with Google Gears support.
+ */
+public class FileUploadGearsDialog extends FileUploadDialog implements Updateable {
+
+       protected final Factory factory = Factory.getInstance();
+
+       /**
+        * The array of files to upload.
+        */
+       private File[] fileObjects;
+
+       /**
+        * A list of files to upload, created from files array. Used to signal
+        * finished state when empty.
+        */
+       protected List<File> selectedFiles = new ArrayList<File>();
+
+       /**
+        * The list of progress bars for individual files.
+        */
+       protected List<ProgressBar> progressBars = new ArrayList<ProgressBar>();
+
+       private Button browse;
+
+       private Button submit;
+
+       private FlexTable generalTable;
+
+       private Map<String, FileResource> toRename;
+
+       protected List<HttpRequest> requests = new ArrayList<HttpRequest>();
+       
+       private boolean canContinue = true;
+
+       /**
+        * The widget's constructor.
+        */
+       public FileUploadGearsDialog() {
+               // Set the dialog's caption.
+               setText("File upload");
+               setAnimationEnabled(true);
+               // Create a panel to hold all of the dialog widgets.
+               VerticalPanel panel = new VerticalPanel();
+               final HTML info = new HTML("You may select one or more files to upload.");
+               info.addStyleName("gss-uploadNote");
+               panel.add(info);
+               // Add an informative label with the folder name.
+               Object selection = GSS.get().getTreeView().getSelection();
+               folder = ((RestResourceWrapper) selection).getResource();
+
+               browse = new Button("Browse...");
+
+               HorizontalPanel fileUploadPanel = new HorizontalPanel();
+               fileUploadPanel.add(browse);
+
+               generalTable = new FlexTable();
+               generalTable.setText(0, 0, "Folder");
+               generalTable.setText(1, 0, "File");
+               generalTable.setText(0, 1, folder.getName());
+               generalTable.setWidget(1, 1, fileUploadPanel);
+               generalTable.getCellFormatter().setStyleName(0, 0, "props-labels");
+               generalTable.getCellFormatter().setStyleName(1, 0, "props-labels");
+               generalTable.getCellFormatter().setStyleName(0, 1, "props-values");
+               generalTable.getCellFormatter().setStyleName(1, 1, "props-values");
+               generalTable.setCellSpacing(4);
+
+               panel.add(generalTable);
+
+               // Create a panel to hold the buttons.
+               HorizontalPanel buttons = new HorizontalPanel();
+
+               submit = new Button("Upload");
+               submit.addClickHandler(new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               prepareAndSubmit();
+                       }
+               });
+               submit.setEnabled(false);
+               buttons.add(submit);
+               buttons.setCellHorizontalAlignment(submit, HasHorizontalAlignment.ALIGN_CENTER);
+               // Create the 'Cancel' button, along with a listener that hides the
+               // dialog when the button is clicked.
+               Button cancel = new Button("Cancel", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               canContinue = false;                            
+                               cancelUpload();                         
+                               GSS.get().showFileList(true);
+                       }
+               });
+               buttons.add(cancel);
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+               buttons.setSpacing(8);
+               buttons.addStyleName("gss-DialogBox");
+
+               browse.addClickHandler(new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               Desktop desktop = factory.createDesktop();
+                               desktop.openFiles(new OpenFilesHandler() {
+
+                                       @Override
+                                       public void onOpenFiles(OpenFilesEvent ofevent) {
+                                               fileObjects = ofevent.getFiles();
+                                               selectedFiles.addAll(Arrays.asList(fileObjects));
+                                               for (int i = 0; i< selectedFiles.size(); i++) {
+                                                       generalTable.setText(i+1, 0, "File");
+                                                       generalTable.setText(i+1, 1, selectedFiles.get(i).getName());
+                                                       ProgressBar progress = new ProgressBar(20, 0);
+                                                       generalTable.setWidget(i+1, 2, progress);
+                                                       progressBars.add(progress);
+                                                       generalTable.getCellFormatter().setStyleName(i+1, 0, "props-labels");
+                                                       generalTable.getCellFormatter().setStyleName(i+1, 1, "props-values");
+                                               }
+                                               submit.setEnabled(true);
+                                       }
+                               });
+                       }
+               });
+
+               panel.add(buttons);
+               panel.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
+               panel.addStyleName("gss-DialogBox");
+               addStyleName("gss-DialogBox");
+               setWidget(panel);
+       }
+
+       /**
+        * Cancels the file upload.
+        */
+       private void cancelUpload() {
+               for (HttpRequest request: requests)
+                       request.abort();
+               hide();         
+       }
+
+       /**
+        * Check whether the specified file name exists in the selected folder.
+        */
+       private boolean canContinue(File file) {
+               String fileName = getFilename(file.getName());
+               if (getFileForName(fileName) == null)
+                       // For file creation, check to see if the file already exists.
+                       for (FileResource fileRes : files)
+                               if (!fileRes.isDeleted() && fileRes.getName().equals(fileName))
+                                       return false;
+               return true;
+       }
+
+       @Override
+       public void prepareAndSubmit() {
+               GSS app = GSS.get();
+               if (selectedFiles.size() == 0) {
+                       app.displayError("You must select a file!");
+                       hide();
+                       return;
+               }
+               for (File file: selectedFiles)
+                       if (!canContinue(file)) {
+                               app.displayError("The file name " + file.getName() +
+                                                       " already exists in this folder");
+                               hide();
+                               return;
+                       }
+               submit.setEnabled(false);
+               browse.setVisible(false);
+               List<String> toUpdate = new ArrayList<String>();
+               toRename = new HashMap<String, FileResource>();
+               for (File file: selectedFiles) {
+                       String fname = getFilename(file.getName());
+                       if (getFileForName(fname) == null) {
+                               // We are going to create a file, so we check to see if there is a
+                               // trashed file with the same name.
+                               FileResource same = null;
+                               for (FileResource fres : folder.getFiles())
+                                       if (fres.isDeleted() && fres.getName().equals(fname))
+                                               same = fres;
+                               // In that case add it to the list of files to rename.
+                               if (same != null)
+                                       toRename.put(getBackupFilename(fname), same);
+                       } else
+                               // If we are updating a file add it to the list of files to update.
+                               toUpdate.add(fname);
+               }
+
+               if (!toUpdate.isEmpty()) {
+                       StringBuffer sb = new StringBuffer();
+                       for (String name: toUpdate)
+                               sb.append(name).append("<br/>");
+                       // We are going to update existing files, so show a confirmation dialog.
+                       ConfirmationDialog confirm = new ConfirmationDialog("Are you sure " +
+                                       "you want to update the following files?<br/><i>" + sb +
+                                       "</i>", "Update") {
+
+                               @Override
+                               public void cancel() {
+                                       hide();
+                               }
+
+                               @Override
+                               public void confirm() {
+                                       confirmRename();
+                               }
+
+                       };
+                       confirm.center();
+               } else
+                       confirmRename();
+       }
+
+       /**
+        * Confirm the renames of synonymous files already in the trash.
+        */
+       private void confirmRename() {
+               if (!toRename.isEmpty()) {
+                       StringBuffer sb = new StringBuffer();
+                       for (FileResource file: toRename.values())
+                               sb.append(file.getName()).append("<br/>");
+                       ConfirmationDialog confirm = new ConfirmationDialog("Files " +
+                                       "with the following names already exist in the trash. If" +
+                                       " you continue,<br/>the trashed files will be renamed " +
+                                       "automatically for you:<br/><i>" + sb + "</i>", "Continue") {
+
+                               @Override
+                               public void cancel() {
+                                       hide();
+                               }
+
+                               @Override
+                               public void confirm() {
+                                       updateTrashedFiles();
+                               }
+
+                       };
+                       confirm.center();
+               } else
+                       uploadFiles();
+       }
+
+       /**
+        * Rename the conflicting trashed files with the supplied new names.
+        */
+       private void updateTrashedFiles() {
+               for (final String name: toRename.keySet()) {
+                       JSONObject json = new JSONObject();
+                       json.put("name", new JSONString(name));
+                       PostCommand cf = new PostCommand(toRename.get(name).getUri() + "?update=", json.toString(), 200) {
+
+                               @Override
+                               public void onComplete() {
+                                       toRename.remove(name);
+                                       uploadFiles();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GSS app = GSS.get();
+                                       GWT.log("", t);
+                                       if (t instanceof RestException) {
+                                               int statusCode = ((RestException) t).getHttpStatusCode();
+                                               if (statusCode == 405)
+                                                       app.displayError("You don't have the necessary permissions");
+                                               else if (statusCode == 404)
+                                                       app.displayError("User in permissions does not exist");
+                                               else if (statusCode == 409)
+                                                       app.displayError("A file with the same name already exists");
+                                               else if (statusCode == 413)
+                                                       app.displayError("Your quota has been exceeded");
+                                               else
+                                                       app.displayError("Unable to modify file:" + ((RestException) t).getHttpStatusText());
+                                       } else
+                                               app.displayError("System error modifying file:" + t.getMessage());
+                               }
+
+                       };
+                       DeferredCommand.addCommand(cf);
+               }
+       }
+
+       /**
+        * Checks if the renaming step for already trashed files is complete and
+        * starts file uploads.
+        */
+       private void uploadFiles() {            
+               if (!toRename.isEmpty()) return;
+               if (canContinue){                                               
+                       doSend(selectedFiles);
+               }
+       }
+
+       /**
+        * Perform the HTTP request to upload the specified file.
+        */
+       protected void doSend(final List<File> filesRemaining) {
+               final GSS app = GSS.get();
+               HttpRequest request = factory.createHttpRequest();
+               requests.add(request);
+               String method = "PUT";
+
+               String path;
+               final String filename = getFilename(filesRemaining.get(0).getName());
+               path = folder.getUri();
+               if (!path.endsWith("/"))
+                       path = path + "/";
+               path = path + encode(filename);
+
+               String token = app.getToken();
+               String resource = path.substring(app.getApiPath().length()-1, path.length());
+               String date = RestCommand.getDate();
+               String sig = RestCommand.calculateSig(method, date, resource, RestCommand.base64decode(token));
+               request.open(method, path);
+               request.setRequestHeader("X-GSS-Date", date);
+               request.setRequestHeader("Authorization", app.getCurrentUserResource().getUsername() + " " + sig);
+               request.setRequestHeader("Accept", "application/json; charset=utf-8");
+               request.setCallback(new RequestCallback() {
+                       @Override
+                       public void onResponseReceived(HttpRequest req) {
+                               int state = req.getReadyState();
+                               if (state != 4) return;
+                               switch(req.getStatus()) {
+                                       case 201: // Created falls through to updated.
+                                       case 204:
+                                               filesRemaining.remove(0);
+                                               if(filesRemaining.isEmpty()){                                                   
+                                                       finish();
+                                                       break;
+                                               }                                               
+                                               doSend(filesRemaining);                         
+                                               break;
+                                       case 403:
+                                               SessionExpiredDialog dlg = new SessionExpiredDialog();
+                                               dlg.center();
+                                               break;
+                                       case 405:
+                                               app.displayError("You don't have permission to " +
+                                                               "upload file " + filename);
+                                               break;
+                                       case 409:
+                                               app.displayError("A folder with the name " + filename +
+                                                               " already exists at this level");
+                                               break;
+                                       case 413:
+                                               app.displayError("There is not enough free space " +
+                                                               "available for uploading " + filename);
+                                               break;
+                                       default:
+                                               app.displayError("Error uploading file " + filename +
+                                                                       ": " + req.getStatus());
+                               }
+                       }
+               });
+               request.getUpload().setProgressHandler(new ProgressHandler() {
+                       @Override
+                       public void onProgress(ProgressEvent event) {
+                               double pcnt = (double) event.getLoaded() / event.getTotal();
+                               progressBars.get(0).setProgress((int) Math.floor(pcnt * 100));
+                               if(pcnt*100 == 100)
+                                       progressBars.remove(0);
+                       }
+               });
+               request.send(filesRemaining.get(0).getBlob());
+       }
+
+       /**
+        * Perform the final actions after the files are uploaded.
+        */
+       protected void finish() {
+               hide();
+               //GSS.get().showFileList(true);
+               GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());//showFileList(true);
+               GSS.get().getStatusPanel().updateStats();
+       }
+
+       /**
+        * Same as URL.encode, but also encode apostrophe since browsers aren't
+        * consistent about it (FF encodes, IE does not).
+        */
+       protected String encode(String decodedURL) {
+               String retv = decodedURL.replaceAll("@", "_"); // Replace bad character
+               retv = URL.encodeComponent(retv);
+               retv = retv.replaceAll("'", "%27");
+               return retv;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/FileUploadGearsIEDialog.java b/src/org/gss_project/gss/web/client/FileUploadGearsIEDialog.java
new file mode 100644 (file)
index 0000000..2d67373
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import java.util.List;
+
+import org.gss_project.gss.web.client.rest.RestCommand;
+
+import com.google.gwt.gears.client.desktop.File;
+import com.google.gwt.gears.client.httprequest.HttpRequest;
+import com.google.gwt.gears.client.httprequest.ProgressEvent;
+import com.google.gwt.gears.client.httprequest.ProgressHandler;
+import com.google.gwt.gears.client.httprequest.RequestCallback;
+
+/**
+ * The 'File upload' dialog box implementation with Google Gears support
+ * for IE.
+ */
+public class FileUploadGearsIEDialog extends FileUploadGearsDialog implements Updateable {
+
+       /**
+        * Perform the HTTP request to upload the specified file.
+        */     
+       @Override
+       protected void doSend(final List<File> filesRemaining) {
+               final GSS app = GSS.get();
+               HttpRequest request = factory.createHttpRequest();
+               requests.add(request);
+               String method = "POST";
+
+               String path;
+               final String filename = getFilename(filesRemaining.get(0).getName());
+               path = folder.getUri();
+               if (!path.endsWith("/"))
+                       path = path + "/";
+               path = path + encode(filename);
+
+               String token = app.getToken();
+               String resource = path.substring(app.getApiPath().length()-1, path.length());
+               String date = RestCommand.getDate();
+               String sig = RestCommand.calculateSig(method, date, resource, RestCommand.base64decode(token));
+               request.open(method, path);
+               request.setRequestHeader("X-GSS-Date", date);
+               request.setRequestHeader("Authorization", app.getCurrentUserResource().getUsername() + " " + sig);
+               request.setRequestHeader("Accept", "application/json; charset=utf-8");
+               request.setCallback(new RequestCallback() {
+                       @Override
+                       public void onResponseReceived(HttpRequest req) {
+                               // XXX: No error checking, since IE throws an Internal Error
+                               // when accessing req.getStatus().
+                               filesRemaining.remove(0);
+                               if(filesRemaining.isEmpty()){                                   
+                                       finish();                                       
+                               }
+                               doSend(filesRemaining); 
+                       }
+               });
+               request.getUpload().setProgressHandler(new ProgressHandler() {
+                       @Override
+                       public void onProgress(ProgressEvent event) {
+                               double pcnt = (double) event.getLoaded() / event.getTotal();
+                               progressBars.get(0).setProgress((int) Math.floor(pcnt * 100));
+                               if(pcnt*100 == 100)
+                                       progressBars.remove(0);
+                       }
+               });
+               request.send(filesRemaining.get(0).getBlob());
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/FilesPropertiesDialog.java b/src/org/gss_project/gss/web/client/FilesPropertiesDialog.java
new file mode 100644 (file)
index 0000000..f190729
--- /dev/null
@@ -0,0 +1,276 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.components.TristateCheckBox;\r
+import org.gss_project.gss.web.client.rest.MultiplePostCommand;\r
+import org.gss_project.gss.web.client.rest.RestException;\r
+import org.gss_project.gss.web.client.rest.resource.FileResource;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.FocusEvent;\r
+import com.google.gwt.event.dom.client.FocusHandler;\r
+import com.google.gwt.json.client.JSONArray;\r
+import com.google.gwt.json.client.JSONBoolean;\r
+import com.google.gwt.json.client.JSONObject;\r
+import com.google.gwt.json.client.JSONString;\r
+import com.google.gwt.user.client.Command;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.DecoratedTabPanel;\r
+import com.google.gwt.user.client.ui.DisclosurePanel;\r
+import com.google.gwt.user.client.ui.FlexTable;\r
+import com.google.gwt.user.client.ui.FlowPanel;\r
+import com.google.gwt.user.client.ui.FocusPanel;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.Label;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'Multiple file properties' dialog box implementation.\r
+ *\r
+ * @author droutsis\r
+ */\r
+public class FilesPropertiesDialog extends AbstractPropertiesDialog {\r
+\r
+       private final TristateCheckBox versionedCheck;\r
+\r
+       private final List<FileResource> files;\r
+\r
+       private Boolean initialVersioned;\r
+\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        *\r
+        * @param _files\r
+        */\r
+       public FilesPropertiesDialog(final List<FileResource> _files) {\r
+               super();\r
+\r
+               files = _files;\r
+               int versionedNum = 0;\r
+               for (FileResource fr : files)\r
+                       if (fr.isVersioned()) versionedNum++;\r
+               Boolean versioned = null;\r
+               if (versionedNum==0) versioned = false;\r
+               if (versionedNum==files.size()) versioned = true;\r
+               initialVersioned = versioned;\r
+               versionedCheck = new TristateCheckBox(versioned);\r
+\r
+               // Set the dialog's caption.\r
+               setText("Files properties");\r
+\r
+               // Outer contains inner and buttons.\r
+               final VerticalPanel outer = new VerticalPanel();\r
+               final FocusPanel focusPanel = new FocusPanel(outer);\r
+               // Inner contains generalPanel and permPanel.\r
+               inner = new DecoratedTabPanel();\r
+               inner.setAnimationEnabled(true);\r
+               final VerticalPanel generalPanel = new VerticalPanel();\r
+               final HorizontalPanel buttons = new HorizontalPanel();\r
+               final VerticalPanel verPanel = new VerticalPanel();\r
+               final HorizontalPanel vPanel = new HorizontalPanel();\r
+\r
+               inner.add(generalPanel, "General");\r
+               inner.add(verPanel, "Versions");\r
+               inner.selectTab(0);\r
+\r
+               final FlexTable generalTable = new FlexTable();\r
+               generalTable.setText(0, 0, String.valueOf(files.size())+" files selected");\r
+               generalTable.setText(1, 0, "Folder");\r
+               generalTable.setText(2, 0, "Tags");\r
+               FileResource firstFile = files.get(0);\r
+               if(firstFile.getFolderName() != null)\r
+                       generalTable.setText(1, 1, firstFile.getFolderName());\r
+               else\r
+                       generalTable.setText(1, 1, "-");\r
+\r
+               // Find if tags are identical\r
+               List<String> tagsList = files.get(0).getTags();\r
+               List<String> tagss;\r
+               for (int i=1; i<files.size(); i++) {\r
+                       tagss = files.get(i).getTags();\r
+                       if (tagsList.size() != tagss.size() || !tagsList.containsAll(tagss)) {\r
+                               tagsList = null;\r
+                               break;\r
+                       }\r
+               }\r
+               // Get the tags.\r
+               StringBuffer tagsBuffer = new StringBuffer();\r
+               if (tagsList==null)\r
+                       tagsBuffer.append(MULTIPLE_VALUES_TEXT);\r
+               else {\r
+                       Iterator i = tagsList.iterator();\r
+                       while (i.hasNext()) {\r
+                               String tag = (String) i.next();\r
+                               tagsBuffer.append(tag).append(", ");\r
+                       }\r
+                       if (tagsBuffer.length() > 1)\r
+                               tagsBuffer.delete(tagsBuffer.length() - 2, tagsBuffer.length() - 1);\r
+               }\r
+               initialTagText = tagsBuffer.toString();\r
+               tags.setText(initialTagText);\r
+               tags.addFocusHandler(new FocusHandler() {\r
+                       @Override\r
+                       public void onFocus(FocusEvent event) {\r
+                               if (MULTIPLE_VALUES_TEXT.equals(tags.getText()))\r
+                                       tags.setText("");\r
+                       }\r
+               }\r
+               );\r
+\r
+               generalTable.setWidget(2, 1, tags);\r
+               generalTable.getFlexCellFormatter().setStyleName(0, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setColSpan(0, 0, 2);\r
+               generalTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(2, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(0, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(1, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(2, 1, "props-values");\r
+               generalTable.setCellSpacing(4);\r
+\r
+               // Create the 'OK' button, along with a listener that hides the dialog\r
+               // when the button is clicked.\r
+               final Button ok = new Button("OK", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               accept();\r
+                               closeDialog();\r
+                       }\r
+               });\r
+               buttons.add(ok);\r
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
+               // Create the 'Cancel' button, along with a listener that hides the\r
+               // dialog when the button is clicked.\r
+               final Button cancel = new Button("Cancel", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               closeDialog();\r
+                       }\r
+               });\r
+               buttons.add(cancel);\r
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               buttons.setSpacing(8);\r
+               buttons.addStyleName("gss-TabPanelBottom");\r
+\r
+               generalPanel.add(generalTable);\r
+\r
+               // Asynchronously retrieve the tags defined by this user.\r
+               DeferredCommand.addCommand(new Command() {\r
+\r
+                       @Override\r
+                       public void execute() {\r
+                               updateTags();\r
+                       }\r
+               });\r
+\r
+               DisclosurePanel allTags = new DisclosurePanel("All tags");\r
+               allTagsContent = new FlowPanel();\r
+               allTags.setContent(allTagsContent);\r
+               generalPanel.add(allTags);\r
+               generalPanel.setSpacing(4);\r
+\r
+\r
+               vPanel.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               vPanel.setSpacing(8);\r
+               vPanel.addStyleName("gss-TabPanelBottom");\r
+               vPanel.add(new Label("Versioned"));\r
+\r
+               vPanel.add(versionedCheck);\r
+               verPanel.add(vPanel);\r
+               outer.add(inner);\r
+               outer.add(buttons);\r
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
+               outer.addStyleName("gss-TabPanelBottom");\r
+\r
+               focusPanel.setFocus(true);\r
+               setWidget(outer);\r
+       }\r
+\r
+\r
+       /**\r
+        * Accepts any change and updates the file\r
+        *\r
+        */\r
+       @Override\r
+       protected void accept() {\r
+               JSONObject json = new JSONObject();\r
+               if ( versionedCheck.getState()!=null && !versionedCheck.getState().equals(initialVersioned) )\r
+                               json.put("versioned", JSONBoolean.getInstance(versionedCheck.getState()));\r
+\r
+               JSONArray taga = new JSONArray();\r
+               int i = 0;\r
+               String tagText = tags.getText();\r
+               if (!MULTIPLE_VALUES_TEXT.equals(tagText) && !initialTagText.equals(tagText)) {\r
+                       String[] tagset = tagText.split(",");\r
+                       for (String t : tagset) {\r
+                               JSONString to = new JSONString(t);\r
+                               taga.set(i, to);\r
+                               i++;\r
+                       }\r
+                       json.put("tags", taga);\r
+               }\r
+               String jsonString = json.toString();\r
+               if(jsonString.equals("{}")){\r
+                       GWT.log("NO CHANGES", null);\r
+                       return;\r
+               }\r
+               final List<String> fileIds = new ArrayList<String>();\r
+               for(FileResource f : files)\r
+                       fileIds.add(f.getUri()+"?update=");\r
+               MultiplePostCommand rt = new MultiplePostCommand(fileIds.toArray(new String[0]), jsonString, 200){\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               GSS.get().getTreeView().refreshCurrentNode(false);\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(String p, Throwable t) {\r
+                               GWT.log("", t);\r
+                               if(t instanceof RestException){\r
+                                       int statusCode = ((RestException)t).getHttpStatusCode();\r
+                                       if(statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary permissions");\r
+                                       else if(statusCode == 404)\r
+                                               GSS.get().displayError("File does not exist");\r
+                                       else if(statusCode == 409)\r
+                                               GSS.get().displayError("A file with the same name already exists");\r
+                                       else if(statusCode == 413)\r
+                                               GSS.get().displayError("Your quota has been exceeded");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to modify file::"+((RestException)t).getHttpStatusText());\r
+                               }\r
+                               else\r
+                                       GSS.get().displayError("System error modifying file:"+t.getMessage());\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(rt);\r
+       }\r
+\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/FolderContextMenu.java b/src/org/gss_project/gss/web/client/FolderContextMenu.java
new file mode 100644 (file)
index 0000000..96c7529
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.commands.CopyCommand;
+import org.gss_project.gss.web.client.commands.CutCommand;
+import org.gss_project.gss.web.client.commands.DeleteCommand;
+import org.gss_project.gss.web.client.commands.EmptyTrashCommand;
+import org.gss_project.gss.web.client.commands.NewFolderCommand;
+import org.gss_project.gss.web.client.commands.PasteCommand;
+import org.gss_project.gss.web.client.commands.PropertiesCommand;
+import org.gss_project.gss.web.client.commands.RefreshCommand;
+import org.gss_project.gss.web.client.commands.RestoreTrashCommand;
+import org.gss_project.gss.web.client.commands.ToTrashCommand;
+import org.gss_project.gss.web.client.commands.UploadFileCommand;
+import org.gss_project.gss.web.client.rest.resource.MyFolderResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.OthersFolderResource;
+import org.gss_project.gss.web.client.rest.resource.OthersResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.SharedFolderResource;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * The 'Folder Context' menu implementation.
+ */
+public class FolderContextMenu extends PopupPanel {
+
+       /**
+        * The widget's images.
+        */
+       private final Images images;
+
+       /**
+        * The image bundle for this widget's images that reuses images defined in
+        * other menus.
+        */
+       public interface Images extends ClientBundle,FileMenu.Images, EditMenu.Images {
+       }
+
+       private MenuItem pasteItem;
+
+       /**
+        * The widget's constructor.
+        *
+        * @param newImages the image bundle passed on by the parent object
+        */
+       public FolderContextMenu(final Images newImages) {
+               // The popup's constructor's argument is a boolean specifying that it
+               // auto-close itself when the user clicks outside of it.
+               super(true);
+               setAnimationEnabled(true);
+               images = newImages;
+
+               pasteItem = new MenuItem("<span id = 'folderContextMenu.paste'>" + AbstractImagePrototype.create(newImages.paste()).getHTML() + "&nbsp;Paste</span>", true, new PasteCommand(this));
+               MenuBar contextMenu = new MenuBar(true);
+               
+               RestResource selectedItem = GSS.get().getTreeView().getSelection();
+
+               if(selectedItem != null)
+                       if(selectedItem instanceof MyFolderResource){           
+                               MenuItem newFolder = new MenuItem("<span id = 'folderContextMenu.newFolder'>" + AbstractImagePrototype.create(newImages.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(this, images));
+                               contextMenu.addItem(newFolder);
+                               
+                               MenuItem upload = new MenuItem("<span id = 'folderContextMenu.upload'>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                               contextMenu.addItem(upload);
+                                                                                       
+                               boolean notRootFolder =(((MyFolderResource) selectedItem).getResource()).getParentURI() != null ? true : false; 
+                               if (notRootFolder) {
+                                       // do not show the copy & cut option for the user's root folder                                 
+                                       MenuItem cut = new MenuItem("<span id = 'folderContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(this));
+                                       contextMenu.addItem(cut);
+                                       
+                               }
+                               MenuItem copy = new MenuItem("<span id = 'folderContextMenu.copy'>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(this));                                    
+                               contextMenu.addItem(copy);
+                               contextMenu.addItem(pasteItem);
+                               if (notRootFolder) {
+                                       // do not show delete options for the user's root folder
+                                       MenuItem moveToTrash = new MenuItem("<span id = 'folderContextMenu.moveToTrash'>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(this));                                    
+                                       contextMenu.addItem(moveToTrash);
+                                       
+                                       MenuItem delete = new MenuItem("<span id = 'folderContextMenu.delete'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, newImages));
+                                       contextMenu.addItem(delete);                                    
+                               }
+                               
+                               MenuItem refresh = new MenuItem("<span id = 'folderContextMenu.refresh'>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem(refresh);
+                               
+                               MenuItem sharing = new MenuItem("<span id = 'folderContextMenu.sharing'>" + AbstractImagePrototype.create(newImages.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, newImages, 1));
+                               contextMenu.addItem(sharing);
+                               
+                               MenuItem properties = new MenuItem("<span id = 'folderContextMenu.properties'>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(this, newImages, 0));
+                               contextMenu.addItem(properties);                
+                       }
+               
+                       if(selectedItem instanceof SharedFolderResource){
+                               MenuItem newFolder = new MenuItem("<span id = 'folderContextMenu.newFolder'>" + AbstractImagePrototype.create(newImages.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(this, images));
+                               contextMenu.addItem(newFolder);
+                               
+                               MenuItem upload = new MenuItem("<span id = 'folderContextMenu.upload'>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                               contextMenu.addItem(upload);
+                               
+                               MenuItem cut = new MenuItem("<span id = 'folderContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(this));
+                               contextMenu.addItem(cut);
+                               
+                               MenuItem copy = new MenuItem("<span id = 'folderContextMenu.copy'>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(this));
+                               contextMenu.addItem(copy);
+                               
+                               contextMenu.addItem(pasteItem);
+                               
+                               MenuItem moveToTrash = new MenuItem("<span id = 'folderContextMenu.moveToTrash'>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(this));
+                               contextMenu.addItem(moveToTrash);
+                               
+                               MenuItem delete = new MenuItem("<span id = 'folderContextMenu.delete'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, newImages));
+                               contextMenu.addItem(delete);
+
+                               MenuItem refresh = new MenuItem("<span id = 'folderContextMenu.refresh'>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem(refresh);
+                               
+                               MenuItem sharing = new MenuItem("<span id = 'folderContextMenu.sharing'>" + AbstractImagePrototype.create(newImages.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, newImages, 1));
+                               contextMenu.addItem(sharing);
+                               
+                               MenuItem properties = new MenuItem("<span id = 'folderContextMenu.properties'>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(this, newImages, 0));
+                               contextMenu.addItem(properties);
+                               
+                       }
+                       if(selectedItem instanceof TrashFolderResource){
+                               MenuItem restore = new MenuItem("<span id = 'folderContextMenu.restore'>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Restore folder and contents</span>", true, new RestoreTrashCommand(this));
+                               contextMenu.addItem(restore);
+                               
+                               MenuItem delete = new MenuItem("<span id = 'folderContextMenu.delete'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, newImages));
+                               contextMenu.addItem(delete);
+                               
+                               MenuItem refresh = new MenuItem("<span id = 'folderContextMenu.refresh'>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem(refresh);
+                               
+                       }
+                       if(selectedItem instanceof OthersFolderResource){                               
+                               MenuItem newFolder = new MenuItem("<span id = 'folderContextMenu.newFolder'>" + AbstractImagePrototype.create(newImages.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(this, images));
+                               contextMenu.addItem(newFolder);
+
+                               MenuItem upload = new MenuItem("<span id ='folderContextMenu.upload'>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                               contextMenu.addItem(upload);
+                               
+                               MenuItem cut = new MenuItem("<span id = 'folderContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(this));
+                               contextMenu.addItem(cut);
+                               
+                               MenuItem copy = new MenuItem("<span id = 'folderContextMenu.copy'>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(this));
+                               contextMenu.addItem(copy);
+                               
+                               contextMenu.addItem(pasteItem);
+                               
+                               MenuItem moveToTrash = new MenuItem("<span id = 'folderContextMenu.moveToTrash'>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(this));
+                               contextMenu.addItem(moveToTrash);
+                               
+                               MenuItem delete = new MenuItem("<span id = 'folderContextMenu.delete'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, newImages));
+                               contextMenu.addItem(delete);
+
+                               MenuItem refresh = new MenuItem("<span id = 'folderContextMenu.delete'>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem(refresh);
+                               
+                               MenuItem sharing = new MenuItem("<span id = 'folderContextMenu.sharing'>" + AbstractImagePrototype.create(newImages.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, newImages, 1));
+                               contextMenu.addItem(sharing);
+                               
+                               MenuItem properties = new MenuItem("<span id = 'folderContextMenu.properties'>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(this, newImages, 0));
+                               contextMenu.addItem(properties);
+                               
+                       }
+                       if(selectedItem instanceof TrashResource){
+                               MenuItem restore = new MenuItem("<span id ='folderContextMenu.restore'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Restore Trash</span>", true, new RestoreTrashCommand(this));
+                               contextMenu.addItem(restore);
+                               
+                               MenuItem emptyTrash = new MenuItem("<span id = 'folderContextMenu.emptyTrash'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Empty Trash</span>", true, new EmptyTrashCommand(this));
+                               contextMenu.addItem(emptyTrash);
+                               
+                               MenuItem refresh = new MenuItem("<span id = 'folderContextMenu.refresh'>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem(refresh);
+                               
+                       }
+                       if(selectedItem instanceof SharedResource || selectedItem instanceof OthersResource || selectedItem instanceof OtherUserResource){
+                               MenuItem refresh = new MenuItem("<span id = 'folderContextMenu.refresh'>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem(refresh);
+                               
+                       }
+                       
+                       /*
+                       if(folders.isTrashItem(selectedItem)){
+                               if (folders.isTrash(selectedItem)){
+                                       contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Empty Trash</span>", true, new EmptyTrashCommand(this));
+                                       contextMenu.addItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               }
+                               else {
+                                       contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Restore folder and contents</span>", true, new RestoreTrashCommand(this));
+                                       contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, newImages));
+                                       contextMenu.addItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               }
+                       }
+                       else if(folders.isFileItem(selectedItem)){
+                               
+                       }
+                       else if(!folders.isMyShares(selectedItem) && folders.isMySharedItem(selectedItem)){
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(this, images));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(this));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(this));
+                               contextMenu.addItem(pasteItem);
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(this));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, newImages));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, newImages, 1));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(this, newImages, 0));
+                       }
+                       else if(!folders.isOthersShared(selectedItem) && folders.isOthersSharedItem(selectedItem) && !(GSS.get().getCurrentSelection() instanceof OtherUserResource)){
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(this, images));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(this));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(this));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(this));
+                               contextMenu.addItem(pasteItem);
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(this));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(this, newImages));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, newImages, 1));
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(this, newImages, 0));
+                       } else if(!selectedItem.equals(folders.getSharesItem()))
+                               contextMenu.addItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
+                       */
+               
+               add(contextMenu);
+               if (GSS.get().getClipboard().hasFolderOrFileItem())
+                       pasteItem.setVisible(true);
+               else
+                       pasteItem.setVisible(false);
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/FolderPropertiesDialog.java b/src/org/gss_project/gss/web/client/FolderPropertiesDialog.java
new file mode 100644 (file)
index 0000000..55f7de4
--- /dev/null
@@ -0,0 +1,490 @@
+/*\r
+ * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.FilePropertiesDialog.Images;\r
+import org.gss_project.gss.web.client.rest.PostCommand;\r
+import org.gss_project.gss.web.client.rest.RestException;\r
+import org.gss_project.gss.web.client.rest.resource.FolderResource;\r
+import org.gss_project.gss.web.client.rest.resource.GroupResource;\r
+import org.gss_project.gss.web.client.rest.resource.PermissionHolder;\r
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;\r
+\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ChangeEvent;\r
+import com.google.gwt.event.dom.client.ChangeHandler;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.http.client.URL;\r
+import com.google.gwt.i18n.client.DateTimeFormat;\r
+import com.google.gwt.json.client.JSONArray;\r
+import com.google.gwt.json.client.JSONBoolean;\r
+import com.google.gwt.json.client.JSONObject;\r
+import com.google.gwt.json.client.JSONString;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.Event.NativePreviewEvent;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.CheckBox;\r
+import com.google.gwt.user.client.ui.DecoratedTabPanel;\r
+import com.google.gwt.user.client.ui.DialogBox;\r
+import com.google.gwt.user.client.ui.FlexTable;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.Label;\r
+import com.google.gwt.user.client.ui.TabPanel;\r
+import com.google.gwt.user.client.ui.TextBox;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'Folder properties' dialog box implementation.\r
+ */\r
+public class FolderPropertiesDialog extends DialogBox {\r
+\r
+       private List<GroupResource> groups = null;\r
+\r
+       final PermissionsList permList;\r
+\r
+       private CheckBox readForAll;\r
+\r
+       /**\r
+        * The widget that holds the folderName of the folder.\r
+        */\r
+       private TextBox folderName = new TextBox();\r
+\r
+       /**\r
+        * A flag that denotes whether the dialog will be used to create or modify a\r
+        * folder.\r
+        */\r
+       private final boolean create;\r
+\r
+       final FolderResource folder;\r
+\r
+       final TabPanel inner;\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        *\r
+        * @param images the image icons from the file properties dialog\r
+        * @param _create true if the dialog is displayed for creating a new\r
+        *            sub-folder of the selected folder, false if it is displayed\r
+        *            for modifying the selected folder\r
+        */\r
+       public FolderPropertiesDialog(Images images, boolean _create,  final List<GroupResource> _groups) {\r
+               setAnimationEnabled(true);\r
+\r
+               // Enable IE selection for the dialog (must disable it upon closing it)\r
+               GSS.enableIESelection();\r
+\r
+               create = _create;\r
+               \r
+               folder = ((RestResourceWrapper) GSS.get().getTreeView().getSelection()).getResource();\r
+               permList = new PermissionsList(images, folder.getPermissions(), folder.getOwner());\r
+               groups = _groups;\r
+\r
+               // Use this opportunity to set the dialog's caption.\r
+               if (create)\r
+                       setText("Create folder");\r
+               else\r
+                       setText("Folder properties");\r
+\r
+               // Outer contains inner and buttons\r
+               VerticalPanel outer = new VerticalPanel();\r
+               // Inner contains generalPanel and permPanel\r
+               inner = new DecoratedTabPanel();\r
+               inner.setAnimationEnabled(true);\r
+               VerticalPanel generalPanel = new VerticalPanel();\r
+               VerticalPanel permPanel = new VerticalPanel();\r
+               final HorizontalPanel permForAll = new HorizontalPanel();\r
+               final HorizontalPanel pathPanel = new HorizontalPanel();\r
+               HorizontalPanel buttons = new HorizontalPanel();\r
+               HorizontalPanel permButtons = new HorizontalPanel();\r
+\r
+               inner.add(generalPanel, "General");\r
+               if (!create)\r
+                       inner.add(permPanel, "Sharing");\r
+               inner.selectTab(0);\r
+\r
+               final Label folderNameNote = new Label("Please note that slashes ('/') are not allowed in folder names.", true);\r
+               folderNameNote.setVisible(false);\r
+               folderNameNote.setStylePrimaryName("gss-readForAllNote");\r
+\r
+               FlexTable generalTable = new FlexTable();\r
+               generalTable.setText(0, 0, "Name");\r
+               generalTable.setText(1, 0, "Parent");\r
+               generalTable.setText(2, 0, "Creator");\r
+               generalTable.setText(3, 0, "Last modified");\r
+               folderName.setText(create ? "" : folder.getName());\r
+               folderName.getElement().setId("folderPropertiesDialog.textBox.name");\r
+               generalTable.setWidget(0, 1, folderName);\r
+               folderName.addChangeHandler(new ChangeHandler() {\r
+                       \r
+                       @Override\r
+                       public void onChange(ChangeEvent event) {\r
+                               if(folderName.getText().contains("/"))\r
+                                       folderNameNote.setVisible(true);\r
+                               else\r
+                                       folderNameNote.setVisible(false);                               \r
+                               \r
+                       }\r
+               });\r
+\r
+\r
+               if (create)\r
+                       generalTable.setText(1, 1, folder.getName());\r
+               else if(folder.getParentName() == null)\r
+                       generalTable.setText(1, 1, "-");\r
+               else\r
+                       generalTable.setText(1, 1, folder.getParentName());\r
+               generalTable.setWidget(0, 2, folderNameNote);\r
+               generalTable.setText(2, 1, folder.getOwner());\r
+               DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");\r
+               if(folder.getModificationDate() != null)\r
+                       generalTable.setText(3, 1, formatter.format(folder.getModificationDate()));\r
+               generalTable.getFlexCellFormatter().setStyleName(0, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(2, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(3, 0, "props-labels");\r
+               generalTable.getFlexCellFormatter().setStyleName(0, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(1, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(2, 1, "props-values");\r
+               generalTable.getFlexCellFormatter().setStyleName(3, 1, "props-values");\r
+               generalTable.setCellSpacing(4);\r
+\r
+               // Create the 'Create/Update' button, along with a listener that hides the dialog\r
+               // when the button is clicked and quits the application.\r
+               String okLabel;\r
+               if (create)\r
+                       okLabel = "Create";\r
+               else\r
+                       okLabel = "Update";\r
+               Button ok = new Button(okLabel, new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {                         \r
+                               if(folderName.getText().contains("/"))\r
+                                       folderNameNote.setVisible(true);\r
+                               else {\r
+                                       folderNameNote.setVisible(false);\r
+                                       createOrUpdateFolder();\r
+                                       closeDialog();\r
+                               }\r
+\r
+                       }\r
+               });\r
+               ok.getElement().setId("folderPropertiesDialog.button.ok");\r
+               buttons.add(ok);\r
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
+               // Create the 'Cancel' button, along with a listener that hides the\r
+               // dialog\r
+               // when the button is clicked.\r
+               Button cancel = new Button("Cancel", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               closeDialog();\r
+                       }\r
+               });\r
+               cancel.getElement().setId("folderPropertiesDialog.button.cancel");\r
+               buttons.add(cancel);\r
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               buttons.setSpacing(8);\r
+               buttons.addStyleName("gss-TabPanelBottom");\r
+\r
+               Button add = new Button("Add Group", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               PermissionsAddDialog dlg = new PermissionsAddDialog(groups, permList, false);\r
+                               dlg.center();\r
+                       }\r
+               });\r
+               add.getElement().setId("folderPropertiesDialog.button.addGroup");\r
+               permButtons.add(add);\r
+               permButtons.setCellHorizontalAlignment(add, HasHorizontalAlignment.ALIGN_CENTER);\r
+\r
+               Button addUser = new Button("Add User", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               PermissionsAddDialog dlg = new PermissionsAddDialog(groups, permList, true);\r
+                               dlg.center();\r
+                       }\r
+               });\r
+               addUser.getElement().setId("folderPropertiesDialog.button.addUser");\r
+               permButtons.add(addUser);\r
+               permButtons.setCellHorizontalAlignment(addUser, HasHorizontalAlignment.ALIGN_CENTER);\r
+\r
+               permButtons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               permButtons.setSpacing(8);\r
+               permButtons.addStyleName("gss-TabPanelBottom");\r
+\r
+               final Label readForAllNote = new Label("When this option is enabled, the folder will be readable" +\r
+                                       " by everyone. By checking this option, you are certifying that you have the right to " +\r
+                                       "distribute this folder's contents and that it does not violate the Terms of Use.", true);\r
+               readForAllNote.setVisible(false);\r
+               readForAllNote.setStylePrimaryName("gss-readForAllNote");\r
+\r
+               readForAll = new CheckBox();\r
+               readForAll.getElement().setId("folderPropertiesDialog.checkBox.public");\r
+               readForAll.setValue(folder.isReadForAll());\r
+               readForAll.addClickHandler(new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               readForAllNote.setVisible(readForAll.getValue());\r
+                       }\r
+\r
+               });\r
+\r
+               generalPanel.add(generalTable);\r
+               permPanel.add(permList);\r
+               permPanel.add(permButtons);\r
+\r
+               // Only show the read for all permission if the user is the owner.\r
+               if (folder.getOwner().equals(GSS.get().getCurrentUserResource().getUsername())) {\r
+                       permForAll.add(new Label("Public"));\r
+                       permForAll.add(readForAll);\r
+                       permForAll.setSpacing(8);\r
+                       permForAll.addStyleName("gss-TabPanelBottom");\r
+                       permForAll.add(readForAllNote);\r
+                       permPanel.add(permForAll);\r
+               }\r
+               TextBox path = new TextBox();\r
+               path.getElement().setId("folderPropertiesDialog.textBox.link");\r
+               path.setWidth("100%");\r
+               path.addClickHandler(new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               GSS.enableIESelection();\r
+                               ((TextBox) event.getSource()).selectAll();\r
+                               GSS.preventIESelection();\r
+                       }\r
+\r
+               });\r
+               path.setText(folder.getUri());\r
+               path.setTitle("Use this link for sharing the folder via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");\r
+               path.setWidth("100%");\r
+               path.setReadOnly(true);\r
+               pathPanel.setWidth("100%");\r
+               pathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);\r
+               pathPanel.add(new Label("Link"));\r
+               pathPanel.setSpacing(8);\r
+               pathPanel.addStyleName("gss-TabPanelBottom");\r
+               pathPanel.add(path);\r
+               permPanel.add(pathPanel);\r
+\r
+               outer.add(inner);\r
+               outer.add(buttons);\r
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
+               outer.addStyleName("gss-TabPanelBottom");\r
+\r
+               setWidget(outer);\r
+\r
+               /*if (create)\r
+                       folderName.setFocus(true);\r
+               else\r
+                       ok.setFocus(true);*/\r
+       }\r
+\r
+       @Override\r
+       public void center() {\r
+               super.center();\r
+               folderName.setFocus(true);\r
+       }\r
+\r
+       @Override\r
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
+               super.onPreviewNativeEvent(preview);\r
+\r
+               NativeEvent evt = preview.getNativeEvent();\r
+               if (evt.getType().equals("keydown"))\r
+                       // Use the popup's key preview hooks to close the dialog when either\r
+                       // enter or escape is pressed.\r
+                       switch (evt.getKeyCode()) {\r
+                               case KeyCodes.KEY_ENTER:\r
+                                       closeDialog();\r
+                                       createOrUpdateFolder();\r
+                                       break;\r
+                               case KeyCodes.KEY_ESCAPE:\r
+                                       closeDialog();\r
+                                       break;\r
+                       }\r
+       }\r
+\r
+\r
+       /**\r
+        * Enables IE selection prevention and hides the dialog\r
+        * (we disable the prevention on creation of the dialog)\r
+        */\r
+       public void closeDialog() {\r
+               GSS.preventIESelection();\r
+               hide();\r
+       }\r
+\r
+       /**\r
+        * Generate an RPC request to create a new folder.\r
+        *\r
+        * @param userId the ID of the user whose namespace will be searched for\r
+        *            folders\r
+        * @param _folderName the name of the folder to create\r
+        */\r
+       private void createFolder() {\r
+               String name = folderName.getText();\r
+               if (!GSS.isValidResourceName(name)) {\r
+                       GSS.get().displayError("The folder name '" + name + "' is invalid");\r
+                       return;\r
+               }\r
+               PostCommand ep = new PostCommand(folder.getUri() + "?new=" +\r
+                               URL.encodeComponent(name), "", 201) {\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               //TODO:CELLTREE\r
+                               if(folder.getUri().equals(GSS.get().getTreeView().getMyFolders().getUri())){\r
+                                       GSS.get().getTreeView().updateRootNode();\r
+                               }\r
+                               else\r
+                                       GSS.get().getTreeView().updateNodeChildren((RestResourceWrapper) GSS.get().getTreeView().getSelection());\r
+                               //GSS.get().getFolders().updateFolder((DnDTreeItem) GSS.get().getFolders().getCurrent());\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               if(t instanceof RestException){\r
+                                       int statusCode = ((RestException)t).getHttpStatusCode();\r
+                                       if(statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary" +\r
+                                                               " permissions or a folder with same name " +\r
+                                                               "already exists");\r
+                                       else if(statusCode == 404)\r
+                                               GSS.get().displayError("Resource not found");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to create folder:" +\r
+                                                               ((RestException)t).getHttpStatusText());\r
+                               }\r
+                               else\r
+                                       GSS.get().displayError("System error creating folder:" +\r
+                                                       t.getMessage());\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(ep);\r
+\r
+       }\r
+\r
+       /**\r
+        * Upon closing the dialog by clicking OK or pressing ENTER this method does\r
+        * the actual work of modifying folder properties or creating a new Folder\r
+        * depending on the value of the create field\r
+        *\r
+        * @param userId\r
+        */\r
+       private void createOrUpdateFolder() {\r
+               if (create)\r
+                       createFolder();\r
+               else\r
+                       updateFolder();\r
+\r
+       }\r
+\r
+       private void updateFolder() {\r
+               permList.updatePermissionsAccordingToInput();\r
+               Set<PermissionHolder> perms = permList.getPermissions();\r
+               JSONObject json = new JSONObject();\r
+               if(!folder.getName().equals(folderName.getText()))\r
+                       json.put("name", new JSONString(folderName.getText()));\r
+               //only update the read for all perm if the user is the owner\r
+               if (readForAll.getValue() != folder.isReadForAll())\r
+                       if (folder.getOwner().equals(GSS.get().getCurrentUserResource().getUsername()))\r
+                               json.put("readForAll", JSONBoolean.getInstance(readForAll.getValue()));\r
+               if (permList.hasChanges()) {\r
+                       JSONArray perma = new JSONArray();\r
+                       int i=0;\r
+                       for(PermissionHolder p : perms){\r
+                               JSONObject po = new JSONObject();\r
+                               if(p.getUser() != null)\r
+                                       po.put("user", new JSONString(p.getUser()));\r
+                               if(p.getGroup() != null)\r
+                                       po.put("group", new JSONString(p.getGroup()));\r
+                               po.put("read", JSONBoolean.getInstance(p.isRead()));\r
+                               po.put("write", JSONBoolean.getInstance(p.isWrite()));\r
+                               po.put("modifyACL", JSONBoolean.getInstance(p.isModifyACL()));\r
+                               perma.set(i,po);\r
+                               i++;\r
+                       }\r
+                       json.put("permissions", perma);\r
+                       GWT.log(json.toString(), null);\r
+               }\r
+               PostCommand ep = new PostCommand(folder.getUri()+"?update=", json.toString(), 200){\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               //TODO:CELLTREE\r
+                               \r
+                               if(getPostBody() != null && !"".equals(getPostBody().trim())){\r
+                                       \r
+                                       \r
+                                       FolderResource fres = ((RestResourceWrapper) GSS.get().getTreeView().getSelection()).getResource();\r
+                                       String initialPath = fres.getUri();\r
+                                       String newPath =  getPostBody().trim();\r
+                                       fres.setUri(newPath);\r
+                                       ((RestResourceWrapper) GSS.get().getTreeView().getSelection()).getResource().setUri(newPath);\r
+                                       ((RestResourceWrapper) GSS.get().getTreeView().getSelection()).setUri(newPath);\r
+                                       GSS.get().getTreeView().updateNodeChildren(fres.getParentURI());\r
+                                       if (permList.hasChanges()) {\r
+                                               GSS.get().getTreeView().updateMySharedNode();\r
+                                       }\r
+                                       /*\r
+                                       if(folderItem.getParentItem() != null && ((DnDTreeItem)folderItem.getParentItem()).getFolderResource() != null){\r
+                                               ((DnDTreeItem)folderItem.getParentItem()).getFolderResource().removeSubfolderPath(initialPath);\r
+                                               ((DnDTreeItem)folderItem.getParentItem()).getFolderResource().getSubfolderPaths().add(newPath);\r
+                                       }*/\r
+                               }\r
+                               //GSS.get().getFolders().updateFolder( (DnDTreeItem) GSS.get().getFolders().getCurrent());\r
+                               \r
+                               GSS.get().showFileList(true);\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+                               GWT.log("", t);\r
+                               if(t instanceof RestException){\r
+                                       int statusCode = ((RestException)t).getHttpStatusCode();\r
+                                       if(statusCode == 405)\r
+                                               GSS.get().displayError("You don't have the necessary permissions or" +\r
+                                                               " a folder with same name already exists");\r
+                                       else if(statusCode == 404)\r
+                                               GSS.get().displayError("Resource not found, or user specified in sharing does not exist");\r
+                                       else\r
+                                               GSS.get().displayError("Unable to update folder: "+((RestException)t).getHttpStatusText());\r
+                               }\r
+                               else\r
+                                       GSS.get().displayError("System error moifying file: "+t.getMessage());\r
+                               //TODO:CELLTREE\r
+                               //GSS.get().getFolders().updateFolder( (DnDTreeItem) GSS.get().getFolders().getCurrent());\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(ep);\r
+       }\r
+\r
+       public void selectTab(int _tab) {\r
+               inner.selectTab(_tab);\r
+       }\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/GSS.java b/src/org/gss_project/gss/web/client/GSS.java
new file mode 100644 (file)
index 0000000..98b0219
--- /dev/null
@@ -0,0 +1,878 @@
+/*
+ * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.clipboard.Clipboard;
+import org.gss_project.gss.web.client.commands.GetUserCommand;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.logical.shared.ResizeHandler;
+import com.google.gwt.event.logical.shared.SelectionEvent;
+import com.google.gwt.event.logical.shared.SelectionHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Cookies;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.DecoratedTabPanel;
+import com.google.gwt.user.client.ui.DockPanel;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HasVerticalAlignment;
+import com.google.gwt.user.client.ui.HorizontalSplitPanel;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.TabPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+/**
+ * Entry point classes define <code>onModuleLoad()</code>.
+ */
+public class GSS implements EntryPoint, ResizeHandler {
+
+       /**
+        * A constant that denotes the completion of an IncrementalCommand.
+        */
+       public static final boolean DONE = false;
+
+       public static final int VISIBLE_FILE_COUNT = 25;
+
+       /**
+        * Instantiate an application-level image bundle. This object will provide
+        * programmatic access to all the images needed by widgets.
+        */
+       private static Images images = (Images) GWT.create(Images.class);
+
+       private GlassPanel glassPanel = new GlassPanel();
+
+       /**
+        * An aggregate image bundle that pulls together all the images for this
+        * application into a single bundle.
+        */
+       public interface Images extends ClientBundle, TopPanel.Images, StatusPanel.Images, FileMenu.Images, EditMenu.Images, SettingsMenu.Images, GroupMenu.Images, FilePropertiesDialog.Images, MessagePanel.Images, FileList.Images, SearchResults.Images, Search.Images, Groups.Images, CellTreeView.Images {
+
+               @Source("org/gss_project/gss/resources/document.png")
+               ImageResource folders();
+
+               @Source("org/gss_project/gss/resources/edit_group_22.png")
+               ImageResource groups();
+
+               @Source("org/gss_project/gss/resources/search.png")
+               ImageResource search();
+       }
+
+       /**
+        * The single GSS instance.
+        */
+       private static GSS singleton;
+
+       /**
+        * Gets the singleton GSS instance.
+        *
+        * @return the GSS object
+        */
+       public static GSS get() {
+               if (GSS.singleton == null)
+                       GSS.singleton = new GSS();
+               return GSS.singleton;
+       }
+
+       /**
+        * The Application Clipboard implementation;
+        */
+       private Clipboard clipboard = new Clipboard();
+
+       private UserResource currentUserResource;
+
+       /**
+        * The top panel that contains the menu bar.
+        */
+       private TopPanel topPanel;
+
+       /**
+        * The panel that contains the various system messages.
+        */
+       private MessagePanel messagePanel = new MessagePanel(GSS.images);
+
+       /**
+        * The bottom panel that contains the status bar.
+        */
+       private StatusPanel statusPanel = new StatusPanel(GSS.images);
+
+       /**
+        * The top right panel that displays the logged in user details
+        */
+       private UserDetailsPanel userDetailsPanel = new UserDetailsPanel();
+
+       /**
+        * The file list widget.
+        */
+       private FileList fileList;
+
+       /**
+        * The group list widget.
+        */
+       private Groups groups = new Groups(images);
+
+       /**
+        * The search result widget.
+        */
+       private SearchResults searchResults;
+
+       /**
+        * The tab panel that occupies the right side of the screen.
+        */
+       private TabPanel inner = new DecoratedTabPanel(){
+               
+               public void onBrowserEvent(com.google.gwt.user.client.Event event) {
+                       if (DOM.eventGetType(event) == Event.ONCONTEXTMENU){
+                               if(isFileListShowing()){
+                                       getFileList().showContextMenu(event);
+                               }
+                               else if(isUserListVisible()){
+                                       getGroups().setCurrent(null);
+                                       getGroups().showPopup(event.getClientX(),event.getClientY());
+                               }
+                       }
+               };
+       };
+
+       /**
+        * The split panel that will contain the left and right panels.
+        */
+       private HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
+
+       /**
+        * The horizontal panel that will contain the search and status panels.
+        */
+       private DockPanel searchStatus = new DockPanel();
+
+       /**
+        * The search widget.
+        */
+       private Search search;
+
+       /**
+        * The widget that displays the tree of folders.
+        */
+       
+       private CellTreeView treeView = new CellTreeView(images);
+       /**
+        * The currently selected item in the application, for use by the Edit menu
+        * commands. Potential types are Folder, File, User and Group.
+        */
+       private Object currentSelection;
+
+       /**
+        * The authentication token of the current user.
+        */
+       private String token;
+
+       /**
+        * The WebDAV password of the current user
+        */
+       private String webDAVPassword;
+
+       
+
+       public HashMap<String, String> userFullNameMap = new HashMap<String, String>();
+
+       @Override
+       public void onModuleLoad() {
+               // Initialize the singleton before calling the constructors of the
+               // various widgets that might call GSS.get().
+               singleton = this;
+               RootPanel.get().add(glassPanel, 0, 0);
+               parseUserCredentials();
+               
+               topPanel = new TopPanel(GSS.images);
+               topPanel.setWidth("100%");
+
+               messagePanel.setWidth("100%");
+               messagePanel.setVisible(false);
+
+               search = new Search(images);
+               searchStatus.add(search, DockPanel.WEST);
+               searchStatus.add(userDetailsPanel, DockPanel.EAST);
+               searchStatus.setCellHorizontalAlignment(userDetailsPanel, HasHorizontalAlignment.ALIGN_RIGHT);
+               searchStatus.setCellVerticalAlignment(search, HasVerticalAlignment.ALIGN_MIDDLE);
+               searchStatus.setCellVerticalAlignment(userDetailsPanel, HasVerticalAlignment.ALIGN_MIDDLE);
+               searchStatus.setWidth("100%");
+
+               fileList = new FileList(images);
+
+               searchResults = new SearchResults(images);
+
+               // Inner contains the various lists.
+               inner.sinkEvents(Event.ONCONTEXTMENU);
+               inner.setAnimationEnabled(true);
+               inner.getTabBar().addStyleName("gss-MainTabBar");
+               inner.getDeckPanel().addStyleName("gss-MainTabPanelBottom");
+               inner.add(fileList, createHeaderHTML(AbstractImagePrototype.create(images.folders()), "Files"), true);
+               
+               inner.add(groups, createHeaderHTML(AbstractImagePrototype.create(images.groups()), "Groups"), true);
+               inner.add(searchResults, createHeaderHTML(AbstractImagePrototype.create(images.search()), "Search Results"), true);
+               //inner.add(new CellTreeView(images), createHeaderHTML(AbstractImagePrototype.create(images.search()), "Cell tree sample"), true);
+               inner.setWidth("100%");
+               inner.selectTab(0);
+
+               inner.addSelectionHandler(new SelectionHandler<Integer>() {
+
+                       @Override
+                       public void onSelection(SelectionEvent<Integer> event) {
+                               int tabIndex = event.getSelectedItem();
+//                             TreeItem treeItem = GSS.get().getFolders().getCurrent();
+                               switch (tabIndex) {
+                                       case 0:
+//                                             Files tab selected
+                                               //fileList.clearSelectedRows();
+                                               fileList.updateCurrentlyShowingStats();
+                                               break;
+                                       case 1:
+//                                             Groups tab selected
+                                               groups.updateCurrentlyShowingStats();
+                                       updateHistory("Groups");
+                                               break;
+                                       case 2:
+//                                             Search tab selected
+                                               searchResults.clearSelectedRows();
+                                               searchResults.updateCurrentlyShowingStats();
+                                       updateHistory("Search");
+                                               break;
+                               }
+                       }
+               });
+//             If the application starts with no history token, redirect to a new "Files" state
+               String initToken = History.getToken();
+               if(initToken.length() == 0)
+                       History.newItem("Files");
+//                Add history listener to handle any history events
+               History.addValueChangeHandler(new ValueChangeHandler<String>() {
+                       @Override
+                       public void onValueChange(ValueChangeEvent<String> event) {
+                               String tokenInput = event.getValue();
+                               String historyToken = handleSpecialFolderNames(tokenInput);
+                               try {
+                                       if(historyToken.equals("Search"))
+                                               inner.selectTab(2);
+                                       else if(historyToken.equals("Groups"))
+                                               inner.selectTab(1);
+                                       else if(historyToken.equals("Files")|| historyToken.length()==0)
+                                               inner.selectTab(0);
+                                       else {
+                                               /*TODO: CELLTREE
+                                               PopupTree popupTree = GSS.get().getFolders().getPopupTree();
+                                               TreeItem treeObj = GSS.get().getFolders().getPopupTree().getTreeItem(historyToken);
+                                               SelectionEvent.fire(popupTree, treeObj);
+                                               */
+                                       }
+                               } catch (IndexOutOfBoundsException e) {
+                                       inner.selectTab(0);
+                               }
+                       }
+               });
+
+               // Add the left and right panels to the split panel.
+               splitPanel.setLeftWidget(treeView);
+               splitPanel.setRightWidget(inner);
+               splitPanel.setSplitPosition("25%");
+               splitPanel.setSize("100%", "100%");
+               splitPanel.addStyleName("gss-splitPanel");
+               
+               // Create a dock panel that will contain the menu bar at the top,
+               // the shortcuts to the left, the status bar at the bottom and the
+               // right panel taking the rest.
+               VerticalPanel outer = new VerticalPanel();
+               outer.add(topPanel);
+               outer.add(searchStatus);
+               outer.add(messagePanel);
+               outer.add(splitPanel);
+               outer.add(statusPanel);
+               outer.setWidth("100%");
+               outer.setCellHorizontalAlignment(messagePanel, HasHorizontalAlignment.ALIGN_CENTER);
+
+               outer.setSpacing(4);
+
+               // Hook the window resize event, so that we can adjust the UI.
+               Window.addResizeHandler(this);
+               // Clear out the window's built-in margin, because we want to take
+               // advantage of the entire client area.
+               Window.setMargin("0px");
+               // Finally, add the outer panel to the RootPanel, so that it will be
+               // displayed.
+               RootPanel.get().add(outer);
+               // Call the window resized handler to get the initial sizes setup. Doing
+               // this in a deferred command causes it to occur after all widgets'
+               // sizes have been computed by the browser.
+               DeferredCommand.addCommand(new Command() {
+
+                       @Override
+                       public void execute() {
+                               onWindowResized(Window.getClientHeight());
+                       }
+               });
+       }
+
+       /**
+        * Fetches the User object for the specified username.
+        *
+        * @param username the username of the user
+        */
+       private void fetchUser(final String username) {
+               String path = getApiPath() + username + "/";
+               GetCommand<UserResource> getUserCommand = new GetCommand<UserResource>(UserResource.class, username, path, null) {
+
+                       @Override
+                       public void onComplete() {
+                               
+                               currentUserResource = getResult();
+                               final String announcement = currentUserResource.getAnnouncement();
+                               if (announcement != null)
+                                       DeferredCommand.addCommand(new Command() {
+
+                                               @Override
+                                               public void execute() {
+                                                       displayInformation(announcement);
+                                               }
+                                       });
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("Fetching user error", t);
+                               if (t instanceof RestException)
+                                       GSS.get().displayError("No user found:" + ((RestException) t).getHttpStatusText());
+                               else
+                                       GSS.get().displayError("System error fetching user data:" + t.getMessage());
+                               authenticateUser();
+                       }
+               };
+               DeferredCommand.addCommand(getUserCommand);
+       }
+
+       /**
+        * Parse and store the user credentials to the appropriate fields.
+        */
+       private void parseUserCredentials() {
+               Configuration conf = (Configuration) GWT.create(Configuration.class);
+               String cookie = conf.authCookie();
+               String auth = Cookies.getCookie(cookie);
+               if (auth == null) {
+                       authenticateUser();
+                       // Redundant, but silences warnings about possible auth NPE, below.
+                       return;
+               }
+               int sepIndex = auth.indexOf(conf.cookieSeparator());
+               if (sepIndex == -1)
+                       authenticateUser();
+               token = auth.substring(sepIndex + 1);
+               final String username = auth.substring(0, sepIndex);
+               if (username == null)
+                       authenticateUser();
+
+               refreshWebDAVPassword();
+
+               DeferredCommand.addCommand(new Command() {
+
+                       @Override
+                       public void execute() {
+                               fetchUser(username);
+                       }
+               });
+       }
+
+       /**
+        * Redirect the user to the login page for authentication.
+        */
+       protected void authenticateUser() {
+               Configuration conf = (Configuration) GWT.create(Configuration.class);
+               Window.Location.assign(GWT.getModuleBaseURL() + conf.loginUrl() + "?next=" + GWT.getModuleBaseURL());
+       }
+
+       /**
+        * Clear the cookie and redirect the user to the logout page.
+        */
+       void logout() {
+               Configuration conf = (Configuration) GWT.create(Configuration.class);
+               String cookie = conf.authCookie();
+               String domain = Window.Location.getHostName();
+               String path = Window.Location.getPath();
+               Cookies.setCookie(cookie, "", null, domain, path, false);
+        String baseUrl = GWT.getModuleBaseURL();
+        String homeUrl = baseUrl.substring(0, baseUrl.indexOf(path));
+               Window.Location.assign(homeUrl + conf.logoutUrl());
+       }
+
+       /**
+        * Creates an HTML fragment that places an image & caption together, for use
+        * in a group header.
+        *
+        * @param imageProto an image prototype for an image
+        * @param caption the group caption
+        * @return the header HTML fragment
+        */
+       private String createHeaderHTML(AbstractImagePrototype imageProto, String caption) {
+               String captionHTML = "<table class='caption' cellpadding='0' " 
+               + "cellspacing='0'>" + "<tr><td class='lcaption'>" + imageProto.getHTML() 
+               + "</td><td id =" + caption +" class='rcaption'><b style='white-space:nowrap'>&nbsp;" 
+               + caption + "</b></td></tr></table>";
+               return captionHTML;
+       }
+
+       private void onWindowResized(int height) {
+               // Adjust the split panel to take up the available room in the window.
+               int newHeight = height - splitPanel.getAbsoluteTop() - 44;
+               if (newHeight < 1)
+                       newHeight = 1;
+               splitPanel.setHeight("" + newHeight);
+               inner.setHeight("" + newHeight);
+               /*if(isFileListShowing()){
+                       getFileList().setHeight("" + (newHeight-50));
+               }*/
+       }
+
+       @Override
+       public void onResize(ResizeEvent event) {
+               int height = event.getHeight();
+               onWindowResized(height);
+       }
+
+       public boolean isFileListShowing() {
+               int tab = inner.getTabBar().getSelectedTab();
+               if (tab == 0)
+                       return true;
+               return false;
+       }
+
+       public boolean isSearchResultsShowing() {
+               int tab = inner.getTabBar().getSelectedTab();
+               if (tab == 2)
+                       return true;
+               return false;
+       }
+
+       /**
+        * Make the user list visible.
+        */
+       public void showUserList() {
+               inner.selectTab(1);
+       }
+
+       /**
+        * Make the file list visible.
+        */
+       public void showFileList() {
+               fileList.updateFileCache(true /*clear selection*/);
+               inner.selectTab(0);
+       }
+
+       /**
+        * Make the file list visible.
+        *
+        * @param update
+        */
+       public void showFileList(boolean update) {
+               if(update){
+                       getTreeView().refreshCurrentNode(true);
+               }
+               else{
+                       RestResource currentFolder = getTreeView().getSelection();
+                       if(currentFolder!=null){
+                               showFileList(currentFolder);
+                       }
+               }
+               
+       }
+       
+       public void showFileList(RestResource r) {
+               showFileList(r,true);
+       }
+       
+       public void showFileList(RestResource r, boolean clearSelection) {
+               RestResource currentFolder = r;
+               if(currentFolder!=null){
+                       List<FileResource> files = null;
+                       if (currentFolder instanceof RestResourceWrapper) {
+                               RestResourceWrapper folder = (RestResourceWrapper) currentFolder;
+                               files = folder.getResource().getFiles();
+                       } else if (currentFolder instanceof TrashResource) {
+                               TrashResource folder = (TrashResource) currentFolder;
+                               files = folder.getFiles();
+                       }
+                       else if (currentFolder instanceof SharedResource) {
+                               SharedResource folder = (SharedResource) currentFolder;
+                               files = folder.getFiles();
+                       }
+                       else if (currentFolder instanceof OtherUserResource) {
+                               OtherUserResource folder = (OtherUserResource) currentFolder;
+                               files = folder.getFiles();
+                       }
+                       if (files != null)
+                               getFileList().setFiles(files);
+                       else
+                               getFileList().setFiles(new ArrayList<FileResource>());
+               }
+               fileList.updateFileCache(clearSelection /*clear selection*/);
+               inner.selectTab(0);
+       }
+
+       /**
+        * Make the search results visible.
+        *
+        * @param query the search query string
+        */
+       public void showSearchResults(String query) {
+               searchResults.updateFileCache(query);
+               searchResults.updateCurrentlyShowingStats();
+               inner.selectTab(2);
+       }
+
+       /**
+        * Display the 'loading' indicator.
+        */
+       public void showLoadingIndicator(String message, String path) {
+               if(path!=null){
+                       String[] split = path.split("/");
+                       message = message +" "+URL.decode(split[split.length-1]);
+               }
+               topPanel.getLoading().show(message);
+       }
+
+       /**
+        * Hide the 'loading' indicator.
+        */
+       public void hideLoadingIndicator() {
+               topPanel.getLoading().hide();
+       }
+
+       /**
+        * A native JavaScript method to reach out to the browser's window and
+        * invoke its resizeTo() method.
+        *
+        * @param x the new width
+        * @param y the new height
+        */
+       public static native void resizeTo(int x, int y) /*-{
+               $wnd.resizeTo(x,y);
+       }-*/;
+
+       /**
+        * A helper method that returns true if the user's list is currently visible
+        * and false if it is hidden.
+        *
+        * @return true if the user list is visible
+        */
+       public boolean isUserListVisible() {
+               return inner.getTabBar().getSelectedTab() == 1;
+       }
+
+       /**
+        * Display an error message.
+        *
+        * @param msg the message to display
+        */
+       public void displayError(String msg) {
+               messagePanel.displayError(msg);
+       }
+
+       /**
+        * Display a warning message.
+        *
+        * @param msg the message to display
+        */
+       public void displayWarning(String msg) {
+               messagePanel.displayWarning(msg);
+       }
+
+       /**
+        * Display an informational message.
+        *
+        * @param msg the message to display
+        */
+       public void displayInformation(String msg) {
+               messagePanel.displayInformation(msg);
+       }
+
+       /**
+        * Retrieve the folders.
+        *
+        * @return the folders
+        
+       public Folders getFolders() {
+               return folders;
+       }*/
+
+       /**
+        * Retrieve the search.
+        *
+        * @return the search
+        */
+       Search getSearch() {
+               return search;
+       }
+
+       /**
+        * Retrieve the currentSelection.
+        *
+        * @return the currentSelection
+        */
+       public Object getCurrentSelection() {
+               return currentSelection;
+       }
+
+       /**
+        * Modify the currentSelection.
+        *
+        * @param newCurrentSelection the currentSelection to set
+        */
+       public void setCurrentSelection(Object newCurrentSelection) {
+               currentSelection = newCurrentSelection;
+       }
+
+       /**
+        * Retrieve the groups.
+        *
+        * @return the groups
+        */
+       public Groups getGroups() {
+               return groups;
+       }
+
+       /**
+        * Retrieve the fileList.
+        *
+        * @return the fileList
+        */
+       public FileList getFileList() {
+               return fileList;
+       }
+
+       public SearchResults getSearchResults() {
+               return searchResults;
+       }
+
+       /**
+        * Retrieve the topPanel.
+        *
+        * @return the topPanel
+        */
+       TopPanel getTopPanel() {
+               return topPanel;
+       }
+
+       /**
+        * Retrieve the clipboard.
+        *
+        * @return the clipboard
+        */
+       public Clipboard getClipboard() {
+               return clipboard;
+       }
+
+       public StatusPanel getStatusPanel() {
+               return statusPanel;
+       }
+
+       /**
+        * Retrieve the userDetailsPanel.
+        *
+        * @return the userDetailsPanel
+        */
+       public UserDetailsPanel getUserDetailsPanel() {
+               return userDetailsPanel;
+       }
+
+       
+
+       public String getToken() {
+               return token;
+       }
+
+       public String getWebDAVPassword() {
+               return webDAVPassword;
+       }
+
+       public void removeGlassPanel() {
+               glassPanel.removeFromParent();
+       }
+
+       /**
+        * Retrieve the currentUserResource.
+        *
+        * @return the currentUserResource
+        */
+       public UserResource getCurrentUserResource() {
+               return currentUserResource;
+       }
+
+       /**
+        * Modify the currentUserResource.
+        *
+        * @param newUser the new currentUserResource
+        */
+       public void setCurrentUserResource(UserResource newUser) {
+               currentUserResource = newUser;
+       }
+
+       public static native void preventIESelection() /*-{
+               $doc.body.onselectstart = function () { return false; };
+       }-*/;
+
+       public static native void enableIESelection() /*-{
+               if ($doc.body.onselectstart != null)
+               $doc.body.onselectstart = null;
+       }-*/;
+
+       /**
+        * @return the absolute path of the API root URL
+        */
+       public String getApiPath() {
+               Configuration conf = (Configuration) GWT.create(Configuration.class);
+               return GWT.getModuleBaseURL() + conf.apiPath();
+       }
+
+       public void refreshWebDAVPassword() {
+               Configuration conf = (Configuration) GWT.create(Configuration.class);
+               String domain = Window.Location.getHostName();
+               String path = Window.Location.getPath();
+               String cookie = conf.webdavCookie();
+               webDAVPassword = Cookies.getCookie(cookie);
+               Cookies.setCookie(cookie, "", null, domain, path, false);
+       }
+
+       /**
+        * Convert server date to local time according to browser timezone
+        * and format it according to localized pattern.
+        * Time is always formatted to 24hr format.
+        * NB: This assumes that server runs in UTC timezone. Otherwise
+        * we would need to adjust for server time offset as well.
+        *
+        * @param date
+        * @return String
+        */
+       public static String formatLocalDateTime(Date date) {
+               Date convertedDate = new Date(date.getTime() - date.getTimezoneOffset());
+               final DateTimeFormat dateFormatter = DateTimeFormat.getShortDateFormat();
+               final DateTimeFormat timeFormatter = DateTimeFormat.getFormat("HH:mm");
+               String datePart = dateFormatter.format(convertedDate);
+               String timePart = timeFormatter.format(convertedDate);
+               return datePart + " " + timePart;
+       }
+       
+       /**
+        * History support for folder navigation
+        * adds a new browser history entry
+        *
+        * @param key
+        */
+       public void updateHistory(String key){
+//             Replace any whitespace of the initial string to "+"
+//             String result = key.replaceAll("\\s","+");
+//             Add a new browser history entry.
+//             History.newItem(result);
+               History.newItem(key);
+       }
+
+       /**
+        * This method examines the token input and add a "/" at the end in case it's omitted.
+        * This happens only in Files/trash/, Files/shared/, Files/others.
+        *
+        * @param tokenInput
+        * @return the formated token with a "/" at the end or the same tokenInput parameter
+        */
+
+       private String handleSpecialFolderNames(String tokenInput){
+               List<String> pathsToCheck = Arrays.asList("Files/trash", "Files/shared", "Files/others");
+               if(pathsToCheck.contains(tokenInput))
+                       return tokenInput + "/";
+               return tokenInput;
+
+       }
+
+       /**
+        * Reject illegal resource names, like '.' or '..' or slashes '/'.
+        */
+       static boolean isValidResourceName(String name) {
+               if (".".equals(name) || "..".equals(name) || name.contains("/"))
+                       return false;
+               return true;
+       }
+
+       public void putUserToMap(String _userName, String _userFullName){
+               userFullNameMap.put(_userName, _userFullName);
+       }
+
+       public String findUserFullName(String _userName){
+               return userFullNameMap.get(_userName);
+       }
+       public String getUserFullName(String _userName) {
+               
+        if (GSS.get().findUserFullName(_userName) == null)
+                //if there is no userFullName found then the map fills with the given _userName,
+                //so userFullName = _userName
+                GSS.get().putUserToMap(_userName, _userName);
+        else if(GSS.get().findUserFullName(_userName).indexOf('@') != -1){
+                //if the userFullName = _userName the GetUserCommand updates the userFullName in the map
+                GetUserCommand guc = new GetUserCommand(_userName);
+                guc.execute();
+        }
+        return GSS.get().findUserFullName(_userName);
+       }
+       /**
+        * Retrieve the treeView.
+        *
+        * @return the treeView
+        */
+       public CellTreeView getTreeView() {
+               return treeView;
+       }
+       
+       public void onResourceUpdate(RestResource resource,boolean clearSelection){
+               if(resource instanceof RestResourceWrapper || resource instanceof OtherUserResource || resource instanceof TrashResource || resource instanceof SharedResource){
+                       if(getTreeView().getSelection()!=null&&getTreeView().getSelection().getUri().equals(resource.getUri()))
+                               showFileList(resource,clearSelection);
+               }
+               
+       }
+       
+       
+}
diff --git a/src/org/gss_project/gss/web/client/GSSSelectionEventManager.java b/src/org/gss_project/gss/web/client/GSSSelectionEventManager.java
new file mode 100644 (file)
index 0000000..c2591c2
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+
+/**
+ * @author kman
+ *
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.view.client.CellPreviewEvent;
+import com.google.gwt.view.client.HasData;
+import com.google.gwt.view.client.MultiSelectionModel;
+import com.google.gwt.view.client.Range;
+import com.google.gwt.view.client.SelectionModel;
+
+/**
+ * An implementation of {@link CellPreviewEvent.Handler} that adds selection
+ * support via the spacebar and mouse clicks and handles the control key.
+ * 
+ * <p>
+ * If the {@link HasData} source of the selection event uses a
+ * {@link MultiSelectionModel}, this manager additionally provides support for
+ * shift key to select a range of values. For all other {@link SelectionModel}s,
+ * only the control key is supported.
+ * </p>
+ * 
+ * @param <T> the data type of records in the list
+ */
+public class GSSSelectionEventManager<T> implements
+    CellPreviewEvent.Handler<T> {
+
+  /**
+   * Implementation of {@link EventTranslator} that only triggers selection when
+   * any checkbox is selected.
+   * 
+   * @param <T> the data type
+   */
+  public static class CheckboxEventTranslator<T> implements EventTranslator<T> {
+
+    /**
+     * The column index of the checkbox. Other columns are ignored.
+     */
+    private final int column;
+
+    /**
+     * Construct a new {@link CheckboxEventTranslator} that will trigger
+     * selection when any checkbox in any column is selected.
+     */
+    public CheckboxEventTranslator() {
+      this(-1);
+    }
+
+    /**
+     * Construct a new {@link CheckboxEventTranslator} that will trigger
+     * selection when a checkbox in the specified column is selected.
+     * 
+     * @param column the column index, or -1 for all columns
+     */
+    public CheckboxEventTranslator(int column) {
+      this.column = column;
+    }
+
+    public boolean clearCurrentSelection(CellPreviewEvent<T> event) {
+      return false;
+    }
+
+    public SelectAction translateSelectionEvent(CellPreviewEvent<T> event) {
+      // Handle the event.
+      NativeEvent nativeEvent = event.getNativeEvent();
+      if ("click".equals(nativeEvent.getType())) {
+        // Ignore if the event didn't occur in the correct column.
+        if (column > -1 && column != event.getColumn()) {
+          return SelectAction.IGNORE;
+        }
+
+        // Determine if we clicked on a checkbox.
+        Element target = nativeEvent.getEventTarget().cast();
+        if ("input".equals(target.getTagName().toLowerCase())) {
+          final InputElement input = target.cast();
+          if ("checkbox".equals(input.getType().toLowerCase())) {
+            // Synchronize the checkbox with the current selection state.
+            input.setChecked(event.getDisplay().getSelectionModel().isSelected(
+                event.getValue()));
+            return SelectAction.TOGGLE;
+          }
+        }
+        return SelectAction.IGNORE;
+      }
+
+      // For keyboard events, do the default action.
+      return SelectAction.DEFAULT;
+    }
+  }
+
+  /**
+   * Translates {@link CellPreviewEvent}s into {@link SelectAction}s.
+   */
+  public static interface EventTranslator<T> {
+    /**
+     * Check whether a user selection event should clear all currently selected
+     * values.
+     * 
+     * @param event the {@link CellPreviewEvent} to translate
+     */
+    boolean clearCurrentSelection(CellPreviewEvent<T> event);
+
+    /**
+     * Translate the user selection event into a {@link SelectAction}.
+     * 
+     * @param event the {@link CellPreviewEvent} to translate
+     */
+    SelectAction translateSelectionEvent(CellPreviewEvent<T> event);
+  }
+
+  /**
+   * The action that controls how selection is handled.
+   */
+  public static enum SelectAction {
+    DEFAULT, // Perform the default action.
+    SELECT, // Select the value.
+    DESELECT, // Deselect the value.
+    TOGGLE, // Toggle the selected state of the value.
+    IGNORE; // Ignore the event.
+  }
+
+  /**
+   * Construct a new {@link GSSSelectionEventManager} that triggers
+   * selection when any checkbox in any column is clicked.
+   * 
+   * @param <T> the data type of the display
+   * @return a {@link GSSSelectionEventManager} instance
+   */
+  public static <T> GSSSelectionEventManager<T> createCheckboxManager() {
+    return new GSSSelectionEventManager<T>(new CheckboxEventTranslator<T>());
+  }
+
+  /**
+   * Construct a new {@link GSSSelectionEventManager} that triggers
+   * selection when a checkbox in the specified column is clicked.
+   * 
+   * @param <T> the data type of the display
+   * @param column the column to handle
+   * @return a {@link GSSSelectionEventManager} instance
+   */
+  public static <T> GSSSelectionEventManager<T> createCheckboxManager(
+      int column) {
+    return new GSSSelectionEventManager<T>(new CheckboxEventTranslator<T>(
+        column));
+  }
+
+  /**
+   * Create a new {@link GSSSelectionEventManager} using the specified
+   * {@link EventTranslator} to control which {@link SelectAction} to take for
+   * each event.
+   * 
+   * @param <T> the data type of the display
+   * @param translator the {@link EventTranslator} to use
+   * @return a {@link GSSSelectionEventManager} instance
+   */
+  public static <T> GSSSelectionEventManager<T> createCustomManager(
+      EventTranslator<T> translator) {
+    return new GSSSelectionEventManager<T>(translator);
+  }
+
+  /**
+   * Create a new {@link GSSSelectionEventManager} that handles selection
+   * via user interactions.
+   * 
+   * @param <T> the data type of the display
+   * @return a new {@link GSSSelectionEventManager} instance
+   */
+  public static <T> GSSSelectionEventManager<T> createDefaultManager() {
+    return new GSSSelectionEventManager<T>(null);
+  }
+
+  /**
+   * The last {@link HasData} that was handled.
+   */
+  private HasData<T> lastDisplay;
+
+  /**
+   * The last page start.
+   */
+  private int lastPageStart;
+
+  /**
+   * The last selected row index.
+   */
+  private int lastSelectedIndex = -1;
+
+  /**
+   * A boolean indicating that the last shift selection was additive.
+   */
+  private boolean shiftAdditive;
+
+  /**
+   * The last place where the user clicked without holding shift. Multi
+   * selections that use the shift key are rooted at the anchor.
+   */
+  private int shiftAnchor = -1;
+
+  /**
+   * The {@link EventTranslator} that controls how selection is handled.
+   */
+  private final EventTranslator<T> translator;
+
+  /**
+   * Construct a new {@link GSSSelectionEventManager} using the specified
+   * {@link EventTranslator} to control which {@link SelectAction} to take for
+   * each event.
+   * 
+   * @param translator the {@link EventTranslator} to use
+   */
+  protected GSSSelectionEventManager(EventTranslator<T> translator) {
+    this.translator = translator;
+  }
+
+  /**
+   * Update the selection model based on a user selection event.
+   * 
+   * @param selectionModel the selection model to update
+   * @param row the selected row index relative to the page start
+   * @param rowValue the selected row value
+   * @param action the {@link SelectAction} to apply
+   * @param selectRange true to select the range from the last selected row
+   * @param clearOthers true to clear the current selection
+   */
+  public void doMultiSelection(MultiSelectionModel<? super T> selectionModel,
+      HasData<T> display, int row, T rowValue, SelectAction action,
+      boolean selectRange, boolean clearOthers) {
+    // Determine if we will add or remove selection.
+    boolean addToSelection = true;
+    if (action != null) {
+      switch (action) {
+        case IGNORE:
+          // Ignore selection.
+          return;
+        case SELECT:
+          addToSelection = true;
+          break;
+        case DESELECT:
+          addToSelection = false;
+          break;
+        case TOGGLE:
+          addToSelection = !selectionModel.isSelected(rowValue);
+          break;
+      }
+    }
+
+    // Determine which rows will be newly selected.
+    int pageStart = display.getVisibleRange().getStart();
+    if (selectRange && pageStart == lastPageStart && lastSelectedIndex > -1
+        && shiftAnchor > -1 && display == lastDisplay) {
+      /*
+       * Get the new shift bounds based on the existing shift anchor and the
+       * selected row.
+       */
+      int start = Math.min(shiftAnchor, row); // Inclusive.
+      int end = Math.max(shiftAnchor, row); // Inclusive.
+
+      if (lastSelectedIndex < start) {
+        // Revert previous selection if the user reselects a smaller range.
+        setRangeSelection(selectionModel, display, new Range(lastSelectedIndex,
+            start - lastSelectedIndex), !shiftAdditive, false);
+      } else if (lastSelectedIndex > end) {
+        // Revert previous selection if the user reselects a smaller range.
+        setRangeSelection(selectionModel, display, new Range(end + 1,
+            lastSelectedIndex - end), !shiftAdditive, false);
+      } else {
+        // Remember if we are adding or removing rows.
+        shiftAdditive = addToSelection;
+      }
+
+      // Update the last selected row, but do not move the shift anchor.
+      lastSelectedIndex = row;
+
+      // Select the range.
+      setRangeSelection(selectionModel, display, new Range(start, end - start
+          + 1), shiftAdditive, clearOthers);
+    } else {
+      /*
+       * If we are not selecting a range, save the last row and set the shift
+       * anchor.
+       */
+      lastDisplay = display;
+      lastPageStart = pageStart;
+      lastSelectedIndex = row;
+      shiftAnchor = row;
+      selectOne(selectionModel, rowValue, addToSelection, clearOthers);
+    }
+  }
+
+  public void onCellPreview(CellPreviewEvent<T> event) {
+    // Early exit if selection is already handled or we are editing.
+    if (event.isCellEditing() || event.isSelectionHandled()) {
+      return;
+    }
+
+    // Early exit if we do not have a SelectionModel.
+    HasData<T> display = event.getDisplay();
+    SelectionModel<? super T> selectionModel = display.getSelectionModel();
+    if (selectionModel == null) {
+      return;
+    }
+
+    // Check for user defined actions.
+    SelectAction action = (translator == null) ? SelectAction.DEFAULT
+        : translator.translateSelectionEvent(event);
+
+    // Handle the event based on the SelectionModel type.
+    if (selectionModel instanceof MultiSelectionModel) {
+      // Add shift key support for MultiSelectionModel.
+      handleMultiSelectionEvent(event, action,
+          (MultiSelectionModel<? super T>) selectionModel);
+    } else {
+      // Use the standard handler.
+      handleSelectionEvent(event, action, selectionModel);
+    }
+  }
+
+  /**
+   * Removes all items from the selection.
+   * 
+   * @param selectionModel the {@link MultiSelectionModel} to clear
+   */
+  protected void clearSelection(MultiSelectionModel<? super T> selectionModel) {
+    selectionModel.clear();
+  }
+
+  /**
+   * Handle an event that could cause a value to be selected for a
+   * {@link MultiSelectionModel}. This overloaded method adds support for both
+   * the control and shift keys. If the shift key is held down, all rows between
+   * the previous selected row and the current row are selected.
+   * 
+   * @param event the {@link CellPreviewEvent} that triggered selection
+   * @param action the action to handle
+   * @param selectionModel the {@link SelectionModel} to update
+   */
+  protected void handleMultiSelectionEvent(CellPreviewEvent<T> event,
+      SelectAction action, MultiSelectionModel<? super T> selectionModel) {
+    NativeEvent nativeEvent = event.getNativeEvent();
+    String type = nativeEvent.getType();
+    boolean rightclick = "mousedown".equals(type) && nativeEvent.getButton()==NativeEvent.BUTTON_RIGHT;
+    if(rightclick){
+       boolean shift = nativeEvent.getShiftKey();
+        boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
+        boolean clearOthers = (translator == null) ? !ctrlOrMeta
+            : translator.clearCurrentSelection(event);
+        if (action == null || action == SelectAction.DEFAULT) {
+          action = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT;
+        }
+        //if the row is selected then do nothing
+        if(selectionModel.isSelected(event.getValue())){
+               return;
+        }
+        doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
+            event.getValue(), action, shift, clearOthers);
+    }
+    else if ("click".equals(type)) {
+      /*
+       * Update selection on click. Selection is toggled only if the user
+       * presses the ctrl key. If the user does not press the control key,
+       * selection is additive.
+       */
+      boolean shift = nativeEvent.getShiftKey();
+      boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
+      boolean clearOthers = (translator == null) ? !ctrlOrMeta
+          : translator.clearCurrentSelection(event);
+      if (action == null || action == SelectAction.DEFAULT) {
+        action = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT;
+      }
+      doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
+          event.getValue(), action, shift, clearOthers);
+      if(ctrlOrMeta){
+         event.setCanceled(true);
+      }
+    } else if ("keyup".equals(type)) {
+      int keyCode = nativeEvent.getKeyCode();
+      if (keyCode == 32) {
+        /*
+         * Update selection when the space bar is pressed. The spacebar always
+         * toggles selection, regardless of whether the control key is pressed.
+         */
+        boolean shift = nativeEvent.getShiftKey();
+        boolean clearOthers = (translator == null) ? false
+            : translator.clearCurrentSelection(event);
+        if (action == null || action == SelectAction.DEFAULT) {
+          action = SelectAction.TOGGLE;
+        }
+        doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
+            event.getValue(), action, shift, clearOthers);
+      }
+    }
+  }
+
+  /**
+   * Handle an event that could cause a value to be selected. This method works
+   * for any {@link SelectionModel}. Pressing the space bar or ctrl+click will
+   * toggle the selection state. Clicking selects the row if it is not selected.
+   * 
+   * @param event the {@link CellPreviewEvent} that triggered selection
+   * @param action the action to handle
+   * @param selectionModel the {@link SelectionModel} to update
+   */
+  protected void handleSelectionEvent(CellPreviewEvent<T> event,
+      SelectAction action, SelectionModel<? super T> selectionModel) {
+    // Handle selection overrides.
+    T value = event.getValue();
+    if (action != null) {
+      switch (action) {
+        case IGNORE:
+          return;
+        case SELECT:
+          selectionModel.setSelected(value, true);
+          return;
+        case DESELECT:
+          selectionModel.setSelected(value, false);
+          return;
+        case TOGGLE:
+          selectionModel.setSelected(value, !selectionModel.isSelected(value));
+          return;
+      }
+    }
+
+    // Handle default selection.
+    NativeEvent nativeEvent = event.getNativeEvent();
+    String type = nativeEvent.getType();
+    if ("click".equals(type)) {
+      if (nativeEvent.getCtrlKey() || nativeEvent.getMetaKey()) {
+        // Toggle selection on ctrl+click.
+        selectionModel.setSelected(value, !selectionModel.isSelected(value));
+      } else {
+        // Select on click.
+        selectionModel.setSelected(value, true);
+      }
+    } else if ("keyup".equals(type)) {
+      // Toggle selection on space.
+      int keyCode = nativeEvent.getKeyCode();
+      if (keyCode == 32) {
+        selectionModel.setSelected(value, !selectionModel.isSelected(value));
+      }
+    }
+  }
+
+  /**
+   * Selects the given item, optionally clearing any prior selection.
+   * 
+   * @param selectionModel the {@link MultiSelectionModel} to update
+   * @param target the item to select
+   * @param selected true to select, false to deselect
+   * @param clearOthers true to clear all other selected items
+   */
+  protected void selectOne(MultiSelectionModel<? super T> selectionModel,
+      T target, boolean selected, boolean clearOthers) {
+    if (clearOthers) {
+      clearSelection(selectionModel);
+    }
+    selectionModel.setSelected(target, selected);
+  }
+
+  /**
+   * Select or deselect a range of row indexes, optionally deselecting all other
+   * values.
+   * 
+   * @param selectionModel the {@link MultiSelectionModel} to update
+   * @param display the {@link HasData} source of the selection event
+   * @param range the {@link Range} of rows to select or deselect
+   * @param addToSelection true to select, false to deselect the range
+   * @param clearOthers true to deselect rows not in the range
+   */
+  protected void setRangeSelection(
+      MultiSelectionModel<? super T> selectionModel, HasData<T> display,
+      Range range, boolean addToSelection, boolean clearOthers) {
+    // Get the list of values to select.
+    List<T> toUpdate = new ArrayList<T>();
+    int itemCount = display.getVisibleItemCount();
+    int start = range.getStart();
+    int end = start + range.getLength();
+    for (int i = start; i < end ; i++) {
+            toUpdate.add(display.getVisibleItem(i-display.getVisibleRange().getStart()));
+       }
+    // Clear all other values.
+    if (clearOthers) {
+      clearSelection(selectionModel);
+    }
+
+    // Update the state of the values.
+    for (T value : toUpdate) {
+      selectionModel.setSelected(value, addToSelection);
+    }
+  }
+}
+
diff --git a/src/org/gss_project/gss/web/client/GlassPanel.java b/src/org/gss_project/gss/web/client/GlassPanel.java
new file mode 100644 (file)
index 0000000..68bfabe
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.SimplePanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class GlassPanel extends Composite{
+
+       public GlassPanel(){
+               SimplePanel mySimplePanel = new SimplePanel();
+           initWidget(mySimplePanel);
+           setStyleName("gwt-GlassPanel");
+           setWidth("100%");
+           setHeight("100%");
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/GroupContextMenu.java b/src/org/gss_project/gss/web/client/GroupContextMenu.java
new file mode 100644 (file)
index 0000000..6695c9d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.Groups.Images;
+import org.gss_project.gss.web.client.commands.CopyCommand;
+import org.gss_project.gss.web.client.commands.DeleteUserOrGroupCommand;
+import org.gss_project.gss.web.client.commands.NewGroupCommand;
+import org.gss_project.gss.web.client.commands.NewUserCommand;
+import org.gss_project.gss.web.client.commands.PasteCommand;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.TreeItem;
+
+
+/**
+ * @author kman
+ *
+ */
+public class GroupContextMenu extends PopupPanel {
+
+       /**
+        * The widget's images.
+        */
+       private final Images images;
+       private MenuItem copy;
+       private MenuItem paste;
+       private MenuItem newGroup;
+       private MenuItem addUser;
+       private MenuItem delete;
+       public GroupContextMenu(final Images newImages) {
+               // The popup's constructor's argument is a boolean specifying that it
+               // auto-close itself when the user clicks outside of it.
+               super(true);
+               images=newImages;
+               setAnimationEnabled(true);
+               final MenuBar contextMenu = new MenuBar(true);
+               newGroup = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.groupNew()).getHTML() + "&nbsp;New Group</span>", true, new NewGroupCommand(this));
+               newGroup.getElement().setId("groupContextMenu.newGroup");
+               contextMenu.addItem(newGroup);
+               
+               addUser = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.groupNew()).getHTML() + "&nbsp;Add User</span>", true, new NewUserCommand(this));
+               addUser.getElement().setId("groupContextMenu.addUser");
+               contextMenu.addItem(addUser);
+                               
+               copy = new MenuItem("<span id=groupContextMenu.copyUser>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy User</span>", true, new CopyCommand(this));
+               copy.getElement().setId("groupContextMenu.copyUser");
+               contextMenu.addItem(copy);
+               
+               paste = new MenuItem("<span id=groupContextMenu.pasteUser>" + AbstractImagePrototype.create(newImages.paste()).getHTML() + "&nbsp;Paste User</span>", true, new PasteCommand(this));
+               paste.getElement().setId("groupContextMenu.pasteUser");
+               contextMenu.addItem(paste);
+               
+               delete = new MenuItem("<span id=groupContextMenu.delete>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteUserOrGroupCommand(this,images));
+               delete.getElement().setId("groupContextMenu.delete");
+               contextMenu.addItem(delete);
+               
+               add(contextMenu);
+
+       }
+
+       /* (non-Javadoc)
+        * @see com.google.gwt.user.client.ui.PopupPanel#show()
+        */
+       @Override
+       public void show() {
+               TreeItem current = GSS.get().getGroups().getCurrent();
+               if(current==null){
+                       copy.setVisible(false);
+                       paste.setVisible(false);
+                       addUser.setVisible(false);
+                       delete.setVisible(false);
+               }
+               else{
+                       newGroup.setVisible(false);
+                       if(current.getUserObject() instanceof GroupUserResource && GSS.get().getCurrentSelection() instanceof GroupUserResource)
+                               copy.setVisible(true);
+                       else
+                               copy.setVisible(false);
+                       if(current.getUserObject() instanceof GroupResource && GSS.get().getCurrentSelection() instanceof GroupResource && GSS.get().getClipboard().hasUserItem())
+                               paste.setVisible(true);
+                       else
+                               paste.setVisible(false);
+               }
+               super.show();
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/GroupMenu.java b/src/org/gss_project/gss/web/client/GroupMenu.java
new file mode 100644 (file)
index 0000000..7e38c7e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.commands.NewGroupCommand;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * The 'Group' menu implementation.
+ */
+public class GroupMenu extends PopupPanel implements ClickHandler {
+       /**
+        * The widget's images.
+        */
+       private Images images;
+       private final MenuBar contextMenu;
+
+       /**
+        * An image bundle for this widgets images.
+        */
+       public interface Images extends ClientBundle {
+               @Source("org/gss_project/gss/resources/groupevent.png")
+               ImageResource groupNew();
+
+               @Source("org/gss_project/gss/resources/view_text.png")
+               ImageResource viewText();
+
+       }
+
+       /**
+        * The widget's constructor.
+        *
+        * @param newImages the image bundle passed on by the parent object
+        */
+       public GroupMenu(final Images newImages) {
+               // The popup's constructor's argument is a boolean specifying that it
+               // auto-close itself when the user clicks outside of it.
+               super(true);
+               setAnimationEnabled(true);
+               images = newImages;
+
+               contextMenu = new MenuBar(true);
+               MenuItem newGroupItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.groupNew()).getHTML() + "&nbsp;New Group</span>", true, new NewGroupCommand(this));
+               newGroupItem.getElement().setId("topMenu.group.newGroup");
+               contextMenu.addItem(newGroupItem);
+               
+               add(contextMenu);
+       }
+
+       @Override
+       public void onClick(ClickEvent event) {
+               GroupMenu menu = new GroupMenu(images);
+               int left = event.getRelativeElement().getAbsoluteLeft();
+               int top = event.getRelativeElement().getAbsoluteTop() + event.getRelativeElement().getOffsetHeight();
+               menu.setPopupPosition(left, top);
+
+               menu.show();
+       }
+
+       /**
+        * Retrieve the contextMenu.
+        *
+        * @return the contextMenu
+        */
+       public MenuBar getContextMenu() {
+               contextMenu.setAutoOpen(false);
+               return contextMenu;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/GroupPropertiesDialog.java b/src/org/gss_project/gss/web/client/GroupPropertiesDialog.java
new file mode 100644 (file)
index 0000000..e33c7fd
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * @author kman
+ */
+public class GroupPropertiesDialog extends DialogBox {
+
+       /**
+        * The widget that holds the folderName of the folder.
+        */
+       private TextBox groupName = new TextBox();
+
+       /**
+        * A flag that denotes whether the dialog will be used to create or modify a
+        * folder.
+        */
+       private final boolean create;
+
+       /**
+        * The widget's constructor.
+        *
+        * @param _create true if the dialog is displayed for creating a new
+        *            sub-folder of the selected folder, false if it is displayed
+        *            for modifying the selected folder
+        */
+       public GroupPropertiesDialog(final boolean _create) {
+               setAnimationEnabled(true);
+               create = _create;
+               // Use this opportunity to set the dialog's caption.
+               if (create)
+                       setText("Create Group");
+               else
+                       setText("Group properties");
+               final VerticalPanel panel = new VerticalPanel();
+               setWidget(panel);
+               groupName.getElement().setId("groupDialog.textBox.name");
+               final Grid generalTable = new Grid(1, 2);
+               generalTable.setText(0, 0, "Group Name");
+               generalTable.setWidget(0, 1, groupName);
+               generalTable.getCellFormatter().setStyleName(0, 0, "props-labels");
+               generalTable.getCellFormatter().setStyleName(0, 1, "props-values");
+               generalTable.setCellSpacing(4);
+
+               panel.add(generalTable);
+               final HorizontalPanel buttons = new HorizontalPanel();
+               final Button ok = new Button("OK", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               createGroup(groupName.getText());
+                               hide();
+                       }
+               });
+               ok.getElement().setId("groupDialog.button.ok");
+               buttons.add(ok);
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);
+               // Create the 'Cancel' button, along with a listener that hides the
+               // dialog
+               // when the button is clicked.
+               final Button cancel = new Button("Cancel", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               hide();
+                       }
+               });
+               cancel.getElement().setId("groupDialog.button.cancel");
+               buttons.add(cancel);
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+               buttons.setSpacing(8);
+               buttons.addStyleName("gss-TabPanelBottom");
+               panel.add(buttons);
+               panel.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
+               //panel.addStyleName("gss-DialogBox");
+               panel.addStyleName("gss-TabPanelBottom");               
+       }
+       @Override
+       public void center() {
+               super.center();
+               groupName.setFocus(true);
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+                       // Use the popup's key preview hooks to close the dialog when either
+                       // enter or escape is pressed.
+                       switch (evt.getKeyCode()) {
+                               case KeyCodes.KEY_ENTER:
+                                       hide();
+                                       createGroup( groupName.getText());
+                                       break;
+                               case KeyCodes.KEY_ESCAPE:
+                                       hide();
+                                       break;
+                       }
+       }
+
+
+       /**
+        * Generate an RPC request to create a new group.
+        *
+        * @param userId the ID of the user whose namespace will be searched for
+        *            groups
+        * @param aGroupName the name of the group to create
+        */
+       private void createGroup(String aGroupName) {
+
+               if (aGroupName == null || aGroupName.length() == 0) {
+                       GSS.get().displayError("Empty group name!");
+                       return;
+               }
+               GWT.log("createGroup(" + aGroupName + ")", null);
+               PostCommand cg = new PostCommand(GSS.get().getCurrentUserResource().getGroupsPath()+"?name="+URL.encodeComponent(aGroupName), "", 201){
+
+                       @Override
+                       public void onComplete() {
+                               GSS.get().getGroups().updateGroups();
+                               GSS.get().showUserList();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       if(statusCode == 405)
+                                               GSS.get().displayError("You don't have the necessary permissions");
+                                       else if(statusCode == 404)
+                                               GSS.get().displayError("Resource does not exist");
+                                       else if(statusCode == 409)
+                                               GSS.get().displayError("A group with the same name already exists");
+                                       else if(statusCode == 413)
+                                               GSS.get().displayError("Your quota has been exceeded");
+                                       else
+                                               GSS.get().displayError("Unable to create group:"+((RestException)t).getHttpStatusText());
+                               }
+                               else
+                                       GSS.get().displayError("System error creating group:"+t.getMessage());
+                       }
+               };
+               DeferredCommand.addCommand(cg);
+
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/Groups.java b/src/org/gss_project/gss/web/client/Groups.java
new file mode 100644 (file)
index 0000000..8f3aea3
--- /dev/null
@@ -0,0 +1,360 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.rest.GetCommand;\r
+import org.gss_project.gss.web.client.rest.MultipleGetCommand;\r
+import org.gss_project.gss.web.client.rest.resource.GroupResource;\r
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;\r
+import org.gss_project.gss.web.client.rest.resource.GroupsResource;\r
+\r
+import java.util.List;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ContextMenuEvent;\r
+import com.google.gwt.event.dom.client.ContextMenuHandler;\r
+import com.google.gwt.event.logical.shared.OpenEvent;\r
+import com.google.gwt.event.logical.shared.OpenHandler;\r
+import com.google.gwt.event.logical.shared.SelectionEvent;\r
+import com.google.gwt.event.logical.shared.SelectionHandler;\r
+import com.google.gwt.resources.client.ClientBundle;\r
+import com.google.gwt.resources.client.ImageResource;\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.Event;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Composite;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.Tree;\r
+import com.google.gwt.user.client.ui.TreeItem;\r
+\r
+/**\r
+ * A component that displays a list of the user's groups.\r
+ */\r
+public class Groups extends Composite implements SelectionHandler, OpenHandler {\r
+\r
+       /**\r
+        * An image bundle for this widget.\r
+        */\r
+       public interface Images extends Tree.Resources, ClientBundle, FileMenu.Images, EditMenu.Images, GroupMenu.Images, MessagePanel.Images {\r
+\r
+               /**\r
+                * Will bundle the file 'groupevent.png' residing in the package\r
+                * 'org.gss_project.gss.web.resources'.\r
+                *\r
+                * @return the image prototype\r
+                */\r
+               @Source("org/gss_project/gss/resources/groupevent.png")\r
+               ImageResource groupImage();\r
+\r
+               @Override\r
+               @Source("org/gss_project/gss/resources/editdelete.png")\r
+               ImageResource delete();\r
+\r
+       }\r
+\r
+       /**\r
+        * cached latest group selection (for selecting and expanding on refresh)\r
+        */\r
+       private String selectedGroup = null;\r
+\r
+       /**\r
+        * The tree widget that displays the groups.\r
+        */\r
+       private Tree tree;\r
+\r
+       /**\r
+        * A cached copy of the currently selected group widget.\r
+        */\r
+       private TreeItem current;\r
+\r
+       /**\r
+        * A cached copy of the previously selected group widget.\r
+        */\r
+       private TreeItem previous;\r
+\r
+       /**\r
+        * The widget's image bundle.\r
+        */\r
+       private final Images images;\r
+\r
+       private GroupContextMenu menu;\r
+\r
+       /**\r
+        * Constructs a new groups widget with a bundle of images.\r
+        *\r
+        * @param newImages a bundle that provides the images for this widget\r
+        */\r
+       public Groups(final Images newImages) {\r
+\r
+               images = newImages;\r
+               menu = new GroupContextMenu(images);\r
+               tree = new Tree(newImages);\r
+               this.addHandler(new ContextMenuHandler() {\r
+\r
+                       @Override\r
+                       public void onContextMenu(ContextMenuEvent event) {\r
+                               if(current==null) return;\r
+                               int left = current.getAbsoluteLeft() + 40;\r
+                               int top = current.getAbsoluteTop() + 20;\r
+                               showPopup(left, top);\r
+\r
+                       }\r
+               }, ContextMenuEvent.getType());\r
+               tree.getElement().setId("groupsList.tree");\r
+               tree.addSelectionHandler(this);\r
+               tree.addOpenHandler(this);\r
+               tree.setAnimationEnabled(true);\r
+               initWidget(tree);\r
+               this.getElement().setAttribute("id", "CreativeFilesPanel");\r
+               setStylePrimaryName("gss-Groups");\r
+               sinkEvents(Event.ONCONTEXTMENU);\r
+               sinkEvents(Event.ONMOUSEUP);\r
+               sinkEvents(Event.ONDBLCLICK);\r
+               sinkEvents(Event.KEYEVENTS);\r
+       }\r
+\r
+\r
+       /**\r
+        * Make an RPC call to retrieve the groups that belong to the specified\r
+        * user.\r
+        */\r
+       public void updateGroups() {\r
+               GetCommand<GroupsResource> gg = new GetCommand<GroupsResource>(GroupsResource.class, GSS.get().getCurrentUserResource().getGroupsPath(),null){\r
+\r
+                       @Override\r
+                       public void onComplete() {\r
+                               GroupsResource res = getResult();\r
+                               MultipleGetCommand<GroupResource> ga = new MultipleGetCommand<GroupResource>(GroupResource.class, res.getGroupPaths().toArray(new String[]{}), null){\r
+\r
+                                       @Override\r
+                                       public void onComplete() {\r
+                                               List<GroupResource> groupList = getResult();\r
+                                               tree.clear();\r
+                                               for (int i = 0; i < groupList.size(); i++) {\r
+                                                       final TreeItem item = new TreeItem();\r
+                                                       item.setWidget(imageItemHTML(images.groupImage(), groupList.get(i).getName(),item));\r
+                                                       item.setUserObject(groupList.get(i));                                                   \r
+                                                       tree.addItem(item);\r
+                                                       updateUsers(item);\r
+                                               }\r
+                                       }\r
+\r
+                                       @Override\r
+                                       public void onError(Throwable t) {\r
+                                               GWT.log("", t);\r
+                                       }\r
+\r
+                                       @Override\r
+                                       public void onError(String p, Throwable throwable) {\r
+                                               GWT.log("Path:"+p, throwable);\r
+                                       }\r
+                               };\r
+                               DeferredCommand.addCommand(ga);\r
+                       }\r
+\r
+                       @Override\r
+                       public void onError(Throwable t) {\r
+\r
+                       }\r
+               };\r
+               DeferredCommand.addCommand(gg);\r
+       }\r
+\r
+       /**\r
+        *  update status panel with currently showing file stats\r
+        */\r
+       public void updateCurrentlyShowingStats() {\r
+               GSS.get().getStatusPanel().updateCurrentlyShowing(null); //clear stats - nothing to show for the groups tab\r
+       }\r
+\r
+       /**\r
+        * A helper method to simplify adding tree items that have attached images.\r
+        *\r
+        * @param parent the tree item to which the new item will be added.\r
+        * @param title the text associated with this item.\r
+        * @param imageProto\r
+        * @return the new tree item\r
+        */\r
+       private TreeItem addImageItem(final TreeItem parent, final String title, final ImageResource imageProto) {\r
+               final TreeItem item = new TreeItem();\r
+               item.setWidget(imageItemHTML(imageProto, title,item));\r
+               parent.addItem(item);\r
+               return item;\r
+       }\r
+\r
+       /**\r
+        * Generates HTML for a tree item with an attached icon.\r
+        *\r
+        * @param imageProto the icon image\r
+        * @param title the title of the item\r
+        * @return the resultant HTML\r
+        */\r
+       private HTML imageItemHTML(final ImageResource imageProto, final String title,final TreeItem item) {\r
+               final HTML link = new HTML("<a class='hidden-link' href='javascript:;'>" + "<span id='groupsList."+title+"'>" + AbstractImagePrototype.create(imageProto).getHTML() + "&nbsp;" + title + "</span>" + "</a>"){\r
+                       @Override\r
+                       public void onBrowserEvent(Event event) {\r
+                               switch (DOM.eventGetType(event)) {\r
+                                       case Event.ONMOUSEDOWN:\r
+                                               if (DOM.eventGetButton(event) == NativeEvent.BUTTON_RIGHT || DOM.eventGetButton(event) == NativeEvent.BUTTON_LEFT)\r
+                                                       onSelection(item);\r
+                                               break;\r
+                                       case Event.ONCONTEXTMENU:\r
+                                               showPopup(event.getClientX(), event.getClientY());\r
+                                               event.preventDefault();\r
+                                               event.stopPropagation();\r
+                                               break;\r
+                               }\r
+                               super.onBrowserEvent(event);\r
+\r
+                       }\r
+               };                      \r
+               link.sinkEvents(Event.ONMOUSEDOWN);\r
+               link.sinkEvents(Event.ONCONTEXTMENU);\r
+               link.sinkEvents(Event.ONCLICK);\r
+               link.sinkEvents(Event.ONKEYDOWN);               \r
+               return link;\r
+       }\r
+\r
+\r
+\r
+       protected void showPopup(final int x, final int y) {\r
+               menu.hide();\r
+               menu = new GroupContextMenu(images);\r
+               menu.setPopupPosition(x, y);\r
+               menu.show();\r
+       }\r
+\r
+\r
+\r
+       /**\r
+        * Generate an RPC request to retrieve the users of the specified group for\r
+        * display.\r
+        *\r
+        * @param groupItem the TreeItem widget that corresponds to the requested\r
+        *            group\r
+        */\r
+       void updateUsers(final TreeItem groupItem) {\r
+               if(groupItem.getUserObject() instanceof GroupResource){\r
+                       GroupResource res = (GroupResource) groupItem.getUserObject();\r
+                       MultipleGetCommand<GroupUserResource> gu = new MultipleGetCommand<GroupUserResource>(GroupUserResource.class, res.getUserPaths().toArray(new String[]{}), null){\r
+                               @Override\r
+                               public void onComplete() {\r
+                                       List<GroupUserResource> users = getResult();\r
+                                       groupItem.removeItems();\r
+                                       for (int i = 0; i < users.size(); i++) {\r
+                                               final TreeItem userItem = addImageItem(groupItem, users.get(i).getName() + " &lt;" + users.get(i).getUsername() + "&gt;", images.permUser());\r
+                                               userItem.setUserObject(users.get(i));\r
+                                       }\r
+                                       if (selectedGroup != null && groupItem.getText().equals(selectedGroup)) {\r
+                                               //SelectionEvent.fire(tree, groupItem);;\r
+                                               onSelection(groupItem);\r
+                                               groupItem.setState(true);\r
+                                       }\r
+                               }\r
+\r
+                               @Override\r
+                               public void onError(Throwable t) {\r
+                                       GWT.log("", t);\r
+                               }\r
+\r
+                               @Override\r
+                               public void onError(String p, Throwable throwable) {\r
+                                       GWT.log("Path:"+p, throwable);\r
+                               }\r
+                       };\r
+                       DeferredCommand.addCommand(gu);\r
+               }\r
+\r
+       }\r
+\r
+       /**\r
+        * Retrieve the current.\r
+        *\r
+        * @return the current\r
+        */\r
+       TreeItem getCurrent() {\r
+               return current;\r
+       }\r
+\r
+       /**\r
+        * Modify the current.\r
+        *\r
+        * @param newCurrent the current to set\r
+        */\r
+       void setCurrent(final TreeItem newCurrent) {\r
+               current = newCurrent;\r
+       }\r
+\r
+       /**\r
+        * Retrieve the previous.\r
+        *\r
+        * @return the previous\r
+        */\r
+       private TreeItem getPrevious() {\r
+               return previous;\r
+       }\r
+\r
+       /**\r
+        * Modify the previous.\r
+        *\r
+        * @param newPrevious the previous to set\r
+        */\r
+       private void setPrevious(final TreeItem newPrevious) {\r
+               previous = newPrevious;\r
+       }\r
+\r
+       @Override\r
+       public void setVisible(final boolean visible) {\r
+               super.setVisible(visible);\r
+               if (visible)\r
+                       updateGroups();\r
+       }\r
+\r
+       @Override\r
+       public void onSelection(SelectionEvent event) {\r
+               final TreeItem item = (TreeItem)event.getSelectedItem();\r
+               onSelection(item);\r
+\r
+       }\r
+\r
+       private void onSelection(TreeItem item){\r
+               final Object selected = item.getUserObject();\r
+               // Preserve the previously selected item, so that the current's\r
+               // onClick() method gets a chance to find it.\r
+               if (getPrevious() != null)\r
+                       getPrevious().getWidget().removeStyleName("gss-SelectedRow");\r
+               setCurrent(item);\r
+               getCurrent().getWidget().addStyleName("gss-SelectedRow");\r
+               setPrevious(getCurrent());\r
+               GSS.get().setCurrentSelection(selected);\r
+               //cache the latest top level node (group) for selecting and expanding on refresh\r
+               if (item.getParentItem() == null)\r
+                       selectedGroup = item.getText();\r
+               else\r
+                       selectedGroup = item.getParentItem().getText();\r
+       }\r
+\r
+       @Override\r
+       public void onOpen(OpenEvent event) {\r
+               final TreeItem item = (TreeItem) event.getTarget();\r
+               updateUsers(item);\r
+       }\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/GssCellTable.css b/src/org/gss_project/gss/web/client/GssCellTable.css
new file mode 100644 (file)
index 0000000..0496d77
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed 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.
+ */
+/* Incremental changes from CellTable.css */ 
+.cellTableFooter {
+  padding: 3px 9px;
+}
+
+.cellTableHeader {
+  /*padding: 3px 9px;*/
+  border:none;
+       background-color: #E0EDFE;
+       font-weight: bold;
+       cursor: pointer;
+}
+
+.cellTableCell {
+  padding: 4px 9px;
+  border-width: 0;
+}
+
+.cellTableFirstColumn {
+  padding: 0px;
+}
+
+.cellTableLastColumn {
+  padding: 0px;
+}
+
+.cellTableFirstColumnFooter {
+  border: 0px;
+  padding: 0px;
+}
+
+.cellTableFirstColumnHeader {
+  border: 0px;
+  padding: 0px;
+}
+
+.cellTableLastColumnFooter {
+  border: 0px;
+  padding: 0px;
+}
+
+.cellTableLastColumnHeader {
+  border: 0px;
+  padding: 0px;
+}
+
+.cellTableEvenRow {
+  cursor: hand;
+  cursor: pointer;
+}
+
+.cellTableOddRow {
+  cursor: hand;
+  cursor: pointer;
+}
+
+.cellTableSelectedRow {
+  background: #628cd5;
+  color: white;
+  height: auto;
+  overflow: auto;
+}
+
+ .cellTableHoveredRow {
+  
+  /*background-color: #E0EDFE;
+  color: white;
+  height: auto;
+  overflow: auto;*/
+}
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/client/GssCellTreeBasic.css b/src/org/gss_project/gss/web/client/GssCellTreeBasic.css
new file mode 100644 (file)
index 0000000..b37b22e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed 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.
+ */
+.cellTreeWidget {
+  
+}
+
+.cellTreeEmptyMessage {
+  padding-left: 16px;
+  font-style: italic;
+}
+
+.cellTreeItem {
+  padding-top: 4px;
+  padding-bottom: 4px;
+  cursor: hand;
+  cursor: pointer;
+  zoom: 1;
+}
+
+.cellTreeItemImage {
+  
+}
+
+.cellTreeItemImageValue {
+  zoom: 1;
+}
+
+.cellTreeItemValue {
+  padding-left: 3px;
+  padding-right: 3px;
+  outline: none;
+}
+
+.cellTreeOpenItem {
+  
+}
+
+.cellTreeTopItem {
+  
+}
+
+.cellTreeTopItemImage {
+  
+}
+
+.cellTreeTopItemImageValue {
+  
+}
+
+.cellTreeKeyboardSelectedItem {
+  background-color: #ffc;
+  outline: none;
+}
+
+.cellTreeSelectedItem {
+  background-color: #628cd5;
+  color: white;
+  height: auto;
+  overflow: visible;
+}
+
+.cellTreeShowMoreButton {
+  padding-left: 16px;
+  outline: none;
+}
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/client/HelpMenu.java b/src/org/gss_project/gss/web/client/HelpMenu.java
new file mode 100644 (file)
index 0000000..2868a9b
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * The 'Help' menu implementation.
+ */
+public class HelpMenu extends PopupPanel implements ClickHandler {
+
+       /**
+        * The widget's images.
+        */
+       private final Images images;
+
+       private MenuBar contextMenu  = new MenuBar(true);
+
+       /**
+        * An image bundle for this widget's images.
+        */
+       public interface Images extends ClientBundle{
+               @Source("org/gss_project/gss/resources/khelpcenter.png")
+               ImageResource userGuide();
+
+               @Source("org/gss_project/gss/resources/linewidth.png")
+               ImageResource terms();
+
+               @Source("org/gss_project/gss/resources/bell.png")
+               ImageResource reportAbuse();
+
+               @Source("org/gss_project/gss/resources/bug.png")
+               ImageResource reportBug();
+
+               @Source("org/gss_project/gss/resources/info.png")
+               ImageResource about();
+
+               @Source("org/gss_project/gss/resources/edit_add.png")
+               ImageResource upgradeQuota();
+       }
+
+       /**
+        * The widget's constructor.
+        *
+        * @param newImages the image bundle passed on by the parent object
+        */
+       public HelpMenu(final Images newImages) {
+               // The popup's constructor's argument is a boolean specifying that it
+               // auto-close itself when the user clicks outside of it.
+               super(true);
+               setAnimationEnabled(true);
+               images = newImages;
+               createMenu();
+               add(contextMenu);
+       }
+
+       @Override
+       public void onClick(ClickEvent event) {
+               HelpMenu menu = new HelpMenu(images);
+               int left = event.getRelativeElement().getAbsoluteLeft();
+               int top = event.getRelativeElement().getAbsoluteTop() + event.getRelativeElement().getOffsetHeight();
+               menu.setPopupPosition(left, top);
+               menu.show();
+       }
+
+       public MenuBar createMenu() {
+               contextMenu.clearItems();
+               contextMenu.setAutoOpen(false);
+               Command hideCommand = new Command() {
+                       @Override
+                       public void execute() {
+                               hide();
+                       }
+               };
+               Command aboutCommand = new Command(){
+                       @Override
+                       public void execute() {
+                               AboutDialog dlg = new AboutDialog();
+                               dlg.center();
+                       }
+               };
+               MenuItem userGuideItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.userGuide()).getHTML() + "&nbsp;<a class='hidden-link' " +
+                                       "href='/userguide/el' target='_blank'>User Guide</a></span>", true, hideCommand);
+               contextMenu.addItem(userGuideItem);
+               userGuideItem.getElement().setId("topMenu.help.userGuide");
+               
+               MenuItem termsItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.terms()).getHTML() + "&nbsp;<a class='hidden-link' " +
+                                       "href='/terms' target='_blank'>Terms &amp; Conditions</a></span>", true, hideCommand);
+               termsItem.getElement().setId("topMenu.help.terms");
+               contextMenu.addItem(termsItem);
+               
+               MenuItem reportAbuseItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.reportAbuse()).getHTML() + "&nbsp;<a class='hidden-link' " +
+                                       "href='/report-abuse' target='_blank'>Report abuse</a></span>", true, hideCommand);
+               reportAbuseItem.getElement().setId("topMenu.help.reportAbuse");
+               contextMenu.addItem(reportAbuseItem);
+               
+               MenuItem upgradeQuotaItem= new MenuItem("<span>" + AbstractImagePrototype.create(images.upgradeQuota()).getHTML() + "&nbsp;<a class='hidden-link' " +
+                                       "href='/pithos/coupon' target='_blank'>Upgrade quota</a></span>", true, hideCommand);
+               upgradeQuotaItem.getElement().setId("topMenu.help.upgradeQuota");
+               contextMenu.addItem(upgradeQuotaItem);
+               
+               MenuItem reportBugItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.reportBug()).getHTML() + "&nbsp;<a class='hidden-link' " +
+                                       "href='http://code.google.com/p/gss/issues/list' target='_blank'>Report bug</a></span>", true, hideCommand);
+               reportBugItem.getElement().setId("topMenu.help.reportBug");
+               contextMenu.addItem(reportBugItem);
+                               
+               MenuItem aboutItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.about()).getHTML() + "&nbsp;About</span>", true, aboutCommand);
+               aboutItem.getElement().setId("topMenu.help.about");
+               contextMenu.addItem(aboutItem);
+               return contextMenu;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/InsufficientPermissionsException.java b/src/org/gss_project/gss/web/client/InsufficientPermissionsException.java
new file mode 100644 (file)
index 0000000..00c04ad
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import java.io.Serializable;
+
+/**
+ * An exception that is thrown when an operation cannot be performed due to the
+ * user having insufficient permissions.
+ *
+ * @author chstath
+ */
+public class InsufficientPermissionsException extends Exception implements Serializable {
+
+       /**
+        * The serial version UID.
+        */
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * The stored message that provides details about the problem.
+        */
+       private String message;
+
+       /**
+        *
+        */
+       public InsufficientPermissionsException() {
+       }
+
+       /**
+        * @param newMessage
+        */
+       public InsufficientPermissionsException(final String newMessage) {
+               super(newMessage);
+               message = newMessage;
+       }
+
+       /**
+        * @param cause
+        */
+       public InsufficientPermissionsException(final Throwable cause) {
+               super(cause);
+
+       }
+
+       /**
+        * @param newMessage
+        * @param cause
+        */
+       public InsufficientPermissionsException(final String newMessage, final Throwable cause) {
+               super(newMessage, cause);
+               message = newMessage;
+       }
+
+       @Override
+       public String getMessage() {
+               return message;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/LoadingIndicator.java b/src/org/gss_project/gss/web/client/LoadingIndicator.java
new file mode 100644 (file)
index 0000000..a8d2835
--- /dev/null
@@ -0,0 +1,84 @@
+/*\r
+ * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import com.google.gwt.resources.client.ClientBundle;\r
+import com.google.gwt.resources.client.ImageResource;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Composite;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'loading' indicator widget implementation.\r
+ */\r
+public class LoadingIndicator extends Composite {\r
+       public static final String DEFAULT_MESSAGE="Please Wait";\r
+       \r
+       HTML messageLabel;\r
+       /**\r
+        * An image bundle for this widgets images.\r
+        */\r
+       public interface Images extends ClientBundle {\r
+               @Source("org/gss_project/gss/resources/ajax-loader.gif")\r
+               ImageResource loading();\r
+       }\r
+\r
+       /**\r
+        * The widget's constructor that creates a spinning indicator image.\r
+        */\r
+       public LoadingIndicator(Images images) {\r
+               VerticalPanel vp = new VerticalPanel();\r
+               //vp.setHorizontalAlignment(HorizontalAlignmentConstant.CENTER);\r
+               HTML inner = new HTML(AbstractImagePrototype.create(images.loading()).getHTML());\r
+               vp.add(inner);\r
+               vp.add(messageLabel = new HTML(DEFAULT_MESSAGE) );\r
+               vp.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);\r
+               vp.setCellHorizontalAlignment(messageLabel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               initWidget(vp);\r
+       }\r
+       \r
+       \r
+       /**\r
+        * Modify the message.\r
+        *\r
+        * @param message the message to set\r
+        */\r
+       public void setMessage(String message) {\r
+               messageLabel.setHTML(message);\r
+       }\r
+       \r
+       public void clearMessage(){\r
+               setMessage(DEFAULT_MESSAGE);\r
+       }\r
+       \r
+       public void show(String msg){\r
+               if(msg==null)\r
+                       setMessage(DEFAULT_MESSAGE);\r
+               else\r
+                       setMessage(msg);\r
+               this.setVisible(true);\r
+       }\r
+       \r
+       public void hide(){\r
+               setMessage(DEFAULT_MESSAGE);\r
+               this.setVisible(false);\r
+       }\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/MessagePanel.java b/src/org/gss_project/gss/web/client/MessagePanel.java
new file mode 100644 (file)
index 0000000..2916081
--- /dev/null
@@ -0,0 +1,218 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import org.gss_project.gss.web.client.animation.FadeIn;\r
+import org.gss_project.gss.web.client.animation.FadeOut;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.resources.client.ClientBundle;\r
+import com.google.gwt.resources.client.ImageResource;\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Composite;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HasVerticalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.SimplePanel;\r
+\r
+/**\r
+ * A panel that displays various system messages.\r
+ */\r
+public class MessagePanel extends Composite {\r
+       /**\r
+        * An image bundle for this widget's images.\r
+        */\r
+       public interface Images extends ClientBundle {\r
+               @Source("org/gss_project/gss/resources/messagebox_info.png")\r
+               ImageResource info();\r
+\r
+               @Source("org/gss_project/gss/resources/messagebox_warning.png")\r
+               ImageResource warn();\r
+\r
+               @Source("org/gss_project/gss/resources/messagebox_critical.png")\r
+               ImageResource error();\r
+       }\r
+\r
+       /**\r
+        * The widget's images.\r
+        */\r
+       public static Images images;\r
+\r
+       /**\r
+        * The system message to be displayed.\r
+        */\r
+       private HTML message = new HTML("&nbsp;");\r
+\r
+       /**\r
+        * A link to clear the displayed message.\r
+        */\r
+       private HTML clearMessageLink = new HTML("<a class='gss-clearMessage' href='javascript:;'>Clear</a>");\r
+\r
+       /**\r
+        * The panel that contains the messages.\r
+        */\r
+       private HorizontalPanel inner = new HorizontalPanel();\r
+\r
+       /**\r
+        * The panel that enables special effects for this widget.\r
+        */\r
+       private SimplePanel simplePanel = new SimplePanel();\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        *\r
+        * @param newImages a bundle that provides the images for this widget\r
+        */\r
+       public MessagePanel(final Images newImages) {\r
+               images = newImages;\r
+               buildPanel();\r
+               simplePanel.setStyleName("effectPanel");\r
+               inner.setStyleName("effectPanel-inner");\r
+               DOM.setStyleAttribute(simplePanel.getElement(), "zoom", "1");\r
+               simplePanel.add(inner);\r
+               initWidget(simplePanel);\r
+       }\r
+\r
+       /**\r
+        * Build the panel that contains the icon, the message and the 'clear' link.\r
+        */\r
+       private void buildPanel() {\r
+               inner.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);\r
+               inner.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);\r
+               inner.setSpacing(4);\r
+               inner.add(message);\r
+               inner.add(clearMessageLink);\r
+               inner.setCellVerticalAlignment(message, HasVerticalAlignment.ALIGN_MIDDLE);\r
+               clearMessageLink.addClickHandler(new ClickHandler() {\r
+\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               FadeOut anim = new FadeOut(simplePanel){\r
+                                       @Override\r
+                                       protected void onComplete() {\r
+                                               super.onComplete();\r
+                                               hideMessage();\r
+                                       }\r
+                               };\r
+                               anim.run(500);\r
+                       }\r
+               });\r
+       }\r
+\r
+       /**\r
+        * Display an error message.\r
+        *\r
+        * @param msg the message to display\r
+        */\r
+       public void displayError(final String msg) {\r
+               GWT.log(msg, null);\r
+               message = new HTML("<table class='gss-errorMessage'><tr><td>" + AbstractImagePrototype.create(images.error()).getHTML() + "</td><td>" + msg + "</td></tr></table>");\r
+               message.addClickHandler(new ClickHandler() {\r
+\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               FadeOut anim = new FadeOut(simplePanel){\r
+\r
+                                       @Override\r
+                                       protected void onComplete() {\r
+                                               super.onComplete();\r
+                                               hideMessage();\r
+                                       }\r
+                               };\r
+                               anim.run(500);\r
+                       }\r
+               });\r
+               buildPanel();\r
+               setVisible(true);\r
+               FadeIn anim = new FadeIn(simplePanel);\r
+               anim.run(500);\r
+       }\r
+\r
+       /**\r
+        * Display a warning message.\r
+        *\r
+        * @param msg the message to display\r
+        */\r
+       public void displayWarning(final String msg) {\r
+               message = new HTML("<table class='gss-warnMessage'><tr><td>" + AbstractImagePrototype.create(images.warn()).getHTML() + "</td><td>" + msg + "</td></tr></table>");\r
+               message.addClickHandler(new ClickHandler() {\r
+\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               FadeOut anim = new FadeOut(simplePanel){\r
+\r
+                                       @Override\r
+                                       protected void onComplete() {\r
+                                               super.onComplete();\r
+                                               hideMessage();\r
+                                       }\r
+                               };\r
+                               anim.run(500);\r
+                       }\r
+               });\r
+\r
+               buildPanel();\r
+               setVisible(true);\r
+               FadeIn anim = new FadeIn(simplePanel);\r
+               anim.run(500);\r
+       }\r
+\r
+       /**\r
+        * Display an informational message.\r
+        *\r
+        * @param msg the message to display\r
+        */\r
+       public void displayInformation(final String msg) {\r
+               message = new HTML("<table class='gss-infoMessage'><tr><td>" + AbstractImagePrototype.create(images.info()).getHTML() + "</td><td>" + msg + "</td></tr></table>");\r
+               message.addClickHandler(new ClickHandler() {\r
+\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               FadeOut anim = new FadeOut(simplePanel){\r
+\r
+                                       @Override\r
+                                       protected void onComplete() {\r
+                                               super.onComplete();\r
+                                               hideMessage();\r
+                                       }\r
+                               };\r
+                               anim.run(500);\r
+                       }\r
+               });\r
+\r
+               buildPanel();\r
+               setVisible(true);\r
+               FadeIn anim = new FadeIn(simplePanel);\r
+               anim.run(500);\r
+       }\r
+\r
+       /**\r
+        * Clear the displayed message and hide the panel.\r
+        */\r
+       public void hideMessage() {\r
+               inner.clear();\r
+               message = new HTML("&nbsp;");\r
+               this.setVisible(false);\r
+       }\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/ObjectNotFoundException.java b/src/org/gss_project/gss/web/client/ObjectNotFoundException.java
new file mode 100644 (file)
index 0000000..de1cd56
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import java.io.Serializable;
+
+/**
+ * An exception thrown when a requested object was not found.
+ *
+ * @author past
+ */
+public class ObjectNotFoundException extends Exception implements Serializable {
+
+       /**
+        * The serial version UID.
+        */
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * The stored message that provides details about the problem.
+        */
+       private String message;
+
+       /**
+        * Default constructor
+        */
+       public ObjectNotFoundException() {
+               super();
+       }
+
+       /**
+        * Constructor from error message.
+        *
+        * @param newMessage The error message
+        */
+       public ObjectNotFoundException(final String newMessage) {
+               super(newMessage);
+               message = newMessage;
+       }
+
+       /**
+        * Constructor from Throwable.
+        *
+        * @param cause The throwable that caused the exception
+        */
+       public ObjectNotFoundException(final Throwable cause) {
+               super(cause);
+       }
+
+       /**
+        * Constructor from error message and Throwable.
+        *
+        * @param newMessage The error message
+        * @param cause The throwable that caused the exception
+        */
+       public ObjectNotFoundException(final String newMessage, final Throwable cause) {
+               super(newMessage, cause);
+               message = newMessage;
+       }
+
+       @Override
+       public String getMessage() {
+               return message;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/PermissionsAddDialog.java b/src/org/gss_project/gss/web/client/PermissionsAddDialog.java
new file mode 100644 (file)
index 0000000..79e4e4c
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.PermissionHolder;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
+import com.google.gwt.user.client.ui.SuggestBox;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * @author kman
+ */
+public class PermissionsAddDialog extends DialogBox {
+
+       private MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
+       private SuggestBox suggestBox = new SuggestBox(oracle);
+
+       private String selectedUser = null;
+
+       private List<GroupResource> groups;
+
+       private ListBox groupBox = new ListBox();
+
+       private CheckBox read = new CheckBox();
+
+       private CheckBox write = new CheckBox();
+
+       private CheckBox modifyACL = new CheckBox();
+
+       private final PermissionsList permList;
+
+       boolean userAdd;
+
+       public PermissionsAddDialog(List<GroupResource> _groups, PermissionsList _permList, boolean _userAdd) {
+               groups = _groups;
+               userAdd = _userAdd;
+               permList = _permList;
+               
+               groupBox.getElement().setId("addPermission.dropDown");
+               
+               suggestBox.getElement().setId("addPermission.textBox");
+               
+               read.getElement().setId("addPermission.read");
+               
+               write.getElement().setId("addPermission.write");
+               
+               modifyACL.getElement().setId("addpermission.modify");
+               
+               for (GroupResource group : _groups)
+                       groupBox.addItem(group.getName(), group.getName());
+               final VerticalPanel panel = new VerticalPanel();
+               final HorizontalPanel buttons = new HorizontalPanel();
+               setWidget(panel);
+               final FlexTable permTable = new FlexTable();
+               permTable.setText(0, 0, "Users/Groups");
+               permTable.setText(0, 1, "Read");
+               permTable.setText(0, 2, "Write");
+               permTable.setText(0, 3, "Modify Access");
+               permTable.getFlexCellFormatter().setStyleName(0, 0, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 1, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 2, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 3, "props-toplabels");
+               if (userAdd) {
+                       suggestBox.getTextBox().addFocusHandler(new FocusHandler() {
+
+                               @Override
+                               public void onFocus(FocusEvent event) {
+                                       if (selectedUser != null && selectedUser.endsWith("@"))
+                                               updateSuggestions();
+
+                               }
+                       });
+
+                       suggestBox.addKeyUpHandler(new KeyUpHandler() {
+
+                               @Override
+                               public void onKeyUp(KeyUpEvent event) {
+                                       // Ignore the arrow keys.
+                                       int keyCode = event.getNativeKeyCode();
+                                       if (keyCode == KeyCodes.KEY_UP ||
+                                                       keyCode == KeyCodes.KEY_DOWN ||
+                                                       keyCode == KeyCodes.KEY_LEFT ||
+                                                       keyCode == KeyCodes.KEY_RIGHT)
+                                               return;
+                                       if (keyCode==KeyCodes.KEY_ESCAPE) {
+                                               suggestBox.hideSuggestionList();
+                                               return;
+                                       }
+                                       String text = suggestBox.getText().trim();
+                                       // Avoid useless queries for keystrokes that do not modify
+                                       // the text.
+                                       if (text.equals(selectedUser))
+                                               return;
+                                       selectedUser = text;
+                                       // Go to the server only if the user typed the @ character.
+                                       if (selectedUser.endsWith("@"))
+                                               updateSuggestions();
+                               }
+                       });
+                       permTable.setWidget(1, 0, suggestBox);
+               } else
+                       permTable.setWidget(1, 0, groupBox);
+               permTable.setWidget(1, 1, read);
+               permTable.setWidget(1, 2, write);
+               permTable.setWidget(1, 3, modifyACL);
+
+               permTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");
+               permTable.getFlexCellFormatter().setHorizontalAlignment(1, 1, HasHorizontalAlignment.ALIGN_CENTER);
+               permTable.getFlexCellFormatter().setHorizontalAlignment(1, 2, HasHorizontalAlignment.ALIGN_CENTER);
+               permTable.getFlexCellFormatter().setHorizontalAlignment(1, 3, HasHorizontalAlignment.ALIGN_CENTER);
+               panel.add(permTable);
+
+               final Button ok = new Button("OK", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               addPermission();
+                               hide();
+                       }
+               });
+               ok.getElement().setId("addPermission.button.ok");
+               buttons.add(ok);
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);
+               // Create the 'Cancel' button, along with a listener that hides the
+               // dialog
+               // when the button is clicked.
+               final Button cancel = new Button("Cancel", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               hide();
+                       }
+               });
+               cancel.getElement().setId("addPermission.button.cancel");
+               buttons.add(cancel);
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+               buttons.setSpacing(8);
+               buttons.addStyleName("gss-TabPanelBottom");
+               panel.add(buttons);
+               panel.addStyleName("gss-TabPanelBottom");
+       }
+
+       private void addPermission() {
+               PermissionHolder perm = new PermissionHolder();
+               if (userAdd) {
+                       selectedUser = suggestBox.getText();
+                       for(PermissionHolder p : permList.permissions)
+                               if (selectedUser.equals(p.getUser())){
+                                       GSS.get().displayError("User already has access to the resource");
+                                       return;
+                               }
+                       perm.setUser(selectedUser);
+               } else {
+                       String groupId = groupBox.getValue(groupBox.getSelectedIndex());
+                       GroupResource selected = null;
+                       for (GroupResource g : groups)
+                               if (g.getName().equals(groupId))
+                                       selected = g;
+                       if (selected == null)
+                               return;
+                       for(PermissionHolder p : permList.permissions)
+                               if (selected.getName().equals(p.getGroup())){
+                                       GSS.get().displayError("Group already has access to the resource");
+                                       return;
+                               }
+                       perm.setGroup(selected.getName());
+               }
+               boolean readValue = read.getValue();
+               boolean writeValue = write.getValue();
+               boolean modifyValue = modifyACL.getValue();
+
+               perm.setRead(readValue);
+               perm.setWrite(writeValue);
+               perm.setModifyACL(modifyValue);
+               permList.addPermission(perm);
+               permList.updateTable();
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+                       // Use the popup's key preview hooks to close the dialog when either
+                       // enter or escape is pressed.
+                       switch (evt.getKeyCode()) {
+                               case KeyCodes.KEY_ENTER:
+                                       addPermission();
+                                       hide();
+                                       break;
+                               case KeyCodes.KEY_ESCAPE:
+                                       hide();
+                                       break;
+                       }
+       }
+
+
+       @Override
+       public void center() {
+               super.center();
+               if (userAdd)
+                       suggestBox.setFocus(true);
+       }
+
+       /**
+        * Update the list of suggestions.
+        */
+       protected void updateSuggestions() {
+               final GSS app = GSS.get();
+               String query = selectedUser.substring(0, selectedUser.length()-1);
+               GWT.log("Searching for " + query, null);
+
+               GetCommand<UserSearchResource> eg = new GetCommand<UserSearchResource>(UserSearchResource.class,
+                                       app.getApiPath() + "users/" + URL.encodeComponent(query), false, null) {
+
+                       @Override
+                       public void onComplete() {
+                               suggestBox.hideSuggestionList();
+                               oracle.clear();
+                               UserSearchResource s = getResult();
+                               for (UserResource user : s.getUsers()) {
+                                       GWT.log("Found " + user.getUsername(), null);
+                                       oracle.add(user.getUsername());
+                               }
+                               suggestBox.showSuggestionList();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               if(t instanceof RestException)
+                                       app.displayError("Unable to perform search: "+((RestException)t).getHttpStatusText());
+                               else
+                                       app.displayError("System error while searching for users: "+t.getMessage());
+                               GWT.log("", t);
+                               DisplayHelper.log(t.getMessage());
+                       }
+
+               };
+               DeferredCommand.addCommand(eg);
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/PermissionsList.java b/src/org/gss_project/gss/web/client/PermissionsList.java
new file mode 100644 (file)
index 0000000..bdcda31
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.FilePropertiesDialog.Images;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.resource.PermissionHolder;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.PushButton;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class PermissionsList extends Composite {
+
+       int selectedRow = -1;
+       
+       int permissionCount = -1;
+       
+       Set<PermissionHolder> permissions = null;
+       
+       final Images images;
+       
+       final VerticalPanel permPanel = new VerticalPanel();
+       
+       final FlexTable permTable = new FlexTable();
+       
+       final String owner;
+       
+       PermissionHolder toRemove = null;
+       
+       private boolean hasChanges = false;
+       
+       private boolean hasAddition = false;
+       
+       public PermissionsList(final Images theImages, Set<PermissionHolder> thePermissions, String anOwner){
+               images = theImages;
+               owner = anOwner;
+               permissions =  new HashSet<PermissionHolder>();
+               permissions.addAll(thePermissions);
+               permTable.setText(0, 0, "Users/Groups");
+               permTable.setText(0, 1, "Read");
+               permTable.setText(0, 2, "Write");
+               permTable.setText(0, 3, "Modify Access");
+               permTable.setText(0, 4, "");
+               permTable.getFlexCellFormatter().setStyleName(0, 0, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 1, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 2, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 3, "props-toplabels");
+               permPanel.add(permTable);
+               permPanel.addStyleName("gss-TabPanelBottom");
+               initWidget(permPanel);
+               updateTable();
+       }
+
+       public boolean hasChanges(){
+               return hasChanges || hasAddition;
+       }
+
+
+       public void updateTable(){
+               copySetAndContinue(permissions);
+       }
+
+       public void updatePermissionsAccordingToInput(){
+               int i=1;
+               for(PermissionHolder dto : permissions){
+                       /*if(dto.getId() == null)
+                               hasChanges =true;*/
+                       CheckBox r = (CheckBox) permTable.getWidget(i, 1);
+                       CheckBox w = (CheckBox) permTable.getWidget(i, 2);
+                       CheckBox m = (CheckBox) permTable.getWidget(i, 3);
+                       
+                       r.getElement().setId("permissionList.read");
+                       w.getElement().setId("permissionList.write");
+                       m.getElement().setId("permissionList.modify");
+                       
+                       if(dto.isRead() != r.getValue() || dto.isWrite() != w.getValue() || dto.isModifyACL() != m.getValue())
+                               hasChanges = true;
+                       dto.setRead(r.getValue());
+                       dto.setWrite(w.getValue());
+                       dto.setModifyACL(m.getValue());
+                       i++;
+               }               
+       }
+
+       /**
+        * Retrieve the permissions.
+        *
+        * @return the permissions
+        */
+       public Set<PermissionHolder> getPermissions() {
+               return permissions;
+       }
+
+       public void addPermission(PermissionHolder permission){
+               permissions.add(permission);
+               hasAddition = true;
+       }
+       /**
+        * Copies the input Set to a new Set
+        * @param input
+        */
+       private void copySetAndContinue(Set<PermissionHolder> input){
+               Set<PermissionHolder> copiedInput = new HashSet<PermissionHolder>();            
+               for(PermissionHolder dto : input) {
+                       copiedInput.add(dto);
+               }
+               handleFullNames(copiedInput);
+       }
+       
+       /**
+        * Examines whether or not the user's full name exists in the 
+        * userFullNameMap in the GSS.java for every element of the input list.
+        * If the user's full name does not exist in the map then a request is being made
+        * for the specific username.  
+        * 
+        * @param filesInput
+        */
+       private void handleFullNames(Set<PermissionHolder> aPermissions){               
+               if(aPermissions.isEmpty()){
+                       showPermissionTable();
+                       return;
+               }
+               
+               final PermissionHolder dto = aPermissions.iterator().next();
+               if(dto.getGroup() != null){
+                       if(aPermissions.size() >= 1){
+                               aPermissions.remove(dto);                               
+                               handleFullNames(aPermissions);                          
+                       }
+               }else if(GSS.get().findUserFullName(dto.getUser()) != null){
+                       if(aPermissions.size() >= 1){
+                               aPermissions.remove(dto);                               
+                               handleFullNames(aPermissions);                          
+                       }
+               }else{
+                       findFullNameAndUpdate(aPermissions);
+               }
+       }
+       
+       /**
+        * Shows the permission table 
+        * 
+        * @param aPermissions
+        */
+       private void showPermissionTable(){
+               int i = 1;
+               if(toRemove != null){
+                       permissions.remove(toRemove);
+                       toRemove = null;
+               }
+               for(final PermissionHolder dto : permissions){
+                       PushButton removeButton = new PushButton(AbstractImagePrototype.create(images.delete()).createImage(), new ClickHandler() {
+                               @Override
+                               public void onClick(ClickEvent event) {
+                                       toRemove = dto;
+                                       updateTable();
+                                       hasChanges = true;
+                               }
+                       });
+                                               
+                       if(dto.getUser() != null){
+                               if(dto.getUser() != null && dto.getUser().equals(owner)){
+                                       permTable.setHTML(i, 0, "<span id=permissionList.Owner>" + AbstractImagePrototype.create(images.permUser()).getHTML() + "&nbsp;Owner</span>");
+                                       removeButton.setVisible(false);
+                               }else{
+                                       permTable.setHTML(i, 0, "<span id=permissionList."+GSS.get().findUserFullName(dto.getUser())+">"+ AbstractImagePrototype.create(images.permUser()).getHTML() + "&nbsp;"+ GSS.get().findUserFullName(dto.getUser()) + "</span>");
+                               }
+                       }else if(dto.getGroup() != null){
+                               permTable.setHTML(i, 0, "<span id=permissionList."+dto.getGroup()+">" + AbstractImagePrototype.create(images.permGroup()).getHTML() + "&nbsp;"+ dto.getGroup() + "</span>");
+                       }
+                       
+                       CheckBox read = new CheckBox();
+                       read.setValue(dto.isRead());
+                       read.getElement().setId("permissionList.read");
+                       
+                       CheckBox write = new CheckBox();
+                       write.setValue(dto.isWrite());
+                       write.getElement().setId("permissionList.write");
+                       
+                       CheckBox modify = new CheckBox();
+                       modify.setValue(dto.isModifyACL());
+                       modify.getElement().setId("permissionList.modify");
+                       
+                       if (dto.getUser()!=null && dto.getUser().equals(owner)) {
+                               read.setEnabled(false);
+                               write.setEnabled(false);
+                               modify.setEnabled(false);
+                       }
+                       
+                       permTable.setWidget(i, 1, read);
+                       permTable.setWidget(i, 2, write);
+                       permTable.setWidget(i, 3, modify);
+                       permTable.setWidget(i, 4, removeButton);
+                       permTable.getFlexCellFormatter().setStyleName(i, 0, "props-labels");
+                       permTable.getFlexCellFormatter().setHorizontalAlignment(i, 1, HasHorizontalAlignment.ALIGN_CENTER);
+                       permTable.getFlexCellFormatter().setHorizontalAlignment(i, 2, HasHorizontalAlignment.ALIGN_CENTER);
+                       permTable.getFlexCellFormatter().setHorizontalAlignment(i, 3, HasHorizontalAlignment.ALIGN_CENTER);
+                       i++;            
+               }
+               for(; i<permTable.getRowCount(); i++)
+                       permTable.removeRow(i);
+               hasChanges = false;
+       }
+       
+       /**
+        * Makes a request to search for full name from a given username
+        * and continues checking the next element of the Set.
+        *  
+        * @param filesInput
+        */
+
+       private void findFullNameAndUpdate(final Set<PermissionHolder> aPermissions){                           
+               final PermissionHolder dto = aPermissions.iterator().next();
+               String path = GSS.get().getApiPath() + "users/" + dto.getUser(); 
+
+               GetCommand<UserSearchResource> gg = new GetCommand<UserSearchResource>(UserSearchResource.class, path, false,null) {
+                       @Override
+                       public void onComplete() {
+                               final UserSearchResource result = getResult();
+                               for (UserResource user : result.getUsers()){
+                                       String username = user.getUsername();
+                                       String userFullName = user.getName();
+                                       GSS.get().putUserToMap(username, userFullName);
+                                       if(aPermissions.size() >= 1){
+                                               aPermissions.remove(dto);                                               
+                                               if(aPermissions.isEmpty()){
+                                                       showPermissionTable();
+                                                       return;
+                                               }
+                                               handleFullNames(aPermissions);                                                                          
+                                       }                                                                       
+                               }
+                       }
+                       @Override
+                       public void onError(Throwable t) {                              
+                               GSS.get().displayError("Unable to fetch user's full name from the given username " + dto.getUser());
+                               if(aPermissions.size() >= 1){
+                                       aPermissions.remove(dto);
+                                       if(aPermissions.isEmpty()){
+                                               showPermissionTable();
+                                               return;
+                                       }
+                                       handleFullNames(aPermissions);
+                               }
+                       }
+               };
+               DeferredCommand.addCommand(gg);
+       
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/ProgressBar.java b/src/org/gss_project/gss/web/client/ProgressBar.java
new file mode 100644 (file)
index 0000000..a56e610
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2006 Robert Hanson <iamroberthanson AT gmail.com>
+ *
+ * Licensed 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.gss_project.gss.web.client;
+
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * <P>
+ * A simple progress bar that uses table elements to show progress and with a
+ * basic time remaining calculation built in.
+ * <P>
+ * You can optionally display some text above the progress bar and/or display
+ * time remaining underneath the progress bar. To control the display of those
+ * features, set the options in the constructor as shown in the following usage
+ * example:
+ *
+ * <PRE>
+ * final ProgressBar progressBar = new ProgressBar(20, ProgressBar.SHOW_TIME_REMAINING + ProgressBar.SHOW_TEXT);
+ * progressBar.setText(&quot;Doing something...&quot;);
+ * RootPanel.get().add(progressBar);
+ * Timer t = new Timer() {
+ *
+ *     public void run() {
+ *             int progress = progressBar.getProgress() + 4;
+ *             if (progress &gt; 100)
+ *                     cancel();
+ *             progressBar.setProgress(progress);
+ *     }
+ * };
+ * t.scheduleRepeating(1000);
+ * </PRE>
+ * <P>
+ * How the time remaining is displayed can be controlled by setting the relevant
+ * messages using the language of your choice.
+ * <P>
+ * The default setting for the messages are as follows:
+ *
+ * <PRE>
+ * setSecondsMessage(&quot;Time remaining: {0} Seconds&quot;);
+ * setMinutesMessage(&quot;Time remaining: {0} Minutes&quot;);
+ * setHoursMessage(&quot;Time remaining: {0} Hours&quot;);
+ * </PRE>
+ * <P>
+ * To reset the time remaining/set the start time, simply set the progress to
+ * zero.
+ * <P>
+ * Some basic CSS styling is available to control the text, border around the
+ * progress bar itself and the colour of the progress bar elements.
+ *
+ * <PRE>
+ * .progressbar-text {
+ *     font-weight: bold;
+ * }
+ * .progressbar-remaining {
+ *     font-size: 12px;
+ *     font-style: italic;
+ * }
+ * .progressbar-outer {
+ *     border: 1px solid black;
+ * }
+ * .progressbar-inner {
+ *     border: 1px solid black;
+ *     margin: 1px;
+ * }
+ * .progressbar-bar {
+ *     width: 5px;
+ *     height: 15px;
+ *     margin: 1px;
+ * }
+ * .progressbar-fullbar {
+ *     background: blue;
+ * }
+ * .progressbar-blankbar {
+ *     background: #eee;
+ * }
+ *</PRE>
+ * <P>
+ * You can take advantage of the default style by adding the following to the
+ * head of your HTML page.
+ * <P>
+ * &lt;link rel="stylesheet" type="text/css" href="style/gwl-progressBar.css">
+ * <P>
+ * This style sheet also has two additional styles which you can use by adding
+ * the stye name to the widget. You can use either one of these, or use both
+ * combined.
+ *
+ * <PRE>
+ * ProgressBar progressBar = new ProgressBar(20);
+ * progressBar.addStyleName(&quot;progressbar-solid&quot;);
+ * progressBar.addStyleName(&quot;progressbar-noborder&quot;);
+ * </PRE>
+ *
+ * @author Bjarne Matzen - Bjarne[dot]Matzen[at]gmail[dot]com
+ */
+
+public class ProgressBar extends VerticalPanel {
+
+       /**
+        * Option to show text label above progress bar
+        */
+       public static final int SHOW_TEXT = 2;
+
+       /**
+        * Option to show time remaining
+        */
+       public static final int SHOW_TIME_REMAINING = 1;
+
+       /**
+        * The time the progress bar was started
+        */
+       private long startTime = System.currentTimeMillis();
+
+       /**
+        * The number of bar elements to show
+        */
+       private int elements = 20;
+
+       /**
+        * Time element text
+        */
+       private String secondsMessage = "Estimated time remaining: {0} Seconds";
+
+       private String minutesMessage = "Estimated time remaining: {0} Minutes";
+
+       private String hoursMessage = "Estimated time remaining: {0} Hours";
+
+       /**
+        * Current progress (as a percentage)
+        */
+       private int progress = 0;
+
+       /**
+        * This is the frame around the progress bar
+        */
+       private FlexTable barFrame = new FlexTable();
+
+       /**
+        * This is the grid used to show the elements
+        */
+       private Grid elementGrid;
+
+       /**
+        * This is the current text label below the progress bar
+        */
+       private Label remainLabel = new Label();
+
+       /**
+        * This is the current text label above the progress bar
+        */
+       private Label textLabel = new Label();
+
+       /**
+        * internal flags for options
+        */
+       private boolean showRemaining = false;
+
+       private boolean showText = false;
+
+       /**
+        * Base constructor for this widget
+        *
+        * @param elementNo The number of elements (bars) to show on the progress bar
+        * @param options The display options for the progress bar
+        */
+       public ProgressBar(int elementNo, int options) {
+               // Read the options and set convenience variables
+               if ((options & SHOW_TIME_REMAINING) == SHOW_TIME_REMAINING)
+                       showRemaining = true;
+               if ((options & SHOW_TEXT) == SHOW_TEXT)
+                       showText = true;
+
+               // Set element count
+               elements = elementNo;
+
+               // Styling
+               remainLabel.setStyleName("progressbar-remaining");
+               textLabel.setStyleName("progressbar-text");
+
+               // Initialize the progress elements
+               elementGrid = new Grid(1, elementNo);
+               elementGrid.setStyleName("progressbar-inner");
+               elementGrid.setCellPadding(0);
+               elementGrid.setCellSpacing(0);
+
+               for (int loop = 0; loop < elementNo; loop++) {
+                       Grid elm = new Grid(1, 1);
+                       // elm.setHTML(0, 0, "&nbsp;");
+                       elm.setHTML(0, 0, "");
+                       elm.setStyleName("progressbar-blankbar");
+                       elm.addStyleName("progressbar-bar");
+                       elementGrid.setWidget(0, loop, elm);
+               }
+
+               // Create the container around the elements
+               Grid containerGrid = new Grid(1, 1);
+               containerGrid.setCellPadding(0);
+               containerGrid.setCellSpacing(0);
+               containerGrid.setWidget(0, 0, elementGrid);
+               containerGrid.setStyleName("progressbar-outer");
+               // containerGrid.setBorderWidth(1);
+
+               // Set up the surrounding flex table based on the options
+               int row = 0;
+               if (showText)
+                       barFrame.setWidget(row++, 0, textLabel);
+               barFrame.setWidget(row++, 0, containerGrid);
+               if (showRemaining)
+                       barFrame.setWidget(row++, 0, remainLabel);
+
+               barFrame.setWidth("100%");
+
+               // Add the frame to the panel
+               this.add(barFrame);
+
+               // Initialize progress bar
+               setProgress(0);
+       }
+
+       /**
+        * Constructor without options
+        *
+        * @param elementNo The number of elements (bars) to show on the progress bar
+        */
+       public ProgressBar(int elementNo) {
+               this(elementNo, 0);
+       }
+
+       /**
+        * Set the current progress as a percentage
+        *
+        * @param percentage Set current percentage for the progress bar
+        */
+       public void setProgress(int percentage) {
+               // Make sure we are error-tolerant
+               if (percentage > 100)
+                       percentage = 100;
+               if (percentage < 0)
+                       percentage = 0;
+
+               // Set the internal variable
+               progress = percentage;
+
+               // Update the elements in the progress grid to
+               // reflect the status
+               int completed = elements * percentage / 100;
+               for (int loop = 0; loop < elements; loop++) {
+                       Grid elm = (Grid) elementGrid.getWidget(0, loop);
+                       if (loop < completed) {
+                               elm.setStyleName("progressbar-fullbar");
+                               elm.addStyleName("progressbar-bar");
+                       } else {
+                               elm.setStyleName("progressbar-blankbar");
+                               elm.addStyleName("progressbar-bar");
+                       }
+               }
+
+               if (percentage > 0) {
+                       // Calculate the new time remaining
+                       long soFar = (System.currentTimeMillis() - startTime) / 1000;
+                       long remaining = soFar * (100 - percentage) / percentage;
+                       // Select the best UOM
+                       String remainText = secondsMessage;
+                       if (remaining > 120) {
+                               remaining = remaining / 60;
+                               remainText = minutesMessage;
+                               if (remaining > 120) {
+                                       remaining = remaining / 60;
+                                       remainText = hoursMessage;
+                               }
+                       }
+                       // Locate the position to insert out time remaining
+                       int pos = remainText.indexOf("{0}");
+                       if (pos >= 0) {
+                               String trail = "";
+                               if (pos + 3 < remainText.length())
+                                       trail = remainText.substring(pos + 3);
+                               remainText = remainText.substring(0, pos) + remaining + trail;
+                       }
+                       // Set the label
+                       remainLabel.setText(remainText);
+               } else
+                       // If progress is 0, reset the start time
+                       startTime = System.currentTimeMillis();
+       }
+
+       /**
+        * Get the current progress as a percentage
+        *
+        * @return Current percentage for the progress bar
+        */
+       public int getProgress() {
+               return progress;
+       }
+
+       /**
+        * Get the text displayed above the progress bar
+        *
+        * @return the text
+        */
+       public String getText() {
+               return textLabel.getText();
+       }
+
+       /**
+        * Set the text displayed above the progress bar
+        *
+        * @param text the text to set
+        */
+       public void setText(String text) {
+               textLabel.setText(text);
+       }
+
+       /**
+        * Get the message used to format the time remaining text for hours
+        *
+        * @return the hours message
+        */
+       public String getHoursMessage() {
+               return hoursMessage;
+       }
+
+       /**
+        * Set the message used to format the time remaining text below the progress
+        * bar. There are 3 messages used for hours, minutes and seconds
+        * respectively. The message must contain a placeholder for the value. The
+        * placeholder must be {0}. For example, the following is a valid message:
+        * "Hours remaining: {0}"
+        *
+        * @param anHoursMessage the hours message to set
+        */
+       public void setHoursMessage(String anHoursMessage) {
+               hoursMessage = anHoursMessage;
+       }
+
+       /**
+        * Get the message used to format the time remaining text for minutes
+        *
+        * @return the minutesMessage
+        */
+       public String getMinutesMessage() {
+               return minutesMessage;
+       }
+
+       /**
+        * Set the message used to format the time remaining text below the progress
+        * bar. There are 3 messages used for hours, minutes and seconds
+        * respectively. The message must contain a placeholder for the value. The
+        * placeholder must be {0}. For example, the following is a valid message:
+        * "Minutes remaining: {0}"
+        *
+        * @param aMinutesMessage the minutes message to set
+        */
+       public void setMinutesMessage(String aMinutesMessage) {
+               minutesMessage = aMinutesMessage;
+       }
+
+       /**
+        * Get the message used to format the time remaining text for seconds
+        *
+        * @return the secondsMessage
+        */
+       public String getSecondsMessage() {
+               return secondsMessage;
+       }
+
+       /**
+        * Set the message used to format the time remaining text below the progress
+        * bar. There are 3 messages used for hours, minutes and seconds
+        * respectively. The message must contain a placeholder for the value. The
+        * placeholder must be {0}. For example, the following is a valid message:
+        * "Seconds remaining: {0}"
+        *
+        * @param aSecondsMessage the secondsMessage to set
+        */
+       public void setSecondsMessage(String aSecondsMessage) {
+               secondsMessage = aSecondsMessage;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/QuitDialog.java b/src/org/gss_project/gss/web/client/QuitDialog.java
new file mode 100644 (file)
index 0000000..080f597
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.dom.client.NativeEvent;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.user.client.Event.NativePreviewEvent;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.DialogBox;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.VerticalPanel;\r
+\r
+/**\r
+ * The 'quit' dialog box.\r
+ */\r
+public class QuitDialog extends DialogBox {\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        */\r
+       public QuitDialog() {\r
+               Configuration conf = (Configuration) GWT.create(Configuration.class);\r
+               String service = conf.serviceName();\r
+               setText("Quit " + service);\r
+\r
+               VerticalPanel outer = new VerticalPanel();\r
+               HorizontalPanel buttons = new HorizontalPanel();\r
+\r
+               HTML text = new HTML("Are you sure you want to quit " + service + "?");\r
+               text.setStyleName("gss-AboutText");\r
+               outer.add(text);\r
+\r
+               // Create the 'Quit' button, along with a listener that hides the dialog\r
+               // when the button is clicked and quits the application.\r
+               Button quit = new Button("Quit", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               hide();\r
+                               GSS.get().logout();\r
+                       }\r
+               });\r
+               buttons.add(quit);\r
+               buttons.setCellHorizontalAlignment(quit, HasHorizontalAlignment.ALIGN_CENTER);\r
+               // Create the 'Cancel' button, along with a listener that hides the\r
+               // dialog when the button is clicked.\r
+               Button cancel = new Button("Cancel", new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               hide();\r
+                       }\r
+               });\r
+               buttons.add(cancel);\r
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
+               buttons.setSpacing(8);\r
+               outer.add(buttons);\r
+               outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
+               setWidget(outer);\r
+       }\r
+\r
+       @Override\r
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
+               super.onPreviewNativeEvent(preview);\r
+\r
+               NativeEvent evt = preview.getNativeEvent();\r
+               if (evt.getType().equals("keydown"))\r
+                       // Use the popup's key preview hooks to close the dialog when either\r
+                       // enter or escape is pressed.\r
+                       switch (evt.getKeyCode()) {\r
+                               case KeyCodes.KEY_ENTER:\r
+                                       hide();\r
+                                       GSS.get().logout();\r
+                                       break;\r
+                               case KeyCodes.KEY_ESCAPE:\r
+                                       hide();\r
+                                       break;\r
+                       }\r
+       }\r
+\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/Search.java b/src/org/gss_project/gss/web/client/Search.java
new file mode 100644 (file)
index 0000000..b12e766
--- /dev/null
@@ -0,0 +1,143 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import com.google.gwt.event.dom.client.BlurEvent;\r
+import com.google.gwt.event.dom.client.BlurHandler;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.event.dom.client.FocusEvent;\r
+import com.google.gwt.event.dom.client.FocusHandler;\r
+import com.google.gwt.event.dom.client.KeyPressEvent;\r
+import com.google.gwt.event.dom.client.KeyPressHandler;\r
+import com.google.gwt.resources.client.ClientBundle;\r
+import com.google.gwt.resources.client.ImageResource;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.Button;\r
+import com.google.gwt.user.client.ui.Composite;\r
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
+import com.google.gwt.user.client.ui.HasVerticalAlignment;\r
+import com.google.gwt.user.client.ui.HorizontalPanel;\r
+import com.google.gwt.user.client.ui.TextBox;\r
+import com.google.gwt.user.client.ui.Widget;\r
+\r
+/**\r
+ * A component that contains the search form.\r
+ */\r
+public class Search extends Composite implements FocusHandler,BlurHandler {\r
+\r
+       /**\r
+        * The text hint that is displayed in the empty search box.\r
+        */\r
+       private static final String TEXT_HINT = "Search for files...";\r
+\r
+       /**\r
+        * Specifies the images that will be bundled for this Composite.\r
+        */\r
+       public interface Images extends ClientBundle {\r
+               @Source("org/gss_project/gss/resources/search_16.png")\r
+               ImageResource searchButton();\r
+       }\r
+\r
+       /**\r
+        * The embedded text box widget that contains the search query.\r
+        */\r
+       private TextBox tb = new TextBox();\r
+\r
+       /**\r
+        * The search widget constructor.\r
+        *\r
+        * @param images the image bundle\r
+        */\r
+       public Search(final Images images) {\r
+               tb.setWidth("200px");\r
+               tb.setText(TEXT_HINT);\r
+               tb.setStylePrimaryName("gss-search");\r
+               tb.addStyleDependentName("empty");\r
+               tb.addFocusHandler(this);\r
+               tb.addBlurHandler(this);\r
+               tb.getElement().setId("textBox.search");\r
+               tb.addKeyPressHandler(new KeyPressHandler() {\r
+\r
+                       @Override\r
+                       public void onKeyPress(KeyPressEvent event) {\r
+                               char keyCode = event.getCharCode();\r
+                               if (keyCode == '\r')\r
+                                       GSS.get().showSearchResults(tb.getText());\r
+                               else if (keyCode == 27) {\r
+                                       // Simulate the proper behavior for the escape key\r
+                                       // (27 == ESC).\r
+                                       onLostFocus((Widget)event.getSource());\r
+                                       tb.setFocus(false);\r
+                               }\r
+                       }\r
+               });\r
+\r
+               Button b = new Button(createHeaderHTML(images.searchButton(), "Search"), new ClickHandler() {\r
+                       @Override\r
+                       public void onClick(ClickEvent event) {\r
+                               GSS.get().showSearchResults(tb.getText());\r
+                       }\r
+               });\r
+               b.getElement().setId("button.search");\r
+               \r
+               HorizontalPanel panel = new HorizontalPanel();\r
+               panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);\r
+               panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);\r
+               panel.add(tb);\r
+               panel.add(b);\r
+               initWidget(panel);\r
+       }\r
+\r
+       /**\r
+        * Creates an HTML fragment that places an image & caption together.\r
+        *\r
+        * @param imageProto an image prototype for an image\r
+        * @param caption the caption\r
+        * @return the HTML fragment\r
+        */\r
+       private String createHeaderHTML(ImageResource imageProto, String caption) {\r
+               String captionHTML = "<table cellpadding='0' cellspacing='0'>" + "<tr><td>" +\r
+               AbstractImagePrototype.create(imageProto).getHTML() + "</td><td style='font-size: 90%;'>&nbsp;" +\r
+                       caption + "</td></tr></table>";\r
+               return captionHTML;\r
+       }\r
+\r
+       public void onLostFocus(Widget sender) {\r
+               TextBox b = (TextBox) sender;\r
+               if (b.getText().equals("")) {\r
+                       b.addStyleDependentName("empty");\r
+                       b.setText(TEXT_HINT);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void onFocus(FocusEvent event) {\r
+               TextBox b = (TextBox) event.getSource();\r
+               if (b.getText().equals(TEXT_HINT))\r
+                       b.setText("");\r
+               b.removeStyleDependentName("empty");\r
+       }\r
+\r
+       @Override\r
+       public void onBlur(BlurEvent event) {\r
+               TextBox b = (TextBox) event.getSource();\r
+               onLostFocus(b);\r
+       }\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/SearchResults.java b/src/org/gss_project/gss/web/client/SearchResults.java
new file mode 100644 (file)
index 0000000..84ec110
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+
+import static com.google.gwt.query.client.GQuery.$;
+
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.RestCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.SearchResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+import gwtquery.plugins.draggable.client.DraggableOptions;
+import gwtquery.plugins.draggable.client.StopDragException;
+import gwtquery.plugins.draggable.client.DraggableOptions.DragFunction;
+import gwtquery.plugins.draggable.client.DraggableOptions.RevertOption;
+import gwtquery.plugins.draggable.client.events.DragContext;
+import gwtquery.plugins.draggable.client.events.DragStartEvent;
+import gwtquery.plugins.draggable.client.events.DragStopEvent;
+import gwtquery.plugins.draggable.client.events.DragStartEvent.DragStartEventHandler;
+import gwtquery.plugins.draggable.client.events.DragStopEvent.DragStopEventHandler;
+import gwtquery.plugins.droppable.client.gwt.DragAndDropCellTable;
+import gwtquery.plugins.droppable.client.gwt.DragAndDropColumn;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.ImageResourceCell;
+import com.google.gwt.cell.client.SafeHtmlCell;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.RepeatingCommand;
+import com.google.gwt.dom.client.Style.Cursor;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.cellview.client.CellTable;
+import com.google.gwt.user.cellview.client.GssSimplePager;
+import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.view.client.AsyncDataProvider;
+import com.google.gwt.view.client.HasData;
+import com.google.gwt.view.client.MultiSelectionModel;
+import com.google.gwt.view.client.ProvidesKey;
+import com.google.gwt.view.client.SelectionChangeEvent;
+import com.google.gwt.view.client.SelectionChangeEvent.Handler;
+
+/**
+ * A composite that displays a list of search results for a particular query on
+ * files.
+ */
+public class SearchResults extends Composite{
+       private HTML searchResults = new HTML("Results for search:");
+       private String lastQuery;
+       SearchDataProvider provider = new SearchDataProvider();
+       /**
+        * Specifies that the images available for this composite will be the ones
+        * available in FileContextMenu.
+        */
+       public interface Images extends ClientBundle,FileContextMenu.Images, CellTreeView.Images, FileList.Images {
+
+               @Source("org/gss_project/gss/resources/blank.gif")
+               ImageResource blank();
+
+               @Source("org/gss_project/gss/resources/asc.png")
+               ImageResource asc();
+
+               @Source("org/gss_project/gss/resources/desc.png")
+               ImageResource desc();
+       }
+
+       
+       interface TableResources extends DragAndDropCellTable.Resources {
+           @Source({CellTable.Style.DEFAULT_CSS, "GssCellTable.css"})
+           TableStyle cellTableStyle();
+         }
+       
+       /**
+          * The styles applied to the table.
+          */
+         interface TableStyle extends CellTable.Style {
+         }
+
+       private String showingStats = "";
+
+       private int startIndex = 0;
+
+       /**
+        * A constant that denotes the completion of an IncrementalCommand.
+        */
+       public static final boolean DONE = false;
+
+       
+       
+       private final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
+
+       
+       
+       DragStopEventHandler dragStop = new DragStopEventHandler() {
+               
+               @Override
+               public void onDragStop(DragStopEvent event) {
+                       GWT.log("DRAG STOPPED");
+                       
+               }
+       };
+       
+       private static class ContactCell extends AbstractCell<org.gss_project.gss.web.client.rest.resource.FileResource> {
+
+           /**
+            * The html of the image used for contacts.
+            * 
+            */
+           private final String imageHtml;
+
+           public ContactCell(ImageResource image) {
+             this.imageHtml = AbstractImagePrototype.create(image).getHTML();
+           }
+
+           
+
+               
+
+           @Override
+           public void render(Context context, FileResource value, SafeHtmlBuilder sb) {
+             // Value can be null, so do a null check..
+             if (value == null) {
+               return;
+             }
+
+          sb.append(FileList.Templates.INSTANCE.rendelContactCell(imageHtml, value.getName(), value.getFileSizeAsString()));
+           }
+
+
+         }
+       /**
+        * Retrieve the celltable.
+        *
+        * @return the celltable
+        */
+       public DragAndDropCellTable<FileResource> getCelltable() {
+               return celltable;
+       }
+       
+
+       
+       /**
+        * The number of files in this folder.
+        */
+       int folderFileCount;
+
+       /**
+        * Total folder size
+        */
+       long folderTotalSize;
+
+       /**
+        * A cache of the files in the list.
+        */
+       private List<FileResource> files;
+
+       /**
+        * The widget's image bundle.
+        */
+       private final Images images;
+       
+       private FileContextMenu menuShowing;
+       private DragAndDropCellTable<FileResource> celltable;
+       private final MultiSelectionModel<FileResource> selectionModel;
+       
+       GssSimplePager pager;
+       GssSimplePager pagerTop;
+       /**
+        * Construct the file list widget. This entails setting up the widget
+        * layout, fetching the number of files in the current folder from the
+        * server and filling the local file cache of displayed files with data from
+        * the server, as well.
+        *
+        * @param _images
+        */
+       public SearchResults(Images _images) {
+               images = _images;
+               DragAndDropCellTable.Resources resources = GWT.create(TableResources.class);
+               ProvidesKey<FileResource> keyProvider = new ProvidesKey<FileResource>(){
+
+                       @Override
+                       public Object getKey(FileResource item) {
+                               return item.getUri();
+                       }
+                       
+               };
+               
+               celltable = new DragAndDropCellTable<FileResource>(GSS.VISIBLE_FILE_COUNT,resources,keyProvider){
+                       @Override
+                       protected void onBrowserEvent2(Event event) {
+                               /*if (DOM.eventGetType((Event) event) == Event.ONMOUSEDOWN && DOM.eventGetButton((Event) event) == NativeEvent.BUTTON_RIGHT){
+                                       fireClickEvent((Element) event.getEventTarget().cast());                                        
+                               }*/
+                               super.onBrowserEvent2(event);
+                       }
+               };
+               provider.addDataDisplay(celltable);
+               celltable.addDragStopHandler(dragStop);
+               celltable.addDragStartHandler(new DragStartEventHandler() {
+
+                     public void onDragStart(DragStartEvent event) {
+                       FileResource value = event.getDraggableData();
+                       
+                       com.google.gwt.dom.client.Element helper = event.getHelper();
+                       SafeHtmlBuilder sb = new SafeHtmlBuilder();
+                       sb.appendHtmlConstant("<b>");
+                       DisplayHelper.log(value.getName());
+                       if(getSelectedFiles().size()==1)
+                               sb.appendEscaped(value.getName());
+                       else
+                               sb.appendEscaped(getSelectedFiles().size()+" files");
+                       sb.appendHtmlConstant("</b>");
+                       helper.setInnerHTML(sb.toSafeHtml().asString());
+
+                     }
+                   });
+               DragAndDropColumn<FileResource, ImageResource> status = new DragAndDropColumn<FileResource, ImageResource>(new ImageResourceCell(){
+                       @Override
+                 public boolean handlesSelection() {
+                           return false;
+                         }
+               }) {
+                 @Override
+                 public ImageResource getValue(FileResource entity) {
+                   return getFileIcon(entity);
+                 }
+                 
+              };
+           celltable.addColumn(status,"");
+           
+           initDragOperation(status);
+               final DragAndDropColumn<FileResource,SafeHtml> nameColumn = new DragAndDropColumn<FileResource,SafeHtml>(new SafeHtmlCell()) {
+
+
+                       @Override
+                       public SafeHtml getValue(FileResource object) {
+                               SafeHtmlBuilder sb = new SafeHtmlBuilder();
+                sb.append(FileList.Templates.INSTANCE.filenameSpan(object.getName()));
+                               if (object.getContentType().endsWith("png") || object.getContentType().endsWith("gif") || object.getContentType().endsWith("jpeg") ){
+                    sb.appendHtmlConstant("&nbsp;").append(FileList.Templates.INSTANCE.viewLink(GSS.get().getTopPanel().getFileMenu().getDownloadURL(object), object.getOwner() + " : " + object.getPath() + object.getName()));
+                               }
+
+                               return sb.toSafeHtml();
+                       }
+                       
+               };
+               initDragOperation(nameColumn);
+               celltable.addColumn(nameColumn,"Name");
+               
+           DragAndDropColumn<FileResource,String> aColumn;
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               return GSS.get().findUserFullName(object.getOwner());
+                       }                       
+               },"Owner");
+               initDragOperation(aColumn);
+               
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               if(object.isDeleted())
+                                       return object.getPath()+" (In Trash)";
+                               return object.getPath();
+                       }                       
+               },"Path");
+               initDragOperation(aColumn);
+               
+               
+                       
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               return object.getVersion().toString();
+                       }                       
+               },"Version");
+               initDragOperation(aColumn);
+               
+               
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               // TODO Auto-generated method stub
+                               return object.getFileSizeAsString();
+                       }                       
+               },"Size");
+               initDragOperation(aColumn);
+                       
+               celltable.addColumn(aColumn=new DragAndDropColumn<FileResource,String>(new TextCell()) {
+                       @Override
+                       public String getValue(FileResource object) {
+                               return formatter.format(object.getModificationDate());
+                       }                       
+               },"Last Modified");
+               
+               
+              
+
+               VerticalPanel vp = new VerticalPanel();
+               vp.setWidth("100%");
+               celltable.setWidth("100%");
+               vp.add(searchResults);
+               searchResults.addStyleName("gss-searchLabel");
+               pagerTop = new GssSimplePager(GssSimplePager.TextLocation.CENTER);
+               pagerTop.setDisplay(celltable);
+               vp.add(pagerTop);
+               vp.add(celltable);
+               pager = new GssSimplePager(GssSimplePager.TextLocation.CENTER);
+               pager.setDisplay(celltable);
+               //celltable.setPageSize(2);
+               
+               vp.add(pager);
+               vp.setCellWidth(celltable, "100%");
+               
+               initWidget(vp);
+               
+               //initWidget(celltable);
+               celltable.setStyleName("gss-List");
+               selectionModel = new MultiSelectionModel<FileResource>();
+               
+
+                Handler selectionHandler = new SelectionChangeEvent.Handler() { 
+             @Override 
+             public void onSelectionChange(com.google.gwt.view.client.SelectionChangeEvent event) {
+                if(getSelectedFiles().size()==1)
+                        GSS.get().setCurrentSelection(getSelectedFiles().get(0));
+                else
+                        GSS.get().setCurrentSelection(getSelectedFiles());
+                               //contextMenu.setFiles(getSelectedFiles());
+             }
+         };
+         selectionModel.addSelectionChangeHandler(selectionHandler);
+         
+               celltable.setSelectionModel(selectionModel,GSSSelectionEventManager.<FileResource>createDefaultManager());
+               celltable.setPageSize(GSS.VISIBLE_FILE_COUNT);
+               celltable.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
+               Scheduler.get().scheduleIncremental(new RepeatingCommand() {
+
+                       @Override
+                       public boolean execute() {
+                               return fetchRootFolder();
+                       }
+               });
+               sinkEvents(Event.ONCONTEXTMENU);
+               sinkEvents(Event.ONMOUSEUP);
+               sinkEvents(Event.ONMOUSEDOWN);
+               sinkEvents(Event.ONCLICK);
+               sinkEvents(Event.ONKEYDOWN);
+               sinkEvents(Event.ONDBLCLICK);
+               GSS.preventIESelection();
+       }
+       
+       //public native void fireClickEvent(Element element) /*-{
+         //  var evObj = $doc.createEvent('MouseEvents');
+           //evObj.initEvent('click', true, true);
+           //element.dispatchEvent(evObj);
+       //}-*/;
+
+        public List<FileResource> getSelectedFiles() {
+         return new ArrayList<FileResource>(selectionModel.getSelectedSet());
+        }
+       
+        private void initDragOperation(DragAndDropColumn<?, ?> column) {
+
+                   // retrieve draggableOptions on the column
+                   DraggableOptions draggableOptions = column.getDraggableOptions();
+                   // use template to construct the helper. The content of the div will be set
+                   // after
+                   draggableOptions.setHelper($(FileList.Templates.INSTANCE.outerHelper().asString()));
+                   //draggableOptions.setZIndex(100);
+                   // opacity of the helper
+                   draggableOptions.setAppendTo("body"); 
+                   //draggableOptions.setOpacity((float) 0.8);
+                   draggableOptions.setContainment("document");
+                   // cursor to use during the drag operation
+                   draggableOptions.setCursor(Cursor.MOVE);
+                   // set the revert option
+                   draggableOptions.setRevert(RevertOption.ON_INVALID_DROP);
+                   // prevents dragging when user click on the category drop-down list
+                   draggableOptions.setCancel("select");
+                   
+                   draggableOptions.setOnBeforeDragStart(new DragFunction() {
+                               
+                               @Override
+                               public void f(DragContext context) {
+                                        FileResource value = context.getDraggableData();
+                                    if(!selectionModel.isSelected(value)){
+                                       throw new StopDragException();
+                                     }
+                                       
+                               }
+                       });
+                 }
+       
+        public void showContextMenu(Event event){
+                menuShowing = new FileContextMenu(images, false, true);
+                       menuShowing=menuShowing.onEmptyEvent(event);
+        }
+       @Override
+       public void onBrowserEvent(Event event) {
+               
+               if (files == null || files.size() == 0) {
+                       if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
+                               menuShowing = new FileContextMenu(images, false, true);
+                               menuShowing=menuShowing.onEmptyEvent(event);
+                               event.preventDefault();
+                               event.cancelBubble(true);
+                       }
+                       return;
+               }
+               if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() != 0) {
+                       GWT.log("*****GOING TO SHOW CONTEXT MENU ****", null);
+                       menuShowing =  new FileContextMenu(images, false, false);
+                       menuShowing=menuShowing.onEvent(event);
+                       event.cancelBubble(true);
+                       event.preventDefault();
+               } else if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
+                       menuShowing = new FileContextMenu(images, false, true);
+                       menuShowing=menuShowing.onEmptyEvent(event);
+                       event.cancelBubble(true);
+                       event.preventDefault();
+               } else if (DOM.eventGetType(event) == Event.ONDBLCLICK)
+                       if (getSelectedFiles().size() == 1) {
+                               GSS app = GSS.get();
+                               FileResource file = getSelectedFiles().get(0);
+                               String dateString = RestCommand.getDate();
+                               String resource = file.getUri().substring(app.getApiPath().length() - 1, file.getUri().length());
+                               String sig = app.getCurrentUserResource().getUsername() + " " +
+                                               RestCommand.calculateSig("GET", dateString, resource,
+                                               RestCommand.base64decode(app.getToken()));
+                               if(!file.isDeleted()){
+                                       Window.open(file.getUri() + "?Authorization=" + URL.encodeComponent(sig) + "&Date=" + URL.encodeComponent(dateString), "_blank", "");
+                               }
+                               event.preventDefault();
+                               return;
+                       }
+               super.onBrowserEvent(event);
+       }
+
+       /**
+        * Retrieve the root folder for the current user.
+        *
+        * @return true if the retrieval was successful
+        */
+       protected boolean fetchRootFolder() {
+               UserResource user = GSS.get().getCurrentUserResource();
+               if (user == null)
+                       return !DONE;
+               // Update cache and clear selection.
+               updateFileCache(null);
+               return DONE;
+       }
+
+
+       /**
+        * Update the display of the file list.
+        */
+       void update(boolean sort) {
+               int count = folderFileCount;
+               int max = startIndex + GSS.VISIBLE_FILE_COUNT;
+               if (max > count)
+                       max = count;
+               folderTotalSize = 0;
+               
+               copyListAndContinue(files);
+               for(FileResource f : files){
+                       folderTotalSize += f.getContentLength();
+               }
+               if (folderFileCount == 0) {
+                       showingStats = "no files";
+               } else if (folderFileCount < GSS.VISIBLE_FILE_COUNT) {
+                       if (folderFileCount == 1)
+                               showingStats = "1 file";
+                       else
+                               showingStats = folderFileCount + " files";
+                       showingStats += " (" + FileResource.getFileSizeAsString(folderTotalSize) + ")";
+               } else {
+                       showingStats = "" + (startIndex + 1) + " - " + max + " of " + count + " files" + " (" + FileResource.getFileSizeAsString(folderTotalSize) + ")";
+               }
+               updateCurrentlyShowingStats();
+
+       }
+
+       /**
+        * Return the proper icon based on the MIME type of the file.
+        *
+        * @param file
+        * @return the icon
+        */
+       private ImageResource getFileIcon(FileResource file) {
+               String mimetype = file.getContentType();
+               boolean shared = file.isShared();
+               if (mimetype == null)
+                       return shared ? images.documentShared() : images.document();
+               mimetype = mimetype.toLowerCase();
+               if (mimetype.startsWith("application/pdf"))
+                       return shared ? images.pdfShared() : images.pdf();
+               else if (mimetype.endsWith("excel"))
+                       return shared ? images.spreadsheetShared() : images.spreadsheet();
+               else if (mimetype.endsWith("msword"))
+                       return shared ? images.wordprocessorShared() : images.wordprocessor();
+               else if (mimetype.endsWith("powerpoint"))
+                       return shared ? images.presentationShared() : images.presentation();
+               else if (mimetype.startsWith("application/zip") ||
+                                       mimetype.startsWith("application/gzip") ||
+                                       mimetype.startsWith("application/x-gzip") ||
+                                       mimetype.startsWith("application/x-tar") ||
+                                       mimetype.startsWith("application/x-gtar"))
+                       return shared ? images.zipShared() : images.zip();
+               else if (mimetype.startsWith("text/html"))
+                       return shared ? images.htmlShared() : images.html();
+               else if (mimetype.startsWith("text/plain"))
+                       return shared ? images.txtShared() : images.txt();
+               else if (mimetype.startsWith("image/"))
+                       return shared ? images.imageShared() : images.image();
+               else if (mimetype.startsWith("video/"))
+                       return shared ? images.videoShared() : images.video();
+               else if (mimetype.startsWith("audio/"))
+                       return shared ? images.audioShared() : images.audio();
+               return shared ? images.documentShared() : images.document();
+       }
+
+       /**
+        * Update status panel with currently showing file stats.
+        */
+       public void updateCurrentlyShowingStats() {
+               GSS.get().getStatusPanel().updateCurrentlyShowing(showingStats);
+       }
+
+       public void updateFileCache(String query) {
+               final GSS app = GSS.get();
+               setLastQuery(query);
+               clearSelectedRows();
+               //clearLabels();
+               startIndex = 0;
+               app.showLoadingIndicator("Getting Search Results",null);
+               if (query == null || query.trim().equals("")) {
+                       searchResults.setHTML("You must specify a query.");
+                       setFiles(new ArrayList());
+                       update(true);
+                       app.hideLoadingIndicator();
+               } else if (!GSS.isValidResourceName(query)) {
+                       searchResults.setHTML("The query was invalid. Try to use words that appear in the file's name, contents or tags.");
+                       setFiles(new ArrayList());
+                       update(true);
+                       app.hideLoadingIndicator();
+               } else{
+                       searchResults.setHTML("Search results for " + query);
+                       showCellTable(true);
+                       
+               }
+       }
+
+       /**
+        * Fill the file cache with data.
+        */
+       public void setFiles(final List<FileResource> _files) {
+               if (_files.size() > 0 && ! (GSS.get().getTreeView().getSelection() instanceof TrashResource)) {
+                       files = new ArrayList<FileResource>();
+                       for (FileResource fres : _files)
+                               files.add(fres);
+               }
+               else
+                       files = _files;
+               Collections.sort(files, new Comparator<FileResource>() {
+
+                       @Override
+                       public int compare(FileResource arg0, FileResource arg1) {
+                               return arg0.getName().compareTo(arg1.getName());
+                       }
+
+               });
+               folderFileCount = files.size();
+       }
+
+       
+
+       
+       /**
+        * Does the list contains the requested filename
+        *
+        * @param fileName
+        * @return true/false
+        */
+       public boolean contains(String fileName) {
+               for (int i = 0; i < files.size(); i++)
+                       if (files.get(i).getName().equals(fileName))
+                               return true;
+               return false;
+       }
+
+       public void clearSelectedRows() {
+               Iterator<FileResource> it = selectionModel.getSelectedSet().iterator();
+               while(it.hasNext()){
+                       selectionModel.setSelected(it.next(),false);
+               }
+       }
+
+       /**
+        *
+        */
+       public void selectAllRows() {
+               Iterator<FileResource> it = selectionModel.getSelectedSet().iterator();
+               while(it.hasNext()){
+                       selectionModel.setSelected(it.next(),true);
+               }
+
+
+       }
+
+       
+       private void sortFiles(final String sortingProperty, final boolean sortingType){
+               Collections.sort(files, new Comparator<FileResource>() {
+
+            @Override
+            public int compare(FileResource arg0, FileResource arg1) {
+                    AbstractImagePrototype descPrototype = AbstractImagePrototype.create(images.desc());
+                    AbstractImagePrototype ascPrototype = AbstractImagePrototype.create(images.asc());
+                    if (sortingType){
+                            if (sortingProperty.equals("version")) {
+                                    return arg0.getVersion().compareTo(arg1.getVersion());
+                            } else if (sortingProperty.equals("owner")) {
+                                    return arg0.getOwner().compareTo(arg1.getOwner());
+                            } else if (sortingProperty.equals("date")) {
+                                    return arg0.getModificationDate().compareTo(arg1.getModificationDate());
+                            } else if (sortingProperty.equals("size")) {
+                                    return arg0.getContentLength().compareTo(arg1.getContentLength());
+                            } else if (sortingProperty.equals("name")) {
+                                    return arg0.getName().compareTo(arg1.getName());
+                            } else if (sortingProperty.equals("path")) {
+                                    return arg0.getUri().compareTo(arg1.getUri());
+                            } else {
+                                    return arg0.getName().compareTo(arg1.getName());
+                            }
+                    }
+                    else if (sortingProperty.equals("version")) {
+                            
+                            return arg1.getVersion().compareTo(arg0.getVersion());
+                    } else if (sortingProperty.equals("owner")) {
+                            
+                            return arg1.getOwner().compareTo(arg0.getOwner());
+                    } else if (sortingProperty.equals("date")) {
+                            
+                            return arg1.getModificationDate().compareTo(arg0.getModificationDate());
+                    } else if (sortingProperty.equals("size")) {
+                            
+                            return arg1.getContentLength().compareTo(arg0.getContentLength());
+                    } else if (sortingProperty.equals("name")) {
+                            
+                            return arg1.getName().compareTo(arg0.getName());
+                    } else if (sortingProperty.equals("path")) {
+                            
+                            return arg1.getUri().compareTo(arg0.getUri());
+                    } else {
+                            
+                            return arg1.getName().compareTo(arg0.getName());
+                    }
+            }
+
+               });
+       }
+       
+       
+       /**
+        * Creates a new ArrayList<FileResources> from the given files ArrayList 
+        * in order that the input files remain untouched 
+        * and continues to find user's full names of each FileResource element
+        * in the new ArrayList
+        *    
+        * @param filesInput
+        */
+       private void copyListAndContinue(List<FileResource> filesInput){
+               List<FileResource> copiedFiles = new ArrayList<FileResource>();         
+               for(FileResource file : filesInput) {
+                       copiedFiles.add(file);
+               }
+               handleFullNames(copiedFiles);
+       }
+       
+       /**
+        * Examines whether or not the user's full name exists in the 
+        * userFullNameMap in the GSS.java for every element of the input list.
+        * If the user's full name does not exist in the map then a command is being made.  
+        * 
+        * @param filesInput
+        */
+       private void handleFullNames(List<FileResource> filesInput){            
+               if(filesInput.size() == 0){
+                       showCellTable(false);
+                       return;
+               }               
+
+               if(GSS.get().findUserFullName(filesInput.get(0).getOwner()) == null){
+                       findFullNameAndUpdate(filesInput);              
+                       return;
+               }
+                               
+               if(filesInput.size() >= 1){
+                       filesInput.remove(filesInput.get(0));
+                       if(filesInput.isEmpty()){
+                               showCellTable(false);                           
+                       }else{
+                               handleFullNames(filesInput);
+                       }
+               }               
+       }
+       
+       /**
+        * Makes a command to search for full name from a given username. 
+        * Only after the completion of the command the celltable is shown
+        * or the search for the next full name continues.
+        *  
+        * @param filesInput
+        */
+       private void findFullNameAndUpdate(final List<FileResource> filesInput){                
+               String aUserName = filesInput.get(0).getOwner();
+               String path = GSS.get().getApiPath() + "users/" + aUserName; 
+
+               GetCommand<UserSearchResource> gg = new GetCommand<UserSearchResource>(UserSearchResource.class, path, false,null) {
+                       @Override
+                       public void onComplete() {
+                               final UserSearchResource result = getResult();
+                               for (UserResource user : result.getUsers()){
+                                       String username = user.getUsername();
+                                       String userFullName = user.getName();
+                                       GSS.get().putUserToMap(username, userFullName);
+                                       if(filesInput.size() >= 1){
+                                               filesInput.remove(filesInput.get(0));
+                                               if(filesInput.isEmpty()){
+                                                       showCellTable(false);
+                                               }else{
+                                                       handleFullNames(filesInput);
+                                               }                                                                                               
+                                       }                                                                       
+                               }
+                       }
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               GSS.get().displayError("Unable to fetch user's full name from the given username " + filesInput.get(0).getOwner());
+                               if(filesInput.size() >= 1){
+                                       filesInput.remove(filesInput.get(0));
+                                       handleFullNames(filesInput);                                    
+                               }
+                       }
+               };
+               DeferredCommand.addCommand(gg);
+       
+       }
+       /**
+        * Shows the files in the cellTable 
+        */
+
+       private void showCellTable(boolean update){
+               if(celltable.getRowCount()>GSS.VISIBLE_FILE_COUNT){
+                       pager.setVisible(true);
+                       pagerTop.setVisible(true);
+               }
+               else{
+                       pager.setVisible(false);
+                       pagerTop.setVisible(false);
+               }
+               if(update)
+                       provider.onRangeChanged(celltable);
+               celltable.redrawHeaders();              
+       }
+       
+       
+       /**
+        * Retrieve the lastQuery.
+        *
+        * @return the lastQuery
+        */
+       public String getLastQuery() {
+               return lastQuery;
+       }
+       
+       
+       /**
+        * Modify the lastQuery.
+        *
+        * @param lastQuery the lastQuery to set
+        */
+       public void setLastQuery(String lastQuery) {
+               this.lastQuery = lastQuery;
+       }
+       
+       class SearchDataProvider extends AsyncDataProvider<FileResource>{
+
+               @Override
+               protected void onRangeChanged(final HasData<FileResource> display) {
+                       final int start = display.getVisibleRange().getStart();
+                       final GSS app = GSS.get();
+                       if(getLastQuery()==null||getLastQuery().equals("")){
+                               display.setRowCount(0,true);
+                               return;
+                               
+                       }
+                       GetCommand<SearchResource> eg = new GetCommand<SearchResource>(SearchResource.class,
+                                               app.getApiPath() + "search/" +URL.encodeComponent(getLastQuery())+"?start="+start, null) {
+
+                               @Override
+                               public void onComplete() {
+                                       SearchResource s = getResult();
+                                       display.setRowCount(s.getSize(),true);
+                                       display.setRowData(start, s.getFiles());
+                                       setFiles(s.getFiles());
+                                       update(true);
+                                       
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       if(t instanceof RestException)
+                                               app.displayError("Unable to perform search:"+((RestException)t).getHttpStatusText());
+                                       else
+                                               app.displayError("System error performing search:"+t.getMessage());
+                                       GWT.log("",t);
+                                       updateFileCache("");
+                               }
+
+                       };
+                       DeferredCommand.addCommand(eg);
+                       
+               }
+               
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/SessionExpiredDialog.java b/src/org/gss_project/gss/web/client/SessionExpiredDialog.java
new file mode 100644 (file)
index 0000000..a5c7e6a
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class SessionExpiredDialog extends DialogBox {
+       /**
+        * The widget constructor.
+        */
+       public SessionExpiredDialog() {
+               // Set the dialog's caption.
+               setText("Session Expired");
+               setAnimationEnabled(true);
+               VerticalPanel outer = new VerticalPanel();
+
+               // Create the text and set a style name so we can style it with CSS.
+               HTML text = new HTML("<p>Your session has expired. You will have to reauthenticate with your Identity Provider.</p> ");
+               text.setStyleName("gss-AboutText");
+               outer.add(text);
+
+               // Create the 'OK' button, along with a listener that hides the dialog
+               // when the button is clicked.
+               Button confirm = new Button("Proceed", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               GSS.get().authenticateUser();
+                               hide();
+                       }
+               });
+               outer.add(confirm);
+               outer.setCellHorizontalAlignment(confirm, HasHorizontalAlignment.ALIGN_CENTER);
+               outer.setSpacing(8);
+               setWidget(outer);
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+                       // Use the popup's key preview hooks to close the dialog when either
+                       // enter or escape is pressed.
+                       switch (evt.getKeyCode()) {
+                               case KeyCodes.KEY_ENTER:
+                                       GSS.get().authenticateUser();
+                                       hide();
+                                       break;
+                               case KeyCodes.KEY_ESCAPE:
+                                       hide();
+                                       break;
+                       }
+       }
+
+
+
+}
diff --git a/src/org/gss_project/gss/web/client/SettingsMenu.java b/src/org/gss_project/gss/web/client/SettingsMenu.java
new file mode 100644 (file)
index 0000000..d2ec15e
--- /dev/null
@@ -0,0 +1,111 @@
+/*\r
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
+ *\r
+ * This file is part of GSS.\r
+ *\r
+ * GSS is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * GSS is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package org.gss_project.gss.web.client;\r
+\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.resources.client.ClientBundle;\r
+import com.google.gwt.resources.client.ImageResource;\r
+import com.google.gwt.user.client.Command;\r
+import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
+import com.google.gwt.user.client.ui.MenuBar;\r
+import com.google.gwt.user.client.ui.MenuItem;\r
+import com.google.gwt.user.client.ui.PopupPanel;\r
+\r
+/**\r
+ * The 'settings' menu implementation.\r
+ */\r
+public class SettingsMenu extends PopupPanel implements ClickHandler {\r
+\r
+       /**\r
+        * The widget's images.\r
+        */\r
+       private Images images;\r
+       private final MenuBar contextMenu;\r
+       /**\r
+        * An image bundle for this widgets images.\r
+        */\r
+       public interface Images extends ClientBundle,MessagePanel.Images {\r
+\r
+               /**\r
+                * Will bundle the file 'advancedsettings.png' residing in the package\r
+                * 'org.gss_project.gss.web.resources'.\r
+                *\r
+                * @return the image prototype\r
+                */\r
+               @Source("org/gss_project/gss/resources/advancedsettings.png")\r
+               ImageResource preferences();\r
+\r
+               @Source("org/gss_project/gss/resources/lock.png")\r
+               ImageResource credentials();\r
+\r
+       }\r
+\r
+       /**\r
+        * The widget's constructor.\r
+        *\r
+        * @param newImages the image bundle passed on by the parent object\r
+        */\r
+       public SettingsMenu(final Images newImages) {\r
+               // The popup's constructor's argument is a boolean specifying that it\r
+               // auto-close itself when the user clicks outside of it.\r
+               super(true);\r
+               setAnimationEnabled(true);\r
+               images = newImages;\r
+\r
+               Command userCredentialsCommand = new Command(){\r
+                       @Override\r
+                       public void execute() {\r
+                               CredentialsDialog dlg = new CredentialsDialog(newImages);\r
+                               dlg.center();\r
+                       }\r
+               };\r
+               contextMenu = new MenuBar(true);\r
+//             contextMenu.addItem("<span>" + newImages.preferences().getHTML() + "&nbsp;Preferences</span>", true, cmd);\r
+               MenuItem showCredentialsItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.credentials()).getHTML() + "&nbsp;Show Credentials</span>", true, userCredentialsCommand);\r
+               showCredentialsItem.getElement().setId("topMenu.settingsMenu.showCredentials");\r
+               contextMenu.addItem(showCredentialsItem);\r
+               \r
+               add(contextMenu);\r
+               // setStyleName("toolbarPopup");\r
+       }\r
+\r
+       @Override\r
+       public void onClick(final ClickEvent event) {\r
+               final SettingsMenu menu = new SettingsMenu(images);\r
+               final int left = event.getRelativeElement().getAbsoluteLeft();\r
+               final int top = event.getRelativeElement().getAbsoluteTop() + event.getRelativeElement().getOffsetHeight();\r
+               menu.setPopupPosition(left, top);\r
+\r
+               menu.show();\r
+       }\r
+\r
+\r
+       /**\r
+        * Retrieve the contextMenu.\r
+        *\r
+        * @return the contextMenu\r
+        */\r
+       public MenuBar getContextMenu() {\r
+               contextMenu.setAutoOpen(false);\r
+               return contextMenu;\r
+       }\r
+\r
+\r
+}\r
diff --git a/src/org/gss_project/gss/web/client/SortableHeader.java b/src/org/gss_project/gss/web/client/SortableHeader.java
new file mode 100644 (file)
index 0000000..0faf695
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed 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.gss_project.gss.web.client;
+
+import com.google.gwt.cell.client.Cell.Context;
+import com.google.gwt.cell.client.ClickableTextCell;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+import com.google.gwt.user.cellview.client.Header;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+
+/**
+ * A {@link Header} subclass that maintains sorting state and displays an icon
+ * to indicate the sort direction.
+ */
+public class SortableHeader extends Header<String> {
+
+  interface Template extends SafeHtmlTemplates {
+    @Template("<div style=\"position:relative;cursor:hand;cursor:pointer;"
+        + "padding-right:{0}px;\">{1}<div>{2}</div></div>")
+    SafeHtml sorted(int imageWidth, SafeHtml arrow, String text);
+
+    @Template("<div style=\"position:relative;cursor:hand;cursor:pointer;"
+        + "padding-right:{0}px;\"><div style=\"position:absolute;display:none;"
+        + "\"></div><div>{1}</div></div>")
+    SafeHtml unsorted(int imageWidth, String text);
+  }
+
+  private static Template template;
+
+  /**
+   * Image resources.
+   */
+  public static interface Resources extends ClientBundle {
+
+    ImageResource downArrow();
+
+    ImageResource upArrow();
+  }
+
+  private static final Resources RESOURCES = GWT.create(Resources.class);
+  private static final int IMAGE_WIDTH = 16;
+  private static final SafeHtml DOWN_ARROW = makeImage(RESOURCES.downArrow());
+  private static final SafeHtml UP_ARROW = makeImage(RESOURCES.upArrow());
+
+  private static SafeHtml makeImage(ImageResource resource) {
+    AbstractImagePrototype proto = AbstractImagePrototype.create(resource);
+    String html = proto.getHTML().replace("style='",
+        "style='position:absolute;right:0px;top:0px;");
+    return SafeHtmlUtils.fromTrustedString(html);
+  }
+
+  private boolean reverseSort = false;
+  private boolean sorted = false;
+  private String text;
+
+  SortableHeader(String text) {
+    super(new ClickableTextCell());
+    if (template == null) {
+      template = GWT.create(Template.class);
+    }
+    this.text = text;
+  }
+
+  public boolean getReverseSort() {
+    return reverseSort;
+  }
+
+  @Override
+  public String getValue() {
+    return text;
+  }
+
+  @Override
+  public void render(Context context, SafeHtmlBuilder sb) {
+    if (sorted) {
+      sb.append(template.sorted(IMAGE_WIDTH, reverseSort ? DOWN_ARROW : UP_ARROW, text));
+    } else {
+      sb.append(template.unsorted(IMAGE_WIDTH, text));
+    }
+  }
+
+  public void setReverseSort(boolean reverseSort) {
+    this.reverseSort = reverseSort;
+  }
+
+  public void setSorted(boolean sorted) {
+    this.sorted = sorted;
+  }
+
+  public void toggleReverseSort() {
+    this.reverseSort = !this.reverseSort;
+  }
+}
diff --git a/src/org/gss_project/gss/web/client/StatusPanel.java b/src/org/gss_project/gss/web/client/StatusPanel.java
new file mode 100644 (file)
index 0000000..3011c7c
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.QuotaHolder;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.IncrementalCommand;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+
+/**
+ * The panel that displays a status bar with quota information.
+ */
+public class StatusPanel extends Composite {
+       public static final boolean DONE = false;
+       private HTML fileCountLabel = new HTML("");
+       private HTML fileSizeLabel = new HTML("");
+       private HTML quotaIcon = new HTML("");
+       private HTML quotaLabel = new HTML("");
+       private HTML lastLoginLabel = new HTML("");
+       private HTML currentLoginLabel = new HTML("");
+       private HTML currentlyShowingLabel = new HTML("");
+
+       /**
+        * An image bundle for this widget's images.
+        */
+       public interface Images extends ClientBundle {
+
+               @Source("org/gss_project/gss/resources/windowlist.png")
+               ImageResource totalFiles();
+
+               @Source("org/gss_project/gss/resources/database.png")
+               ImageResource totalSize();
+
+               @Source("org/gss_project/gss/resources/redled.png")
+               ImageResource redSize();
+
+               @Source("org/gss_project/gss/resources/greenled.png")
+               ImageResource greenSize();
+
+               @Source("org/gss_project/gss/resources/yellowled.png")
+               ImageResource yellowSize();
+
+               @Source("org/gss_project/gss/resources/xclock.png")
+               ImageResource lastLogin();              
+       }
+
+       private final Images images;
+
+       /**
+        * The constructor of the status panel.
+        *
+        * @param theImages the supplied images
+        */
+       public StatusPanel(Images theImages) {
+               images = theImages;
+               HorizontalPanel outer = new HorizontalPanel();
+               outer.setWidth("100%");
+               outer.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
+
+               HorizontalPanel left = new HorizontalPanel();
+               left.setSpacing(8);
+               HorizontalPanel middle = new HorizontalPanel();
+               middle.setSpacing(8);
+               HorizontalPanel right = new HorizontalPanel();
+               right.setSpacing(8);
+               outer.add(left);
+               outer.add(middle);
+               outer.add(right);
+               left.add(new HTML("<b>Totals:</b> "));
+               left.add(AbstractImagePrototype.create(images.totalFiles()).createImage());
+               left.add(fileCountLabel);
+               left.add(AbstractImagePrototype.create(images.totalSize()).createImage());
+               left.add(fileSizeLabel);
+               quotaIcon.setHTML(AbstractImagePrototype.create(images.greenSize()).getHTML());
+               left.add(quotaIcon);
+               left.add(quotaLabel);
+               middle.add(AbstractImagePrototype.create(images.lastLogin()).createImage());
+               middle.add(new HTML("<b>Last login:</b> "));
+               middle.add(lastLoginLabel);
+               middle.add(new HTML("<b>\u0387 Current session login:</b> "));
+               middle.add(currentLoginLabel);
+               right.add(currentlyShowingLabel);
+               outer.setStyleName("statusbar-inner");
+               left.setStyleName("statusbar-inner");
+               middle.setStyleName("statusbar-inner");
+               right.setStyleName("statusbar-inner");
+               outer.setCellHorizontalAlignment(right, HasHorizontalAlignment.ALIGN_RIGHT);
+
+               initWidget(outer);
+
+               // Initialize and display the quota information.
+               DeferredCommand.addCommand(new IncrementalCommand() {
+                       @Override
+                       public boolean execute() {
+                               GSS app = GSS.get();
+                               UserResource user = app.getCurrentUserResource();
+                               if (user == null || app.getTreeView().getMyFolders() == null)
+                                       return !DONE;
+                               displayStats(user);
+                               return DONE;
+                       }
+               });
+       }
+
+       /**
+        * Refresh the widget with the provided statistics.
+        */
+       private void displayStats(UserResource user) {
+               QuotaHolder stats = user.getQuota();
+               if (stats.getFileCount() == 1)
+                       fileCountLabel.setHTML("1 file");
+               else
+                       fileCountLabel.setHTML(stats.getFileCount() + " files");
+               fileSizeLabel.setHTML(stats.getFileSizeAsString() + " used");
+               long pc = stats.percentOfFreeSpace();
+               if(pc<10) {
+                       quotaIcon.setHTML(AbstractImagePrototype.create(images.redSize()).getHTML());
+                       quotaLabel.setHTML(stats.getQuotaLeftAsString() +" free");
+               } else if(pc<20) {
+                       quotaIcon.setHTML(AbstractImagePrototype.create(images.yellowSize()).getHTML());
+                       quotaLabel.setHTML(stats.getQuotaLeftAsString() +" free");
+               } else {
+                       quotaIcon.setHTML(AbstractImagePrototype.create(images.greenSize()).getHTML());
+                       quotaLabel.setHTML(stats.getQuotaLeftAsString() +" free");
+               }
+               final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
+               lastLoginLabel.setHTML(formatter.format(user.getLastLogin()));
+               currentLoginLabel.setHTML(formatter.format(user.getCurrentLogin()));
+       }
+
+       /**
+        * Requests updated quota information from the server and refreshes
+        * the display.
+        */
+       public void updateStats() {
+               final GSS app = GSS.get();
+               UserResource user = app.getCurrentUserResource();
+               GetCommand<UserResource> uc = new GetCommand<UserResource>(UserResource.class, user.getUri(), null){
+                       @Override
+                       public void onComplete() {
+                               displayStats(getResult());
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               if(t instanceof RestException)
+                                       app.displayError("Unable to fetch quota:" +
+                                                               ((RestException)t).getHttpStatusText());
+                               else
+                                       app.displayError("System error fetching quota:" +
+                                                               t.getMessage());
+                               GWT.log("ERR", t);
+                       }
+               };
+               DeferredCommand.addCommand(uc);
+       }
+
+       /**
+        * Displays the statistics for the current folder.
+        *
+        * @param text the statistics to display
+        */
+       public void updateCurrentlyShowing(String text) {
+               if (text == null)
+                       currentlyShowingLabel.setText("");
+               else
+                       currentlyShowingLabel.setHTML(" <b>Showing:</b> " + text);
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/TopPanel.java b/src/org/gss_project/gss/web/client/TopPanel.java
new file mode 100644 (file)
index 0000000..9f820cf
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HasVerticalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+
+/**
+ * The top panel, which contains the menu bar icons and the user name.
+ */
+public class TopPanel extends Composite {
+
+       /**
+        * A constant that denotes the completion of an IncrementalCommand.
+        */
+       public static final boolean DONE = false;
+
+       /**
+        * An image bundle for this widgets images.
+        */
+       public interface Images extends ClientBundle, FileMenu.Images, EditMenu.Images,
+                       SettingsMenu.Images, GroupMenu.Images, FilePropertiesDialog.Images,
+                       HelpMenu.Images, LoadingIndicator.Images {
+
+               @Source("org/gss_project/gss/resources/exit.png")
+               ImageResource exit();
+
+               @Source("org/gss_project/gss/resources/folder_blue.png")
+               ImageResource folder();
+
+               @Source("org/gss_project/gss/resources/edit.png")
+               ImageResource edit();
+
+               @Source("org/gss_project/gss/resources/edit_group.png")
+               ImageResource group();
+
+               @Source("org/gss_project/gss/resources/configure.png")
+               ImageResource configure();
+
+               @Source("org/gss_project/gss/resources/help.png")
+               ImageResource help();
+
+               @Source("org/gss_project/gss/resources/pithos-logo.png")
+               ImageResource gssLogo();
+
+               @Source("org/gss_project/gss/resources/grnet-logo.png")
+               ImageResource grnetLogo();
+       }
+
+       /**
+        * The menu bar widget.
+        */
+       private MenuBar menu;
+
+       /**
+        * The file menu widget.
+        */
+       private FileMenu fileMenu;
+
+       /**
+        * The edit menu widget.
+        */
+       private EditMenu editMenu;
+
+       /**
+        * The group menu widget.
+        */
+       private GroupMenu groupMenu;
+
+       /**
+        * The settings menu widget.
+        */
+       private SettingsMenu settingsMenu;
+
+       /**
+        * The help menu widget.
+        */
+       private HelpMenu helpMenu;
+
+       /**
+        * A widget that displays a message indicating that communication with the
+        * server is underway.
+        */
+       private LoadingIndicator loading;
+
+       /**
+        * The constructor for the top panel.
+        *
+        * @param images the supplied images
+        */
+       public TopPanel(Images images) {
+               fileMenu = new FileMenu(images);
+               editMenu = new EditMenu(images);
+               groupMenu = new GroupMenu(images);
+               settingsMenu = new SettingsMenu(images);
+               helpMenu = new HelpMenu(images);
+               loading = new LoadingIndicator(images);
+               HorizontalPanel outer = new HorizontalPanel();
+
+               outer.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
+
+               menu = new MenuBar();
+               menu.setWidth("100%");
+               menu.setAutoOpen(false);
+               menu.setAnimationEnabled(true);
+               menu.setStyleName("toolbarmenu");
+
+               Command quitCommand = new Command(){
+                       @Override
+                       public void execute() {
+                               QuitDialog dlg = new QuitDialog();
+                               dlg.center();
+                       }
+               };
+               MenuItem quitItem = new MenuItem("<table style='font-size: 100%'><tr><td>" +
+                                       AbstractImagePrototype.create(images.exit()).getHTML() + "</td><td>Quit</td></tr></table>", true, quitCommand);
+               quitItem.getElement().setId("topMenu.quit");
+               
+               MenuItem fileItem = new MenuItem("<table style='font-size: 100%'><tr><td>" +
+                                       AbstractImagePrototype.create(images.folder()).getHTML() + "</td><td>File</td></tr></table>", true, new MenuBar(true)){
+                       @Override
+                       public MenuBar getSubMenu() {
+                               return fileMenu.createMenu();
+                       }
+               };
+               fileItem.getElement().setId("topMenu.file");
+               
+               MenuItem editItem = new MenuItem("<table style='font-size: 100%'><tr><td>" +
+                                       AbstractImagePrototype.create(images.edit()).getHTML() + "</td><td>Edit</td></tr></table>", true, new MenuBar(true)){
+                       @Override
+                       public MenuBar getSubMenu() {
+                               return editMenu.createMenu();
+                       }
+               };
+               editItem.getElement().setId("topMenu.edit");
+               
+               MenuItem groupItem = new MenuItem("<table style='font-size: 100%'><tr><td>" +
+                                       AbstractImagePrototype.create(images.group()).getHTML() + "</td><td>Group</td></tr></table>", true,
+                                       groupMenu.getContextMenu());
+               groupItem.getElement().setId("topMenu.group");
+               
+               MenuItem configureItem = new MenuItem("<table style='font-size: 100%'><tr><td>" +
+                                       AbstractImagePrototype.create(images.configure()).getHTML() + "</td><td>Settings</td></tr></table>",
+                                       true,settingsMenu.getContextMenu());
+               configureItem.getElement().setId("topMenu.settings");
+               
+               MenuItem helpItem = new MenuItem("<table style='font-size: 100%'><tr><td>" +
+                                       AbstractImagePrototype.create(images.help()).getHTML() + "</td><td>Help</td></tr></table>", true, new MenuBar(true)){
+                       @Override
+                       public MenuBar getSubMenu() {
+                               return helpMenu.createMenu();
+                       }
+               };
+               helpItem.getElement().setId("topMenu.help");
+               
+               menu.addItem(quitItem);
+               menu.addItem(fileItem);
+               menu.addItem(editItem);
+               menu.addItem(groupItem);
+               menu.addItem(configureItem);
+               menu.addItem(helpItem);
+
+               outer.setSpacing(2);
+               outer.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
+               outer.setCellVerticalAlignment(menu, HasVerticalAlignment.ALIGN_MIDDLE);
+               outer.add(menu);
+               outer.setStyleName("toolbar");
+
+               outer.add(loading);
+
+               Configuration conf = (Configuration) GWT.create(Configuration.class);
+        String path = Window.Location.getPath();
+        String baseUrl = GWT.getModuleBaseURL();
+        String homeUrl = baseUrl.substring(0, baseUrl.indexOf(path));
+               HTML logos = new HTML("<table><tr><td><a href='" + homeUrl +
+                                       "' target='gss'>" +     AbstractImagePrototype.create(images.gssLogo()).getHTML() +
+                                       "</a><a href='http://www.grnet.gr/' " + "target='grnet'>" +
+                                       AbstractImagePrototype.create(images.grnetLogo()).getHTML()+"</a></td></tr></table>");
+               outer.add(logos);
+
+               outer.setCellHorizontalAlignment(logos, HasHorizontalAlignment.ALIGN_RIGHT);
+
+               initWidget(outer);
+       }
+
+
+       /**
+        * Retrieve the loading.
+        *
+        * @return the loading
+        */
+       public LoadingIndicator getLoading() {
+               return loading;
+       }
+
+       /**
+        * Retrieve the fileMenu.
+        *
+        * @return the fileMenu
+        */
+       FileMenu getFileMenu() {
+               return fileMenu;
+       }
+
+       /**
+        * Retrieve the editMenu.
+        *
+        * @return the editMenu
+        */
+       EditMenu getEditMenu() {
+               return editMenu;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/Updateable.java b/src/org/gss_project/gss/web/client/Updateable.java
new file mode 100644 (file)
index 0000000..3bdcb02
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+
+/**
+ * @author kman
+ *
+ */
+public interface Updateable {
+       public void update();
+}
diff --git a/src/org/gss_project/gss/web/client/UserAddDialog.java b/src/org/gss_project/gss/web/client/UserAddDialog.java
new file mode 100644 (file)
index 0000000..2cf0feb
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
+import com.google.gwt.user.client.ui.SuggestBox;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * @author kman
+ */
+public class UserAddDialog extends DialogBox {
+
+       private MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
+       private SuggestBox suggestBox = new SuggestBox(oracle);
+
+       String selectedUser=null;
+       FlexTable userTable = new FlexTable();
+
+       /**
+        * The widget's constructor.
+        */
+       public UserAddDialog() {
+               setAnimationEnabled(true);
+               setText("Add User");
+               VerticalPanel panel = new VerticalPanel();
+               setWidget(panel);
+               panel.addStyleName("gss-TabPanelBottom");
+               userTable.addStyleName("gss-permList");
+               userTable.setWidget(0, 0, new Label("Username:"));
+               userTable.getFlexCellFormatter().setStyleName(0, 0, "props-toplabels");
+               suggestBox.getTextBox().addFocusHandler(new FocusHandler() {
+
+                       @Override
+                       public void onFocus(FocusEvent event) {
+                               if (selectedUser != null && selectedUser.endsWith("@"))
+                                       updateSuggestions();
+                       }
+               });
+
+               suggestBox.addKeyUpHandler(new KeyUpHandler() {
+
+                       @Override
+                       public void onKeyUp(KeyUpEvent event) {
+                               // Ignore the arrow keys.
+                               int keyCode=event.getNativeKeyCode();
+                               if(keyCode == KeyCodes.KEY_UP ||
+                                               keyCode == KeyCodes.KEY_DOWN ||
+                                               keyCode == KeyCodes.KEY_LEFT ||
+                                               keyCode == KeyCodes.KEY_RIGHT)
+                                       return;
+                               if (keyCode==KeyCodes.KEY_ESCAPE) {
+                                       suggestBox.hideSuggestionList();
+                                       return;
+                               }
+                               String text = suggestBox.getText().trim();
+                               // Avoid useless queries for keystrokes that do not modify the
+                               // text.
+                               if (text.equals(selectedUser))
+                                       return;
+                               selectedUser = text;
+                               // Go to the server only if the user typed the @ character.
+                               if (selectedUser.endsWith("@"))
+                                       updateSuggestions();
+                       }
+               });
+               suggestBox.getElement().setId("addUser.textBox");
+        userTable.setWidget(0, 1, suggestBox);
+        panel.add(userTable);
+               HorizontalPanel buttons = new HorizontalPanel();
+               Button ok = new Button("OK", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               addUser();
+                               hide();
+                       }
+               });
+               ok.getElement().setId("addUser.button.ok");
+               buttons.add(ok);
+               buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);
+               // Create the 'Cancel' button, along with a listener that hides the
+               // dialog when the button is clicked.
+               Button cancel = new Button("Cancel", new ClickHandler() {
+                       @Override
+                       public void onClick(ClickEvent event) {
+                               hide();
+                       }
+               });
+               cancel.getElement().setId("addUser.button.cancel");
+               buttons.add(cancel);
+               buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
+               buttons.setSpacing(8);
+               buttons.addStyleName("gss-TabPanelBottom");
+               panel.add(buttons);
+               panel.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
+               panel.addStyleName("gss-DialogBox");
+       }
+
+       @Override
+       public void center() {
+               super.center();
+               suggestBox.setFocus(true);
+       }
+
+       @Override
+       protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+               super.onPreviewNativeEvent(preview);
+
+               NativeEvent evt = preview.getNativeEvent();
+               if (evt.getType().equals("keydown"))
+                       // Use the popup's key preview hooks to close the dialog when either
+                       // enter or escape is pressed.
+                       switch (evt.getKeyCode()) {
+                               case KeyCodes.KEY_ENTER:
+                                       addUser();
+                                       hide();
+                                       break;
+                               case KeyCodes.KEY_ESCAPE:
+                                       hide();
+                                       break;
+                       }
+       }
+
+       /**
+        * Generate a request to add a user to a group.
+        *
+        * @param groupName the name of the group to create
+        */
+       private void addUser() {
+               GroupResource group = (GroupResource) GSS.get().getCurrentSelection();
+               selectedUser = suggestBox.getText();
+               if ( group == null ) {
+                       GSS.get().displayError("Empty group name!");
+                       return;
+               }
+               if ( selectedUser == null ) {
+                       GSS.get().displayError("No User Selected!");
+                       return;
+               }
+               PostCommand cg = new PostCommand(group.getUri()+"?name="+selectedUser, "", 201){
+                       @Override
+                       public void onComplete() {
+                               GSS.get().getGroups().updateGroups();
+                               GSS.get().showUserList();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       if(statusCode == 405)
+                                               GSS.get().displayError("You don't have the necessary permissions");
+                                       else if(statusCode == 404)
+                                               GSS.get().displayError("User does not exist");
+                                       else if(statusCode == 409)
+                                               GSS.get().displayError("A user with the same name already exists");
+                                       else if(statusCode == 413)
+                                               GSS.get().displayError("Your quota has been exceeded");
+                                       else
+                                               GSS.get().displayError("Unable to add user: "+((RestException)t).getHttpStatusText());
+                               }
+                               else
+                                       GSS.get().displayError("System error adding user: "+t.getMessage());
+                       }
+               };
+               DeferredCommand.addCommand(cg);
+       }
+
+       /**
+        * Update the list of suggestions.
+        */
+       protected void updateSuggestions() {
+               final GSS app = GSS.get();
+               String query = selectedUser.substring(0, selectedUser.length()-1);
+               GWT.log("Searching for " + query, null);
+
+               GetCommand<UserSearchResource> eg = new GetCommand<UserSearchResource>(UserSearchResource.class,
+                                       app.getApiPath() + "users/" + URL.encodeComponent(query), false, null) {
+
+                       @Override
+                       public void onComplete() {
+                               suggestBox.hideSuggestionList();
+                               oracle.clear();
+                               UserSearchResource s = getResult();
+                               for (UserResource user : s.getUsers()) {
+                                       GWT.log("Found " + user.getUsername(), null);
+                                       oracle.add(user.getUsername());
+                               }
+                               suggestBox.showSuggestionList();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               if(t instanceof RestException)
+                                       app.displayError("Unable to perform search: "+((RestException)t).getHttpStatusText());
+                               else
+                                       app.displayError("System error while searching for users: "+t.getMessage());
+                               GWT.log("", t);
+                               DisplayHelper.log(t.getMessage());
+                       }
+
+               };
+               DeferredCommand.addCommand(eg);
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/UserDetailsPanel.java b/src/org/gss_project/gss/web/client/UserDetailsPanel.java
new file mode 100644 (file)
index 0000000..9e52ea4
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.IncrementalCommand;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+
+/**
+ * The panel that displays a status bar with quota information.
+ */
+public class UserDetailsPanel extends Composite {
+       public static final boolean DONE = false;
+
+       /**
+        * The label that displays user information.
+        */
+       private HTML userInfoLabel;
+
+       /**
+        * The constructor of the user details panel.
+        */
+       public UserDetailsPanel() {
+               final HorizontalPanel outer = new HorizontalPanel();
+               outer.setSpacing(8);
+               userInfoLabel = new HTML("&nbsp;");
+               outer.add(userInfoLabel);
+               outer.setCellHorizontalAlignment(userInfoLabel, HasHorizontalAlignment.ALIGN_RIGHT);
+               outer.setStyleName("statusbar-inner");
+
+               initWidget(outer);
+
+               DeferredCommand.addCommand(new IncrementalCommand() {
+
+                       @Override
+                       public boolean execute() {
+                               return displayUserInfo();
+                       }
+               });
+       }
+
+       /**
+        * Display the user information on the panel.
+        *
+        * @return true if the work has been carried out successfully
+        */
+       protected boolean displayUserInfo() {
+               UserResource user = GSS.get().getCurrentUserResource();
+               if (user == null)
+                       return !DONE;
+               userInfoLabel.setHTML("<b>" + user.getName() + " \u0387 " + user.getUsername() + "</b>");
+               GSS.get().putUserToMap(user.getUsername(), user.getName());
+               return DONE;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/VersionsList.java b/src/org/gss_project/gss/web/client/VersionsList.java
new file mode 100644 (file)
index 0000000..80cd6f9
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client;
+
+import org.gss_project.gss.web.client.FilePropertiesDialog.Images;
+import org.gss_project.gss.web.client.rest.DeleteCommand;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+/**
+ * @author kman
+ */
+public class VersionsList extends Composite {
+
+       int selectedRow = -1;
+
+       int permissionCount = -1;
+
+       List<FileResource> versions = null;
+
+       final Images images;
+
+       final VerticalPanel permPanel = new VerticalPanel();
+
+       final FlexTable permTable = new FlexTable();
+
+       FileResource toRemove = null;
+
+       FilePropertiesDialog container;
+
+       public VersionsList(FilePropertiesDialog aContainer, final Images theImages, List<FileResource> theVersions) {
+               images = theImages;
+               container = aContainer;
+               versions = theVersions;
+               Collections.sort(theVersions, new Comparator<FileResource>(){
+
+                       @Override
+                       public int compare(FileResource o1, FileResource o2) {
+                               return o1.getVersion().compareTo(o2.getVersion());
+                       }
+
+               });
+               permTable.setText(0, 0, "Version");
+               permTable.setText(0, 1, "Created");
+               permTable.setText(0, 2, "Modified");
+               permTable.setText(0, 3, "Size");
+               permTable.setText(0, 4, "");
+               permTable.setText(0, 5, "");
+               permTable.getFlexCellFormatter().setStyleName(0, 0, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 1, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 2, "props-toplabels");
+               permTable.getFlexCellFormatter().setStyleName(0, 3, "props-toplabels");
+               permTable.getFlexCellFormatter().setColSpan(0, 1, 2);
+               permTable.getFlexCellFormatter().setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER);
+               permTable.getFlexCellFormatter().setHorizontalAlignment(0, 1, HasHorizontalAlignment.ALIGN_CENTER);
+               permTable.getFlexCellFormatter().setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_CENTER);
+               permTable.getFlexCellFormatter().setHorizontalAlignment(0, 3, HasHorizontalAlignment.ALIGN_CENTER);
+               permPanel.add(permTable);
+               permPanel.addStyleName("gss-TabPanelBottom");
+               permTable.addStyleName("gss-permList");
+               initWidget(permPanel);
+               updateTable();
+       }
+
+       public void updateTable() {
+               copyListAndContinue(versions);          
+       }
+       
+       public void showVersionsTable(){
+               int i = 1;
+               if (toRemove != null) {
+                       versions.remove(toRemove);
+                       toRemove = null;
+               }
+               for (final FileResource dto : versions) {
+                       HTML restoreVersion = new HTML("<a href='#' class='hidden-link info'><span>"+AbstractImagePrototype.create(images.restore()).getHTML()+"</span><div>Restore this Version</div></a>");
+                       restoreVersion.addClickHandler(new ClickHandler() {
+                               @Override
+                               public void onClick(ClickEvent event) {
+                                       restoreVersion(dto);
+                               }
+                       });
+
+                       permTable.setHTML(i, 0, "<span>" + dto.getVersion() + "</span>");
+                       permTable.setHTML(i, 1, "<span>" + formatDate(dto.getCreationDate()) + " by " + GSS.get().findUserFullName(dto.getCreatedBy()) + "</span>");
+                       permTable.setHTML(i, 2, "<span>" + formatDate(dto.getModificationDate()) + " by " + GSS.get().findUserFullName(dto.getModifiedBy()) + "</span>");
+                       permTable.setHTML(i, 3, "<span>" + dto.getFileSizeAsString() + "</span>");
+                       HTML downloadHtml = new HTML("<a class='hidden-link info' href='#'><span>"+AbstractImagePrototype.create(images.download()).getHTML()+"</span><div>View this Version</div></a>");
+                       downloadHtml.addClickHandler(new ClickHandler() {
+                               @Override
+                               public void onClick(ClickEvent event) {
+                                       GSS app = GSS.get();
+                                       String dateString = RestCommand.getDate();
+                                       String resource = dto.getUri().substring(app.getApiPath().length()-1, dto.getUri().length());
+                                       String sig = app.getCurrentUserResource().getUsername()+" "+RestCommand.calculateSig("GET", dateString, resource, RestCommand.base64decode(app.getToken()));
+                                       String fileUrl = dto.getUri() + "?version=" + dto.getVersion() + "&Authorization=" + URL.encodeComponent(sig) + "&Date="+URL.encodeComponent(dateString);
+                                       Window.open(fileUrl, "_BLANK", "");
+                               }
+                       });
+                       permTable.setWidget(i, 4, downloadHtml);
+                       permTable.setWidget(i, 5, restoreVersion);
+                       permTable.getFlexCellFormatter().setStyleName(i, 0, "props-labels");
+                       permTable.getFlexCellFormatter().setHorizontalAlignment(i, 0, HasHorizontalAlignment.ALIGN_CENTER);
+                       permTable.getFlexCellFormatter().setHorizontalAlignment(i, 1, HasHorizontalAlignment.ALIGN_CENTER);
+                       permTable.getFlexCellFormatter().setColSpan(i, 1, 2);
+                       permTable.getFlexCellFormatter().setHorizontalAlignment(i, 2, HasHorizontalAlignment.ALIGN_CENTER);
+                       permTable.getFlexCellFormatter().setHorizontalAlignment(i, 3, HasHorizontalAlignment.ALIGN_CENTER);
+                       i++;
+               }
+               for (; i < permTable.getRowCount(); i++)
+                       permTable.removeRow(i);
+       }
+
+       void removeVersion(final FileResource version) {
+               DeleteCommand df = new DeleteCommand(version.getUri()){
+
+                       @Override
+                       public void onComplete() {
+                               toRemove = version;
+                               updateTable();
+                               GSS.get().getTreeView().refreshCurrentNode(false);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       if(statusCode == 405)
+                                               GSS.get().displayError("You don't have the necessary permissions");
+                                       else if(statusCode == 404)
+                                               GSS.get().displayError("Versions does not exist");
+                                       else
+                                               GSS.get().displayError("Unable to remove version:"+((RestException)t).getHttpStatusText());
+                               }
+                               else
+                                       GSS.get().displayError("System error removing version:"+t.getMessage());
+                       }
+               };
+               DeferredCommand.addCommand(df);
+
+       }
+
+       void restoreVersion(final FileResource version) {
+               FileResource selectedFile = (FileResource) GSS.get().getCurrentSelection();
+               PostCommand ep = new PostCommand(selectedFile.getUri()+"?restoreVersion="+version.getVersion(),"",200){
+
+
+                       @Override
+                       public void onComplete() {
+                               container.hide();
+                GSS.get().getTreeView().refreshCurrentNode(false);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException)
+                                       GSS.get().displayError("Unable to restore version:"+((RestException)t).getHttpStatusText());
+                               else
+                                       GSS.get().displayError("System error restoring version:"+t.getMessage());
+                       }
+
+               };
+               DeferredCommand.addCommand(ep);
+       }
+
+       private String formatDate(Date date){
+               DateTimeFormat format = DateTimeFormat.getFormat("dd/MM/yyyy : HH:mm");
+               return format.format(date);
+       }
+       
+       /**
+        * Copies the input List to a new List
+        * @param input
+        */
+       private void copyListAndContinue(List<FileResource> input){
+               List<FileResource> copiedInput = new ArrayList<FileResource>();         
+               for(FileResource dto : input) {
+                       copiedInput.add(dto);
+               }
+               handleFullNames(copiedInput);
+       }
+       
+       /**
+        * Examines whether or not the user's full name exists in the 
+        * userFullNameMap in the GSS.java for every element of the input list.
+        * If the user's full name does not exist in the map then a request is being made
+        * for the specific username.  
+        * 
+        * @param input
+        */
+       private void handleFullNames(List<FileResource> input){         
+               if(input.isEmpty()){
+                       showVersionsTable();
+                       return;
+               }
+               
+               if(GSS.get().findUserFullName(input.get(0).getOwner()) == null){
+                       findFullNameAndUpdate(input);           
+                       return;
+               }
+                               
+               if(input.size() >= 1){
+                       input.remove(input.get(0));
+                       if(input.isEmpty()){
+                               showVersionsTable();                    
+                       }else{
+                               handleFullNames(input);
+                       }
+               }                                       
+       }
+       
+       /**
+        * Makes a request to search for full name from a given username
+        * and continues checking the next element of the List.
+        *  
+        * @param input
+        */
+
+       private void findFullNameAndUpdate(final List<FileResource> input){                             
+               final String aUserName = input.get(0).getOwner();
+               String path = GSS.get().getApiPath() + "users/" + aUserName; 
+
+               GetCommand<UserSearchResource> gg = new GetCommand<UserSearchResource>(UserSearchResource.class, path, false,null) {
+                       @Override
+                       public void onComplete() {
+                               final UserSearchResource result = getResult();
+                               for (UserResource user : result.getUsers()){
+                                       String username = user.getUsername();
+                                       String userFullName = user.getName();
+                                       GSS.get().putUserToMap(username, userFullName);
+                                       if(input.size() >= 1){
+                                               input.remove(input.get(0));                                             
+                                               if(input.isEmpty()){
+                                                       showVersionsTable();
+                                                       return;
+                                               }
+                                               handleFullNames(input);                                                                         
+                                       }                                                                       
+                               }
+                       }
+                       @Override
+                       public void onError(Throwable t) {                              
+                               GSS.get().displayError("Unable to fetch user's full name from the given username " + aUserName);
+                               if(input.size() >= 1){
+                                       input.remove(input.get(0));
+                                       handleFullNames(input);                                 
+                               }
+                       }
+               };
+               DeferredCommand.addCommand(gg);
+       
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/animation/FadeIn.java b/src/org/gss_project/gss/web/client/animation/FadeIn.java
new file mode 100644 (file)
index 0000000..5da4f7f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008, 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.animation;
+
+import com.google.gwt.animation.client.Animation;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+
+
+/**
+ * @author kman
+ *
+ */
+public class FadeIn extends Animation {
+       Widget widget;
+       int initialOpacity = 100;
+       double currOpacity = 100;
+
+       public FadeIn(Widget aWidget){
+               widget = aWidget;
+       }
+
+       @Override
+       protected void onUpdate(double progress) {
+               if(currOpacity > 0.0){
+                       progress = 1.0 - progress;
+                       currOpacity = initialOpacity * progress;
+                       DOM.setStyleAttribute(widget.getElement(), "opacity", ""+new Double(1d - currOpacity / 100d));
+                       //required for ie to work
+                       //Disabled because IE has bugs rendering non-opaque objects
+                       //int opacityToSet = new Double(currOpacity).intValue();
+                       //DOM.setStyleAttribute(widget.getElement(), "filter", "alpha(opacity=" + (initialOpacity - opacityToSet) + ")");
+               }
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/animation/FadeOut.java b/src/org/gss_project/gss/web/client/animation/FadeOut.java
new file mode 100644 (file)
index 0000000..17f6391
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008, 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.animation;
+
+import com.google.gwt.animation.client.Animation;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+
+
+/**
+ * @author kman
+ *
+ */
+public class FadeOut extends Animation {
+       Widget widget;
+
+       int initialOpacity = 100;
+       double currOpacity = 100;
+
+       public FadeOut(Widget aWidget){
+               widget = aWidget;
+       }
+
+       @Override
+       protected void onUpdate(double progress) {
+               if(currOpacity>0.0){
+                       progress = 1.0 - progress;
+                       currOpacity = initialOpacity*progress;
+                       DOM.setStyleAttribute(widget.getElement(), "opacity", ""+new Double(currOpacity/100d));
+                       //required for ie to work
+                       //Disabled because IE has bugs rendering non-opaque objects
+                       //int opacityToSet = new Double(currOpacity).intValue();
+                       //DOM.setStyleAttribute(widget.getElement(), "filter", "alpha(opacity="+currOpacity+")");
+               }
+       }
+
+       /*
+       protected void onComplete() {
+               super.onComplete();
+               hpanel.clear();
+               html = new HTML("&nbsp;");
+               hpanel.getParent().setVisible(false);
+       }
+       */
+
+}
diff --git a/src/org/gss_project/gss/web/client/cellTreeClosedItem.gif b/src/org/gss_project/gss/web/client/cellTreeClosedItem.gif
new file mode 100644 (file)
index 0000000..9051e56
Binary files /dev/null and b/src/org/gss_project/gss/web/client/cellTreeClosedItem.gif differ
diff --git a/src/org/gss_project/gss/web/client/cellTreeLoadingBasic.gif b/src/org/gss_project/gss/web/client/cellTreeLoadingBasic.gif
new file mode 100644 (file)
index 0000000..c5fedc3
Binary files /dev/null and b/src/org/gss_project/gss/web/client/cellTreeLoadingBasic.gif differ
diff --git a/src/org/gss_project/gss/web/client/cellTreeOpenItem.gif b/src/org/gss_project/gss/web/client/cellTreeOpenItem.gif
new file mode 100644 (file)
index 0000000..3d3691a
Binary files /dev/null and b/src/org/gss_project/gss/web/client/cellTreeOpenItem.gif differ
diff --git a/src/org/gss_project/gss/web/client/clipboard/Clipboard.java b/src/org/gss_project/gss/web/client/clipboard/Clipboard.java
new file mode 100644 (file)
index 0000000..2a6b747
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.clipboard;
+
+
+/**
+ * @author koutsoub
+ *
+ */
+public class Clipboard {
+       public final static int CUT=1;
+       public final static int COPY=2;
+       private ClipboardItem item;
+
+       /**
+        * Retrieve the item.
+        *
+        * @return the item
+        */
+       public ClipboardItem getItem() {
+               return item;
+       }
+
+       /**
+        * Modify the item.
+        *
+        * @param anItem the item to set
+        */
+       public void setItem(ClipboardItem anItem) {
+               item = anItem;
+       }
+
+       public boolean hasFolderOrFileItem(){
+               if( item !=null )
+                       return item.isFileOrFolder();
+               return false;
+       }
+
+       public boolean hasFileItem(){
+               if( item !=null )
+                       return item.isFile();
+               return false;
+       }
+
+       public boolean hasUserItem(){
+               if( item !=null )
+                       return item.isUser();
+               return false;
+       }
+
+       public boolean isEmpty(){
+               return item == null;
+       }
+
+       public void clear(){
+               item = null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/clipboard/ClipboardItem.java b/src/org/gss_project/gss/web/client/clipboard/ClipboardItem.java
new file mode 100644 (file)
index 0000000..2a19b14
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.clipboard;
+
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+/**
+ * @author kman
+ *
+ */
+public class ClipboardItem implements Serializable{
+       private int operation;
+       private FileResource file;
+       private List<FileResource> files;
+       private RestResourceWrapper folderResource;
+       private GroupUserResource user;
+
+       public ClipboardItem(){}
+
+       public ClipboardItem(int anOperation, List<FileResource> theFiles){
+               operation = anOperation;
+               files = theFiles;
+       }
+
+       public ClipboardItem(int anOperation, FileResource aFile){
+               operation = anOperation;
+               file = aFile;
+       }
+
+       public ClipboardItem(int anOperation, RestResourceWrapper folder){
+               operation = anOperation;
+               folderResource = folder;
+       }
+       public ClipboardItem(int anOperation, GroupUserResource aUser){
+               operation = anOperation;
+               user = aUser;
+       }
+
+       public ClipboardItem(GroupUserResource aUser){
+               operation = Clipboard.COPY;
+               user = aUser;
+       }
+
+       public ClipboardItem(List<FileResource> theFiles){
+               operation = Clipboard.COPY;
+               files = theFiles;
+       }
+
+       public ClipboardItem(FileResource aFile){
+               operation = Clipboard.COPY;
+               file = aFile;
+       }
+
+       public ClipboardItem(RestResourceWrapper folder){
+               operation = Clipboard.COPY;
+               folderResource = folder;
+       }
+
+       /**
+        * Retrieve the user.
+        *
+        * @return the user
+        */
+       public GroupUserResource getUser() {
+               return user;
+       }
+
+       /**
+        * Modify the user.
+        *
+        * @param aUser the user to set
+        */
+       public void setUser(GroupUserResource aUser) {
+               user = aUser;
+       }
+
+       /**
+        * Retrieve the operation.
+        *
+        * @return the operation
+        */
+       public int getOperation() {
+               return operation;
+       }
+
+       /**
+        * Modify the operation.
+        *
+        * @param anOperation the operation to set
+        */
+       public void setOperation(int anOperation) {
+               operation = anOperation;
+       }
+
+       /**
+        * Retrieve the file.
+        *
+        * @return the file
+        */
+       public FileResource getFile() {
+               return file;
+       }
+
+       /**
+        * Modify the file.
+        *
+        * @param aFile the file to set
+        */
+       public void setFile(FileResource aFile) {
+               file = aFile;
+       }
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<FileResource> getFiles() {
+               return files;
+       }
+
+       /**
+        * checks whether the clipboard item is a file or folder
+        */
+       public boolean isFileOrFolder(){
+               if(file !=null || files != null || folderResource != null)
+                       return true;
+               return false;
+       }
+
+       /**
+        * checks whether the clipboard item is a file (or files)
+        */
+       public boolean isFile() {
+               if(file !=null || files != null)
+                       return true;
+               return false;
+       }
+
+       public boolean isUser(){
+               if( user!=null  )
+                       return true;
+               return false;
+       }
+
+       /**
+        * Retrieve the folderResource.
+        *
+        * @return the folderResource
+        */
+       public RestResourceWrapper getRestResourceWrapper() {
+               return folderResource;
+       }
+
+       /**
+        * Modify the folderResource.
+        *
+        * @param aFolder the folderResource to set
+        */
+       public void setRestResourceWrapper(RestResourceWrapper aFolder) {
+               folderResource = aFolder;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/commands/CopyCommand.java b/src/org/gss_project/gss/web/client/commands/CopyCommand.java
new file mode 100644 (file)
index 0000000..50c38b5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.clipboard.ClipboardItem;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.List;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+/**
+ *
+ * Command for copying a file, folder or user to GSS Clipboard
+ * @author kman
+ *
+ */
+public class CopyCommand implements Command{
+       private PopupPanel containerPanel;
+
+       public CopyCommand(PopupPanel _containerPanel){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               Object selection = GSS.get().getCurrentSelection();
+               if (selection == null)
+                       return;
+
+               if (selection instanceof RestResourceWrapper) {
+                       ClipboardItem clipboardItem = new ClipboardItem((RestResourceWrapper) selection);
+                       GSS.get().getClipboard().setItem(clipboardItem);
+               } else if (selection instanceof FileResource) {
+                       ClipboardItem clipboardItem = new ClipboardItem((FileResource) selection);
+                       GSS.get().getClipboard().setItem(clipboardItem);
+               } else if (selection instanceof GroupUserResource) {
+                       ClipboardItem clipboardItem = new ClipboardItem((GroupUserResource) selection);
+                       GSS.get().getClipboard().setItem(clipboardItem);
+               }
+                else if (selection instanceof List){
+                        ClipboardItem clipboardItem = new ClipboardItem((List<FileResource>) selection);
+                        GSS.get().getClipboard().setItem(clipboardItem);
+                }
+
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/CutCommand.java b/src/org/gss_project/gss/web/client/commands/CutCommand.java
new file mode 100644 (file)
index 0000000..ddccef2
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.clipboard.Clipboard;
+import org.gss_project.gss.web.client.clipboard.ClipboardItem;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * Command for cutting a file, folder or user to GSS Clipboard
+ * @author kman
+ *
+ */
+public class CutCommand implements Command{
+       private PopupPanel containerPanel;
+
+       public CutCommand( PopupPanel _containerPanel ){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               Object selection = GSS.get().getCurrentSelection();
+               if (selection == null)
+                       return;
+               GWT.log("selection: " + selection.toString(), null);
+               if (selection instanceof RestResourceWrapper) {
+                       ClipboardItem clipboardItem = new ClipboardItem(Clipboard.CUT, (RestResourceWrapper) selection);
+                       GSS.get().getClipboard().setItem(clipboardItem);
+               } else if (selection instanceof FileResource) {
+                       ClipboardItem clipboardItem = new ClipboardItem(Clipboard.CUT, (FileResource) selection);
+                       GSS.get().getClipboard().setItem(clipboardItem);
+               } else if (selection instanceof GroupUserResource) {
+                       ClipboardItem clipboardItem = new ClipboardItem(Clipboard.CUT, (GroupUserResource) selection);
+                       GSS.get().getClipboard().setItem(clipboardItem);
+               }
+               else if (selection instanceof List){
+                        ClipboardItem clipboardItem = new ClipboardItem(Clipboard.CUT, (List<FileResource>) selection);
+                        GSS.get().getClipboard().setItem(clipboardItem);
+                }
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/DeleteCommand.java b/src/org/gss_project/gss/web/client/commands/DeleteCommand.java
new file mode 100644 (file)
index 0000000..03766ee
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.DeleteFileDialog;
+import org.gss_project.gss.web.client.DeleteFolderDialog;
+import org.gss_project.gss.web.client.DeleteGroupDialog;
+import org.gss_project.gss.web.client.EditMenu.Images;
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * Delete selected object command
+ * @author kman
+ *
+ */
+public class DeleteCommand implements Command{
+       private PopupPanel containerPanel;
+       final Images newImages;
+
+       /**
+        * @param _containerPanel
+        * @param _newImages the images of all the possible delete dialogs
+        */
+       public DeleteCommand( PopupPanel _containerPanel, final Images _newImages ){
+               containerPanel = _containerPanel;
+               newImages=_newImages;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               displayDelete();
+       }
+       /**
+        * Display the delete dialog, according to the selected object.
+        *
+        *
+        */
+       void displayDelete() {
+               Object selection = GSS.get().getCurrentSelection();
+               if (selection == null)
+                       return;
+               GWT.log("selection: " + selection.toString(), null);
+               if (selection instanceof RestResourceWrapper) {
+                       DeleteFolderDialog dlg = new DeleteFolderDialog(newImages);
+                       dlg.center();
+               } else if (selection instanceof FileResource || selection instanceof List) {
+                       DeleteFileDialog dlg = new DeleteFileDialog(newImages);
+                       dlg.center();
+               } else if (selection instanceof GroupUserResource) {
+                       // TODO implement user deletion
+               } else if (selection instanceof GroupResource) {
+                       DeleteGroupDialog dlg = new DeleteGroupDialog(newImages);
+                       dlg.center();
+               }
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/commands/DeleteUserOrGroupCommand.java b/src/org/gss_project/gss/web/client/commands/DeleteUserOrGroupCommand.java
new file mode 100644 (file)
index 0000000..4a8626d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.DeleteGroupDialog;
+import org.gss_project.gss.web.client.DeleteUserDialog;
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.Groups.Images;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class DeleteUserOrGroupCommand implements Command{
+       private PopupPanel containerPanel;
+       final Images images;
+
+       /**
+        * @param aContainerPanel
+        * @param newImages the images of the new folder dialog
+        */
+       public DeleteUserOrGroupCommand(PopupPanel aContainerPanel, final Images newImages){
+               containerPanel = aContainerPanel;
+               images = newImages;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               if(GSS.get().getCurrentSelection() instanceof GroupResource)
+                       displayNewGroup();
+               else if(GSS.get().getCurrentSelection() instanceof GroupUserResource)
+                       displayNewUser();
+               else
+                       GSS.get().displayError("No user or group selected");
+       }
+
+       void displayNewGroup() {
+               DeleteGroupDialog dlg = new DeleteGroupDialog(images);
+               dlg.center();
+       }
+
+       void displayNewUser() {
+               DeleteUserDialog dlg = new DeleteUserDialog(images);
+               dlg.center();
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/EmptyTrashCommand.java b/src/org/gss_project/gss/web/client/commands/EmptyTrashCommand.java
new file mode 100644 (file)
index 0000000..4212cd4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.DeleteCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * Command to empty trash bin.
+ *
+ * @author kman
+ */
+public class EmptyTrashCommand implements Command{
+       private PopupPanel containerPanel;
+
+       public EmptyTrashCommand(PopupPanel _containerPanel){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               DeleteCommand df = new DeleteCommand(GSS.get().getTreeView().getTrash().getUri()){
+
+                       @Override
+                       public void onComplete() {
+                               GSS.get().getTreeView().updateTrashNode();
+                               GSS.get().showFileList(true);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       if(statusCode == 405)
+                                               GSS.get().displayError("You don't have the necessary permissions");
+                                       else if(statusCode == 404)
+                                               GSS.get().displayError("Resource does not exist");
+                                       else
+                                               GSS.get().displayError("Unable to empty trash:"+((RestException)t).getHttpStatusText());
+                               }
+                               else
+                                       GSS.get().displayError("System error emptying trash:"+t.getMessage());
+                       }
+               };
+               DeferredCommand.addCommand(df);
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/GetUserCommand.java b/src/org/gss_project/gss/web/client/commands/GetUserCommand.java
new file mode 100644 (file)
index 0000000..efbed03
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+
+
+/**
+ * This command manages usernames and the corresponding user's Full Name
+ * along with the HashMap collection in the GSS.java class
+ *
+ * @author natasa
+ *
+ */
+public class GetUserCommand implements Command{
+
+       /**
+        * User's username e.g johndoe@somewhere.com
+        */
+       private String userName;
+
+       public GetUserCommand(String _userName){
+               userName = _userName;
+       }
+
+       @Override
+       public void execute() {
+               String path = GSS.get().getApiPath() + "users/" + userName; 
+               GetCommand<UserSearchResource> gg = new GetCommand<UserSearchResource>(UserSearchResource.class,
+                                       path, false ,null) {
+                       @Override
+                       public void onComplete() {
+                               final UserSearchResource result = getResult();
+                               for (UserResource user : result.getUsers()){
+                                       String username = user.getUsername();
+                                       String _userFullName = user.getName();
+                                       GSS.get().putUserToMap(username, _userFullName);
+                               }
+                       }
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               GSS.get().displayError("Unable to fetch user's full name from the given username " + userName);
+                       }
+               };
+               DeferredCommand.addCommand(gg);
+
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/NewFolderCommand.java b/src/org/gss_project/gss/web/client/commands/NewFolderCommand.java
new file mode 100644 (file)
index 0000000..f848db7
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.FileMenu.Images;
+import org.gss_project.gss.web.client.FolderPropertiesDialog;
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupsResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.IncrementalCommand;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * Display the 'new folder' dialog for creating a new folder.
+ * @author kman
+ *
+ */
+public class NewFolderCommand implements Command{
+       private PopupPanel containerPanel;
+       final Images images;
+
+       private List<GroupResource> groups = null;
+
+       /**
+        * @param aContainerPanel
+        * @param newImages the images of the new folder dialog
+        */
+       public NewFolderCommand(PopupPanel aContainerPanel, final Images newImages){
+               containerPanel = aContainerPanel;
+               images=newImages;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               getGroups();
+               DeferredCommand.addCommand(new IncrementalCommand() {
+
+                       @Override
+                       public boolean execute() {
+                               boolean res = canContinue();
+                               if (res) {
+                                       displayNewFolder();
+                                       return false;
+                               }
+                               return true;
+                       }
+
+               });
+       }
+
+       private boolean canContinue() {
+               if (groups == null)
+                       return false;
+               return true;
+       }
+
+       void displayNewFolder() {
+               RestResource currentFolder = GSS.get().getTreeView().getSelection();
+               if (currentFolder == null) {
+                       GSS.get().displayError("You have to select the parent folder first");
+                       return;
+               }
+               FolderPropertiesDialog dlg = new FolderPropertiesDialog(images, true,  groups);
+               dlg.center();
+       }
+
+       private void getGroups() {
+               GetCommand<GroupsResource> gg = new GetCommand<GroupsResource>(GroupsResource.class, GSS.get().getCurrentUserResource().getGroupsPath(), null){
+
+                       @Override
+                       public void onComplete() {
+                               GroupsResource res = getResult();
+                               MultipleGetCommand<GroupResource> ga = new MultipleGetCommand<GroupResource>(GroupResource.class, res.getGroupPaths().toArray(new String[]{}), null){
+
+                                       @Override
+                                       public void onComplete() {
+                                               List<GroupResource> groupList = getResult();
+                                               groups = groupList;
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("", t);
+                                               GSS.get().displayError("Unable to fetch groups");
+                                               groups = new ArrayList<GroupResource>();
+                                       }
+
+                                       @Override
+                                       public void onError(String p, Throwable throwable) {
+                                               GWT.log("Path:"+p, throwable);
+                                       }
+                               };
+                               DeferredCommand.addCommand(ga);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               GSS.get().displayError("Unable to fetch groups");
+                               groups = new ArrayList<GroupResource>();
+                       }
+               };
+               DeferredCommand.addCommand(gg);
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/NewGroupCommand.java b/src/org/gss_project/gss/web/client/commands/NewGroupCommand.java
new file mode 100644 (file)
index 0000000..893f91e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GroupPropertiesDialog;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class NewGroupCommand implements Command{
+       private PopupPanel containerPanel;
+
+       /**
+        * @param _containerPanel
+        */
+       public NewGroupCommand(PopupPanel _containerPanel){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               displayNewGroup();
+       }
+
+       void displayNewGroup() {
+               GroupPropertiesDialog dlg = new GroupPropertiesDialog(true);
+               dlg.center();
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/NewUserCommand.java b/src/org/gss_project/gss/web/client/commands/NewUserCommand.java
new file mode 100644 (file)
index 0000000..2906cad
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.UserAddDialog;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class NewUserCommand implements Command {
+       private PopupPanel containerPanel;
+
+       /**
+        * @param _containerPanel
+        */
+       public NewUserCommand(PopupPanel _containerPanel){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               displayNewUser();
+       }
+
+       private void displayNewUser() {
+               UserAddDialog dlg = new UserAddDialog();
+               dlg.center();
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/PasteCommand.java b/src/org/gss_project/gss/web/client/commands/PasteCommand.java
new file mode 100644 (file)
index 0000000..e345c01
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.clipboard.Clipboard;
+import org.gss_project.gss.web.client.clipboard.ClipboardItem;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * @author kman Command for pasting Clipboard contents
+ */
+public class PasteCommand implements Command {
+
+       private PopupPanel containerPanel;
+
+       public PasteCommand(PopupPanel _containerPanel) {
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               Object selection = GSS.get().getCurrentSelection();
+               if(selection != null && selection instanceof GroupResource){
+                       final ClipboardItem citem = GSS.get().getClipboard().getItem();
+                       GroupResource group = (GroupResource) GSS.get().getCurrentSelection();
+                       if(citem.getUser() != null){
+                               PostCommand cg = new PostCommand(group.getUri()+"?name="+citem.getUser().getUsername(), "", 201){
+
+                                       @Override
+                                       public void onComplete() {
+                                               GSS.get().getGroups().updateGroups();
+                                               GSS.get().showUserList();
+                                               GSS.get().getClipboard().setItem(null);
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("", t);
+                                               if(t instanceof RestException){
+                                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                                       if(statusCode == 405)
+                                                               GSS.get().displayError("You don't have the necessary permissions");
+                                                       else if(statusCode == 404)
+                                                               GSS.get().displayError("User does not exist");
+                                                       else if(statusCode == 409)
+                                                               GSS.get().displayError("A user with the same name already exists");
+                                                       else if(statusCode == 413)
+                                                               GSS.get().displayError("Your quota has been exceeded");
+                                                       else
+                                                               GSS.get().displayError("Unable to add user:"+((RestException)t).getHttpStatusText());
+                                               }
+                                               else
+                                                       GSS.get().displayError("System error adding user:"+t.getMessage());
+                                       }
+                               };
+                               DeferredCommand.addCommand(cg);
+                               return;
+                       }
+               }
+               FolderResource selectedFolder = null;
+               if(selection != null && selection instanceof RestResourceWrapper)
+                       selectedFolder = ((RestResourceWrapper)selection).getResource();
+               //TODO:CELLTREE
+               /*
+               else if(GSS.get().getFolders().getCurrent() != null && ((DnDTreeItem)GSS.get().getFolders().getCurrent()).getFolderResource() != null)
+                       selectedFolder = ((DnDTreeItem)GSS.get().getFolders().getCurrent()).getFolderResource();
+               */
+               if (selectedFolder != null) {
+                       final ClipboardItem citem = GSS.get().getClipboard().getItem();
+                       if (citem != null && citem.getRestResourceWrapper() != null) {
+                               String target = selectedFolder.getUri();
+                               target = target.endsWith("/") ? target : target + '/';
+                               target = target + URL.encodeComponent(citem.getRestResourceWrapper().getResource().getName());
+                               if (citem.getOperation() == Clipboard.COPY) {
+                                       PostCommand cf = new PostCommand(citem.getRestResourceWrapper().getUri() + "?copy=" + target, "", 200) {
+
+                                               @Override
+                                               public void onComplete() {
+                                                       //TODO:CELLTREE
+                                                       //GSS.get().getFolders().updateFolder((DnDTreeItem) GSS.get().getFolders().getCurrent());
+                                                       GSS.get().getTreeView().updateNodeChildren(GSS.get().getTreeView().getSelection());
+                                                       GSS.get().getStatusPanel().updateStats();
+                                                       GSS.get().getClipboard().setItem(null);
+                                               }
+
+                                               @Override
+                                               public void onError(Throwable t) {
+                                                       GWT.log("", t);
+                                                       if(t instanceof RestException){
+                                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                                               if(statusCode == 405)
+                                                                       GSS.get().displayError("You don't have the necessary permissions");
+
+                                                               else if(statusCode == 409)
+                                                                       GSS.get().displayError("A folder with the same name already exists");
+                                                               else if(statusCode == 413)
+                                                                       GSS.get().displayError("Your quota has been exceeded");
+                                                               else
+                                                                       GSS.get().displayError("Unable to copy folder:"+((RestException)t).getHttpStatusText());
+                                                       }
+                                                       else
+                                                               GSS.get().displayError("System error copying folder:"+t.getMessage());
+                                               }
+                                       };
+                                       DeferredCommand.addCommand(cf);
+                               } else if (citem.getOperation() == Clipboard.CUT) {
+                                       PostCommand cf = new PostCommand(citem.getRestResourceWrapper().getUri() + "?move=" + target, "", 200) {
+
+                                               @Override
+                                               public void onComplete() {
+                                                       //TODO:CELLTREE
+                                                       /*
+                                                       List<TreeItem> items = GSS.get().getFolders().getItemsOfTreeForPath(citem.getFolderResource().getUri());
+                                                       for (TreeItem item : items)
+                                                               if (item.getParentItem() != null && !item.equals(GSS.get().getFolders().getCurrent()))
+                                                                       GSS.get().getFolders().updateFolder((DnDTreeItem) item.getParentItem());
+                                                       GSS.get().getFolders().updateFolder((DnDTreeItem) GSS.get().getFolders().getCurrent());
+                                                       */
+                                                       GSS.get().getTreeView().updateNodeChildren(GSS.get().getTreeView().getSelection());
+                                                       GSS.get().getTreeView().updateNodeChildrenForRemove(citem.getRestResourceWrapper().getResource().getParentURI());
+                                                       GSS.get().getStatusPanel().updateStats();               
+                                                       GSS.get().getClipboard().setItem(null);
+                                               }
+
+                                               @Override
+                                               public void onError(Throwable t) {
+                                                       GWT.log("", t);
+                                                       if(t instanceof RestException){
+                                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                                               if(statusCode == 405)
+                                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                                               else if(statusCode == 409)
+                                                                       GSS.get().displayError("A folder with the same name already exists");
+                                                               else if(statusCode == 413)
+                                                                       GSS.get().displayError("Your quota has been exceeded");
+                                                               else
+                                                                       GSS.get().displayError("Unable to move folder:"+((RestException)t).getHttpStatusText());
+                                                       }
+                                                       else
+                                                               GSS.get().displayError("System error moving folder:"+t.getMessage());
+                                               }
+                                       };
+                                       DeferredCommand.addCommand(cf);
+                               }
+                               return;
+                       } else if (citem != null && citem.getFile() != null) {
+                               String target = selectedFolder.getUri();
+                               target = target.endsWith("/") ? target : target + '/';
+                               target = target + URL.encodeComponent(citem.getFile().getName());
+                               if (citem.getOperation() == Clipboard.COPY) {
+                                       PostCommand cf = new PostCommand(citem.getFile().getUri() + "?copy=" + target, "", 200) {
+
+                                               @Override
+                                               public void onComplete() {
+                                                       GSS.get().showFileList(true);
+                                                       GSS.get().getStatusPanel().updateStats();
+                                                       GSS.get().getClipboard().setItem(null);
+                                               }
+
+                                               @Override
+                                               public void onError(Throwable t) {
+                                                       GWT.log("", t);
+                                                       if(t instanceof RestException){
+                                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                                               if(statusCode == 405)
+                                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                                               else if(statusCode == 404)
+                                                                       GSS.get().displayError("File not found");
+                                                               else if(statusCode == 409)
+                                                                       GSS.get().displayError("A file with the same name already exists");
+                                                               else if(statusCode == 413)
+                                                                       GSS.get().displayError("Your quota has been exceeded");
+                                                               else
+                                                                       GSS.get().displayError("Unable to copy file:"+((RestException)t).getHttpStatusText());
+                                                       }
+                                                       else
+                                                               GSS.get().displayError("System error copying file:"+t.getMessage());
+                                               }
+                                       };
+                                       DeferredCommand.addCommand(cf);
+                               } else if (citem.getOperation() == Clipboard.CUT) {
+                                       PostCommand cf = new PostCommand(citem.getFile().getUri() + "?move=" + target, "", 200) {
+
+                                               @Override
+                                               public void onComplete() {
+                                                       GSS.get().showFileList(true);
+                                                       GSS.get().getStatusPanel().updateStats();
+                                                       GSS.get().getClipboard().setItem(null);
+                                               }
+
+                                               @Override
+                                               public void onError(Throwable t) {
+                                                       GWT.log("", t);
+                                                       if(t instanceof RestException){
+                                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                                               if(statusCode == 405)
+                                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                                               else if(statusCode == 404)
+                                                                       GSS.get().displayError("File not found");
+                                                               else if(statusCode == 409)
+                                                                       GSS.get().displayError("A file with the same name already exists");
+                                                               else if(statusCode == 413)
+                                                                       GSS.get().displayError("Your quota has been exceeded");
+                                                               else
+                                                                       GSS.get().displayError("Unable to copy file:"+((RestException)t).getHttpStatusText());
+                                                       }
+                                                       else
+                                                               GSS.get().displayError("System error copying file:"+t.getMessage());
+                                               }
+                                       };
+                                       DeferredCommand.addCommand(cf);
+                               }
+                               return;
+                       } else if (citem != null && citem.getFiles() != null) {
+                               List<FileResource> res = citem.getFiles();
+                               List<String> fileIds = new ArrayList<String>();
+                               String target = selectedFolder.getUri();
+                               target = target.endsWith("/") ? target : target + '/';
+
+                               if (citem.getOperation() == Clipboard.COPY) {
+                                       for (FileResource fileResource : res) {
+                                               String fileTarget = target + fileResource.getName();
+                                               fileIds.add(fileResource.getUri() + "?copy=" + fileTarget);
+                                       }
+                                       int index = 0;
+                                       executeCopyOrMove(index, fileIds);
+
+                               } else if (citem.getOperation() == Clipboard.CUT) {
+                                       for (FileResource fileResource : res) {
+                                               String fileTarget = target + fileResource.getName();
+                                               fileIds.add(fileResource.getUri() + "?move=" + fileTarget);
+                                       }
+                                       int index = 0;
+                                       executeCopyOrMove(index, fileIds);
+                               }
+                               return;
+                       }
+               }
+       }
+
+       private void executeCopyOrMove(final int index, final List<String> paths){
+               if(index >= paths.size()){
+                       GSS.get().showFileList(true);
+                       GSS.get().getStatusPanel().updateStats();
+                       GSS.get().getClipboard().setItem(null);
+                       return;
+               }
+               PostCommand cf = new PostCommand(paths.get(index), "", 200) {
+
+                       @Override
+                       public void onComplete() {
+                               executeCopyOrMove(index+1, paths);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               if(t instanceof RestException){
+                                       int statusCode = ((RestException)t).getHttpStatusCode();
+                                       if(statusCode == 405)
+                                               GSS.get().displayError("You don't have the necessary permissions");
+                                       else if(statusCode == 404)
+                                               GSS.get().displayError("File not found");
+                                       else if(statusCode == 409)
+                                               GSS.get().displayError("A file with the same name already exists");
+                                       else if(statusCode == 413)
+                                               GSS.get().displayError("Your quota has been exceeded");
+                                       else
+                                               GSS.get().displayError("Unable to copy file:"+((RestException)t).getHttpStatusText());
+                               }
+                               else
+                                       GSS.get().displayError("System error copying file:"+t.getMessage());
+                       }
+               };
+               DeferredCommand.addCommand(cf);
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/commands/PropertiesCommand.java b/src/org/gss_project/gss/web/client/commands/PropertiesCommand.java
new file mode 100644 (file)
index 0000000..c0613de
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.FileMenu;
+import org.gss_project.gss.web.client.FilePropertiesDialog;
+import org.gss_project.gss.web.client.FilesPropertiesDialog;
+import org.gss_project.gss.web.client.FolderPropertiesDialog;
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.FileMenu.Images;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.HeadCommand;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand;
+import org.gss_project.gss.web.client.rest.MultipleHeadCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand.Cached;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupsResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.IncrementalCommand;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * The command that displays the appropriate Properties dialog, according to the
+ * selected object in the application.
+ *
+ * @author kman
+ */
+public class PropertiesCommand implements Command {
+
+       final FileMenu.Images newImages;
+
+       private PopupPanel containerPanel;
+
+       private List<GroupResource> groups = null;
+
+       private List<FileResource> versions = null;
+
+       private int tabToShow = 0;
+
+       private String userName;
+
+       /**
+        * @param _containerPanel
+        * @param _newImages the images of all the possible delete dialogs
+        * @param _tab the tab to switch to
+        */
+       public PropertiesCommand(PopupPanel _containerPanel, final FileMenu.Images _newImages, int _tab) {
+               containerPanel = _containerPanel;
+               newImages = _newImages;
+               tabToShow = _tab;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               if (GSS.get().getCurrentSelection() instanceof RestResourceWrapper) {
+                       GetCommand<FolderResource> eg = new GetCommand<FolderResource>(FolderResource.class, ((RestResourceWrapper) GSS.get().getCurrentSelection()).getUri(),((RestResourceWrapper) GSS.get().getCurrentSelection()).getResource()) {
+
+                               @Override
+                               public void onComplete() {
+                                       ((RestResourceWrapper) GSS.get().getCurrentSelection()).setResource(getResult());
+                                       initialize();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+
+                               }
+
+                       };
+                       DeferredCommand.addCommand(eg);
+               }
+               else if (GSS.get().getCurrentSelection() instanceof FileResource) {
+                       final String path = ((FileResource) GSS.get().getCurrentSelection()).getUri();
+                       // Needed because firefox caches head requests.
+                       HeadCommand<FileResource> eg = new HeadCommand<FileResource>(FileResource.class, path+"?"+Math.random(), null ) {
+
+                               @Override
+                               public void onComplete() {
+                                       FileResource res = getResult();
+                                       GSS.get().setCurrentSelection(res);
+                                       initialize();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       if(t instanceof RestException)
+                                               GSS.get().displayError("Unable to retrieve file details:"+((RestException)t).getHttpStatusText());
+                               }
+
+                       };
+                       DeferredCommand.addCommand(eg);
+               }
+               else if (GSS.get().getCurrentSelection() instanceof List) {
+                       List<String> paths = new ArrayList<String>();
+                       for (FileResource fr : (List<FileResource>) GSS.get().getCurrentSelection())
+                               paths.add(fr.getUri()+"?"+Math.random());
+                       Cached[] cached = new Cached[paths.size()];
+                       int i=0;
+                       for (FileResource fr : (List<FileResource>) GSS.get().getCurrentSelection()){
+                               Cached c = new Cached();
+                               c.uri=fr.getUri()+"?"+Math.random();
+                               c.cache=fr;
+                               cached[i]=c;
+                               i++;
+                       }
+                       MultipleHeadCommand<FileResource> gv = new MultipleHeadCommand<FileResource>(FileResource.class, paths.toArray(new String[] {}),cached) {
+
+                               @Override
+                               public void onComplete() {
+                                       List<FileResource> res = getResult();
+                                       GSS.get().setCurrentSelection(res);
+                                       FilesPropertiesDialog dlg = new FilesPropertiesDialog(res);
+                                       dlg.selectTab(tabToShow);
+                                       dlg.center();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("", t);
+                                       GSS.get().displayError("Unable to fetch files details");
+                               }
+
+                               @Override
+                               public void onError(String p, Throwable throwable) {
+                                       GWT.log("Path:" + p, throwable);
+                               }
+                       };
+                       DeferredCommand.addCommand(gv);
+               }
+       }
+
+       private void initialize(){
+               getGroups();
+               getVersions();
+               getOwnerFullName();
+               DeferredCommand.addCommand(new IncrementalCommand() {
+
+                       @Override
+                       public boolean execute() {
+                               boolean res = canContinue();
+                               if (res) {
+                                       displayProperties(newImages, GSS.get().findUserFullName(userName));
+                                       return false;
+                               }
+                               return true;
+                       }
+
+               });
+
+       }
+
+       private boolean canContinue() {
+               String userFullNameFromMap = GSS.get().findUserFullName(userName);
+               if(groups == null || versions == null || userFullNameFromMap == null)
+                       return false;
+               return true;
+       }
+
+       /**
+        * Display the appropriate Properties dialog, according to the selected
+        * object in the application.
+        *
+        * @param propImages the images of all the possible properties dialogs
+        */
+       void displayProperties(final Images propImages, final String _userName) {
+               if (GSS.get().getCurrentSelection() instanceof RestResourceWrapper) {
+                       FolderPropertiesDialog dlg = new FolderPropertiesDialog(propImages, false, groups);
+                       dlg.selectTab(tabToShow);
+                       dlg.center();
+               } else if (GSS.get().getCurrentSelection() instanceof FileResource) {
+                       FilePropertiesDialog dlg = new FilePropertiesDialog(propImages, groups, versions, _userName);
+                       dlg.selectTab(tabToShow);
+                       dlg.center();
+               }
+       }
+
+       private void getGroups() {
+               GetCommand<GroupsResource> gg = new GetCommand<GroupsResource>(GroupsResource.class, GSS.get().getCurrentUserResource().getGroupsPath(), null) {
+
+                       @Override
+                       public void onComplete() {
+                               GroupsResource res = getResult();
+                               MultipleGetCommand<GroupResource> ga = new MultipleGetCommand<GroupResource>(GroupResource.class, res.getGroupPaths().toArray(new String[] {}), null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               List<GroupResource> groupList = getResult();
+                                               groups = groupList;
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("", t);
+                                               GSS.get().displayError("Unable to fetch groups");
+                                               groups = new ArrayList<GroupResource>();
+                                       }
+
+                                       @Override
+                                       public void onError(String p, Throwable throwable) {
+                                               GWT.log("Path:" + p, throwable);
+                                       }
+                               };
+                               DeferredCommand.addCommand(ga);
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               GWT.log("", t);
+                               GSS.get().displayError("Unable to fetch groups");
+                               groups = new ArrayList<GroupResource>();
+                       }
+               };
+               DeferredCommand.addCommand(gg);
+       }
+
+       private void getVersions() {
+               if (GSS.get().getCurrentSelection() instanceof FileResource) {
+                       FileResource afile = (FileResource) GSS.get().getCurrentSelection();
+                       GWT.log("File is versioned:" + afile.isVersioned(), null);
+                       if (afile.isVersioned()) {
+                               List<String> paths = new ArrayList<String>();
+                               for (int i = 1; i <= afile.getVersion(); i++)
+                                       paths.add(afile.getUri() + "?version=" + i);
+                               MultipleHeadCommand<FileResource> gv = new MultipleHeadCommand<FileResource>(FileResource.class, paths.toArray(new String[] {}), null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               versions = getResult();
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               GWT.log("", t);
+                                               GSS.get().displayError("Unable to fetch versions");
+                                               versions = new ArrayList<FileResource>();
+                                       }
+
+                                       @Override
+                                       public void onError(String p, Throwable throwable) {
+                                               GWT.log("Path:" + p, throwable);
+                                       }
+                               };
+                               DeferredCommand.addCommand(gv);
+                       } else
+                               versions = new ArrayList<FileResource>();
+               } else
+                       versions = new ArrayList<FileResource>();
+       }
+
+       private void getOwnerFullName() {
+               if(GSS.get().getCurrentSelection() instanceof FileResource){                    
+                       FileResource fileResource = (FileResource) GSS.get().getCurrentSelection();
+                       userName = fileResource.getOwner();
+                       if(GSS.get().findUserFullName(userName) == null){
+                               GetUserCommand gu = new GetUserCommand(userName);
+                               gu.execute();
+                       }
+               }else{                  
+                       FolderResource resource = ((RestResourceWrapper) GSS.get().getCurrentSelection()).getResource();
+                       userName = resource.getOwner();
+                       if(GSS.get().findUserFullName(userName) == null){
+                               GetUserCommand gu = new GetUserCommand(userName);
+                               gu.execute();
+                       }
+               }
+       }
+
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/RefreshCommand.java b/src/org/gss_project/gss/web/client/commands/RefreshCommand.java
new file mode 100644 (file)
index 0000000..f99a550
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.FileMenu;
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+
+import java.util.List;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class RefreshCommand implements Command {
+
+       final FileMenu.Images newImages;
+
+       private PopupPanel containerPanel;
+
+       /**
+        * @param _containerPanel
+        * @param _newImages the images of all the possible delete dialogs
+        */
+       public RefreshCommand(PopupPanel _containerPanel, final FileMenu.Images _newImages) {
+               containerPanel = _containerPanel;
+               newImages = _newImages;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               if (GSS.get().getCurrentSelection() instanceof FileResource || GSS.get().getCurrentSelection() instanceof List)
+                       GSS.get().showFileList(true);
+               else if (GSS.get().getCurrentSelection() instanceof GroupUserResource)
+                       return;
+               else{
+                       //TODO:CELLTREE
+                       //DnDTreeItem selectedTreeItem = (DnDTreeItem) GSS.get().getFolders().getCurrent();
+                       //if(selectedTreeItem != null){
+                               //GSS.get().getFolders().updateFolder(selectedTreeItem);
+                       GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());
+                               GSS.get().showFileList(true);
+                       //}
+               }
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/commands/ResreshOthersSharesCommand.java b/src/org/gss_project/gss/web/client/commands/ResreshOthersSharesCommand.java
new file mode 100644 (file)
index 0000000..b0439d3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ * @author kman
+ *
+ */
+public class ResreshOthersSharesCommand implements Command{
+       private PopupPanel containerPanel;
+
+       public ResreshOthersSharesCommand(PopupPanel _containerPanel){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               //TODO:CELLTREE
+               //GSS.get().getFolders().update( GSS.get().getFolders().getCurrent());
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/RestoreTrashCommand.java b/src/org/gss_project/gss/web/client/commands/RestoreTrashCommand.java
new file mode 100644 (file)
index 0000000..1439db7
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.MultiplePostCommand;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.TrashFolderResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+
+/**
+ *
+ * Restore trashed files and folders.
+ *
+ * @author kman
+ */
+public class RestoreTrashCommand implements Command{
+       private PopupPanel containerPanel;
+
+       public RestoreTrashCommand(PopupPanel _containerPanel){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               Object selection = GSS.get().getCurrentSelection();
+               if (selection == null){
+                       // Check to see if Trash Node is selected.
+                       List folderList = new ArrayList();
+                       TrashResource trashItem = GSS.get().getTreeView().getTrash();
+                       for(int i=0 ; i < trashItem.getFolders().size() ; i++)
+                               folderList.add(trashItem.getFolders().get(i));
+                       return;
+               }
+               GWT.log("selection: " + selection.toString(), null);
+               if (selection instanceof FileResource) {
+                       final FileResource resource = (FileResource)selection;
+                       PostCommand rt = new PostCommand(resource.getUri()+"?restore=","", 200){
+
+                               @Override
+                               public void onComplete() {
+                                       //TODO:CELLTREE
+                                       //GSS.get().getFolders().update(GSS.get().getFolders().getTrashItem());
+                                       
+                                       GSS.get().showFileList(true);
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("", t);
+                                       if(t instanceof RestException){
+                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                               if(statusCode == 405)
+                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                               else if(statusCode == 404)
+                                                       GSS.get().displayError("File does not exist");
+                                               else if(statusCode == 409)
+                                                       GSS.get().displayError("A file with the same name already exists");
+                                               else if(statusCode == 413)
+                                                       GSS.get().displayError("Your quota has been exceeded");
+                                               else
+                                                       GSS.get().displayError("Unable to restore file:"+((RestException)t).getHttpStatusText());
+                                       }
+                                       else
+                                               GSS.get().displayError("System error restoring file:"+t.getMessage());
+                               }
+                       };
+                       DeferredCommand.addCommand(rt);
+               }
+               else if (selection instanceof List) {
+                       final List<FileResource> fdtos = (List<FileResource>) selection;
+                       final List<String> fileIds = new ArrayList<String>();
+                       for(FileResource f : fdtos)
+                               fileIds.add(f.getUri()+"?restore=");
+                       MultiplePostCommand rt = new MultiplePostCommand(fileIds.toArray(new String[0]), 200){
+
+                               @Override
+                               public void onComplete() {
+                                       //TODO:CELLTREE
+                                       //GSS.get().getFolders().update(GSS.get().getFolders().getTrashItem());
+                                       GSS.get().showFileList(true);
+                               }
+
+                               @Override
+                               public void onError(String p, Throwable t) {
+                                       GWT.log("", t);
+                                       if(t instanceof RestException){
+                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                               if(statusCode == 405)
+                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                               else if(statusCode == 404)
+                                                       GSS.get().displayError("File does not exist");
+                                               else if(statusCode == 409)
+                                                       GSS.get().displayError("A file with the same name already exists");
+                                               else if(statusCode == 413)
+                                                       GSS.get().displayError("Your quota has been exceeded");
+                                               else
+                                                       GSS.get().displayError("Unable to restore file::"+((RestException)t).getHttpStatusText());
+                                       }
+                                       else
+                                               GSS.get().displayError("System error restoring file:"+t.getMessage());
+                               }
+                       };
+                       DeferredCommand.addCommand(rt);
+               }
+               else if (selection instanceof TrashFolderResource) {
+                       final FolderResource resource = ((TrashFolderResource)selection).getResource();
+                       PostCommand rt = new PostCommand(resource.getUri()+"?restore=","", 200){
+
+                               @Override
+                               public void onComplete() {
+                                       //TODO:CELLTREE
+                                       /*
+                                       GSS.get().getFolders().updateFolder((DnDTreeItem) GSS.get().getFolders().getRootItem());
+
+                                       GSS.get().getFolders().update(GSS.get().getFolders().getTrashItem());
+                                       */
+                                       
+                                       GSS.get().getTreeView().updateTrashNode();
+                                       GSS.get().getTreeView().updateRootNode();
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("", t);
+                                       if(t instanceof RestException){
+                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                               if(statusCode == 405)
+                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                               else if(statusCode == 404)
+                                                       GSS.get().displayError("Folder does not exist");
+                                               else if(statusCode == 409)
+                                                       GSS.get().displayError("A folder with the same name already exists");
+                                               else if(statusCode == 413)
+                                                       GSS.get().displayError("Your quota has been exceeded");
+                                               else
+                                                       GSS.get().displayError("Unable to restore folder::"+((RestException)t).getHttpStatusText());
+                                       }
+                                       else
+                                               GSS.get().displayError("System error restoring folder:"+t.getMessage());
+                               }
+                       };
+                       DeferredCommand.addCommand(rt);
+               }
+
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/ToTrashCommand.java b/src/org/gss_project/gss/web/client/commands/ToTrashCommand.java
new file mode 100644 (file)
index 0000000..af7dceb
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.MultiplePostCommand;
+import org.gss_project.gss.web.client.rest.PostCommand;
+import org.gss_project.gss.web.client.rest.RestException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ *
+ * Move file or folder to trash.
+ *
+ * @author kman
+ *
+ */
+public class ToTrashCommand implements Command{
+       private PopupPanel containerPanel;
+
+       public ToTrashCommand(PopupPanel _containerPanel){
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+               Object selection = GSS.get().getCurrentSelection();
+               if (selection == null)
+                       return;
+               GWT.log("selection: " + selection.toString(), null);
+               if (selection instanceof RestResourceWrapper) {
+                       FolderResource fdto = ((RestResourceWrapper) selection).getResource();
+                       PostCommand tot = new PostCommand(fdto.getUri()+"?trash=","",200){
+
+                               @Override
+                               public void onComplete() {
+                                       //TODO:CELLTREE
+                                       /*
+                                       TreeItem folder = GSS.get().getFolders().getCurrent();
+                                       if(folder.getParentItem() != null){
+                                               GSS.get().getFolders().select(folder.getParentItem());
+                                               GSS.get().getFolders().updateFolder((DnDTreeItem) folder.getParentItem());
+                                       }
+                                       GSS.get().getFolders().update(GSS.get().getFolders().getTrashItem());
+                                       */
+                                       FolderResource fres = ((RestResourceWrapper) GSS.get().getTreeView().getSelection()).getResource();
+                                       GSS.get().getTreeView().updateNodeChildrenForRemove(fres.getParentURI());
+                                       GSS.get().getTreeView().clearSelection();
+                                       //GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getTrash());
+                                       GSS.get().getTreeView().updateTrashNode();
+                                       GSS.get().showFileList(true);
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("", t);
+                                       if(t instanceof RestException){
+                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                               if(statusCode == 405)
+                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                               else if(statusCode == 404)
+                                                       GSS.get().displayError("Folder does not exist");
+                                               else
+                                                       GSS.get().displayError("Unable to trash folder:"+((RestException)t).getHttpStatusText());
+                                       }
+                                       else
+                                               GSS.get().displayError("System error trashing folder:"+t.getMessage());
+                               }
+                       };
+                       DeferredCommand.addCommand(tot);
+               } else if (selection instanceof FileResource) {
+                       FileResource fdto = (FileResource) selection;
+                       PostCommand tot = new PostCommand(fdto.getUri()+"?trash=","",200){
+
+                               @Override
+                               public void onComplete() {
+                                       GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());
+                               }
+
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("", t);
+                                       if(t instanceof RestException){
+                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                               if(statusCode == 405)
+                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                               else if(statusCode == 404)
+                                                       GSS.get().displayError("File does not exist");
+                                               else
+                                                       GSS.get().displayError("Unable to trash file:"+((RestException)t).getHttpStatusText());
+                                       }
+                                       else
+                                               GSS.get().displayError("System error trashing file:"+t.getMessage());
+                               }
+                       };
+                       DeferredCommand.addCommand(tot);
+
+               }
+               else if (selection instanceof List) {
+                       List<FileResource> fdtos = (List<FileResource>) selection;
+                       final List<String> fileIds = new ArrayList<String>();
+                       for(FileResource f : fdtos)
+                               fileIds.add(f.getUri()+"?trash=");
+                       MultiplePostCommand tot = new MultiplePostCommand(fileIds.toArray(new String[0]),200){
+
+                               @Override
+                               public void onComplete() {
+                                       GSS.get().getTreeView().updateNode(GSS.get().getTreeView().getSelection());
+                               }
+
+                               @Override
+                               public void onError(String p, Throwable t) {
+                                       GWT.log("", t);
+                                       if(t instanceof RestException){
+                                               int statusCode = ((RestException)t).getHttpStatusCode();
+                                               if(statusCode == 405)
+                                                       GSS.get().displayError("You don't have the necessary permissions");
+                                               else if(statusCode == 404)
+                                                       GSS.get().displayError("File does not exist");
+                                               else
+                                                       GSS.get().displayError("Unable to trash file:"+((RestException)t).getHttpStatusText());
+                                       }
+                                       else
+                                               GSS.get().displayError("System error trashing file:"+t.getMessage());
+                               }
+                       };
+                       DeferredCommand.addCommand(tot);
+               }
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/UploadFileCommand.java b/src/org/gss_project/gss/web/client/commands/UploadFileCommand.java
new file mode 100644 (file)
index 0000000..41a73e6
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008, 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.FileUploadDialog;
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.GetCommand;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.RestResourceWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.IncrementalCommand;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+/**
+ * Upload a file command
+ *
+ * @author kman
+ */
+public class UploadFileCommand implements Command {
+
+       private PopupPanel containerPanel;
+       private List<FileResource> files;
+
+       public UploadFileCommand(PopupPanel _containerPanel) {
+               containerPanel = _containerPanel;
+       }
+
+       @Override
+       public void execute() {
+               if(containerPanel!=null)
+                       containerPanel.hide();
+               displayNewFile();
+       }
+
+       /**
+        * Display the 'new file' dialog for uploading a new file to the system.
+        */
+       private void displayNewFile() {
+               RestResource currentFolder = GSS.get().getTreeView().getSelection();
+               if (currentFolder == null) {
+                       GSS.get().displayError("You have to select the parent folder first");
+                       return;
+               }
+               getFileList();
+               DeferredCommand.addCommand(new IncrementalCommand() {
+
+                       @Override
+                       public boolean execute() {
+                               boolean res = canContinue();
+                               if (res) {
+                                       FileUploadDialog dlg = GWT.create(FileUploadDialog.class);
+                                       dlg.setFiles(files);
+                                       dlg.center();
+                                       return false;
+                               }
+                               return true;
+                       }
+
+               });
+       }
+
+       private boolean canContinue() {
+               if (files != null )
+                       return true;
+               return false;
+       }
+
+       private void getFileList() {
+               GetCommand<FolderResource> eg = new GetCommand<FolderResource>(FolderResource.class,((RestResourceWrapper)GSS.get().getTreeView().getSelection()).getUri(), null){
+
+                       @Override
+                       public void onComplete() {
+                               files = getResult().getFiles();
+                       }
+
+                       @Override
+                       public void onError(Throwable t) {
+                               files = new ArrayList<FileResource>();
+                       }
+
+               };
+               DeferredCommand.addCommand(eg);
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/commands/ViewImageCommand.java b/src/org/gss_project/gss/web/client/commands/ViewImageCommand.java
new file mode 100644 (file)
index 0000000..06779a6
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.commands;
+
+import org.gss_project.gss.web.client.FileMenu;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.ErrorEvent;
+import com.google.gwt.event.dom.client.ErrorHandler;
+import com.google.gwt.event.dom.client.LoadEvent;
+import com.google.gwt.event.dom.client.LoadHandler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+
+public class ViewImageCommand implements Command {
+
+       final FileMenu.Images newImages;
+
+       private PopupPanel containerPanel;
+
+       private String imageDownloadURL;
+
+       private Label errorLabel = new Label();
+
+       /**
+        * @param _containerPanel
+        * @param _newImages the images of all the possible delete dialogs
+        */
+       public ViewImageCommand(PopupPanel _containerPanel, final FileMenu.Images _newImages, String _imageDownloadURL) {
+               containerPanel = _containerPanel;
+               newImages = _newImages;
+               imageDownloadURL = _imageDownloadURL;
+       }
+
+       @Override
+       public void execute() {
+               containerPanel.hide();
+
+               final Image image = new Image();
+               // Hook up a load handler, so that we can be informed if the image
+               // fails to load.
+           image.addLoadHandler(new LoadHandler() {
+
+                       @Override
+                       public void onLoad(LoadEvent event) {
+                               errorLabel.setText("");
+                       }
+               });
+               image.addErrorHandler(new ErrorHandler() {
+
+                       @Override
+                       public void onError(ErrorEvent event) {
+                               errorLabel.setText("An error occurred while loading.");
+                       }
+               });
+           image.setUrl(imageDownloadURL);
+           final DialogBox imagePopup = new DialogBox(true, true);
+           imagePopup.setAnimationEnabled(true);
+           imagePopup.setText("Showing image in actual size");
+           VerticalPanel imageViewPanel = new VerticalPanel();
+           errorLabel.setText("loading image...");
+           imageViewPanel.add(errorLabel);
+           imageViewPanel.add(image);
+           imagePopup.setWidget(imageViewPanel);
+           image.setTitle("Click to close");
+           image.addClickHandler(new ClickHandler() {
+
+                       @Override
+                       public void onClick(ClickEvent event) {
+                       imagePopup.hide();
+               }
+           });
+           imagePopup.setPopupPosition(0, 0);
+           imagePopup.show();
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/components/TristateCheckBox.java b/src/org/gss_project/gss/web/client/components/TristateCheckBox.java
new file mode 100644 (file)
index 0000000..9fd18de
--- /dev/null
@@ -0,0 +1,123 @@
+package org.gss_project.gss.web.client.components;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.FocusWidget;
+import com.google.gwt.user.client.ui.HasValue;
+
+/**
+ * Checkbox with three states (checked, unchecked and undefined).
+ *
+ */
+public class TristateCheckBox extends FocusWidget implements HasValue<Boolean> {
+
+    private static final String UNCHECKED_IMG = "images/tristate_unchecked.gif";
+
+    private static final String UNKNOWN_IMG = "images/tristate_intermediate.gif";
+
+    private static final String CHECKED_IMG = "images/tristate_checked.gif";
+
+    private final Element buttonElement = DOM.createElement("input");
+
+    private boolean valueChangeHandlerInitialized;
+
+    private Boolean value;
+
+    private Boolean initialValue;
+
+    public TristateCheckBox(final Boolean state) {
+        DOM.setElementProperty(buttonElement, "type", "image");
+        setElement(buttonElement);
+        setStyleName("tristateCheckbox");
+        DOM.setElementAttribute(buttonElement, "src", UNCHECKED_IMG);
+
+        addClickHandler(new ClickHandler() {
+
+                       @Override
+                       public void onClick(ClickEvent event) {
+                final String img = DOM.getElementAttribute(buttonElement, "src");
+                String newImg;
+                if (img.endsWith(UNCHECKED_IMG))
+                                       newImg = CHECKED_IMG;
+                               else if (img.endsWith(UNKNOWN_IMG))
+                                       newImg = UNCHECKED_IMG;
+                               else if (img.endsWith(CHECKED_IMG))
+                                       if (initialValue==null) // Only show unknown choice if there is a reason for it
+                                               newImg = UNKNOWN_IMG;
+                                       else
+                                               newImg = UNCHECKED_IMG;
+                               else
+                                       throw new IllegalArgumentException("unknown checkbox state");
+
+                DOM.setElementAttribute(buttonElement, "src", newImg);
+            }
+
+        });
+
+        setState(state);
+        initialValue = state;
+    }
+
+    public void setState(final Boolean state) {
+       DOM.setElementAttribute(buttonElement, "src", state == null ?
+                       UNKNOWN_IMG : state.booleanValue() ? CHECKED_IMG : UNCHECKED_IMG);
+    }
+
+    public Boolean getState() {
+        final String img = DOM.getElementAttribute(buttonElement, "src");
+        if (img.endsWith(UNCHECKED_IMG))
+                       return Boolean.FALSE;
+               else if (img.endsWith(UNKNOWN_IMG))
+                       return null;
+               else if (img.endsWith(CHECKED_IMG))
+                       return Boolean.TRUE;
+               else
+                       throw new IllegalArgumentException("unknown checkbox state");
+    }
+
+    @Override
+       public Boolean getValue() {
+        return value;
+    }
+
+    @Override
+       public void setValue(final Boolean _value) {
+        value = _value;
+    }
+
+    @Override
+       public HandlerRegistration addValueChangeHandler(
+           ValueChangeHandler<Boolean> handler) {
+           // Is this the first value change handler? If so, time to add handlers
+           if (!valueChangeHandlerInitialized) {
+               ensureDomEventHandlers();
+               valueChangeHandlerInitialized = true;
+           }
+           return addHandler(handler, ValueChangeEvent.getType());
+         }
+
+    protected void ensureDomEventHandlers() {
+        addClickHandler(new ClickHandler() {
+               @Override
+                       public void onClick(ClickEvent event) {
+                       ValueChangeEvent.fire(TristateCheckBox.this, getValue());
+               }
+        });
+    }
+
+    @Override
+       public void setValue(Boolean _value, boolean fireEvents) {
+        Boolean oldValue = getValue();
+        setValue(_value);
+        if (_value.equals(oldValue))
+                       return;
+        if (fireEvents)
+                       ValueChangeEvent.fire(this, _value);
+    }
+
+}
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/client/downArrow.png b/src/org/gss_project/gss/web/client/downArrow.png
new file mode 100644 (file)
index 0000000..fd4012c
Binary files /dev/null and b/src/org/gss_project/gss/web/client/downArrow.png differ
diff --git a/src/org/gss_project/gss/web/client/rest/CallbackList.java b/src/org/gss_project/gss/web/client/rest/CallbackList.java
new file mode 100644 (file)
index 0000000..dfe5059
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+
+
+/**
+ * @author kman
+ *
+ */
+public class CallbackList<T> implements AsyncCallback<T>{
+       List<T> result = new ArrayList();
+       boolean erroneous = false;
+
+       @Override
+       public void onFailure(Throwable arg0) {
+               GWT.log("Error in callback list", arg0);
+               erroneous = true;
+
+       }
+
+
+       @Override
+       public void onSuccess(T arg0) {
+               result.add(arg0);
+       }
+
+
+
+       /**
+        * Retrieve the result.
+        *
+        * @return the result
+        */
+       public List<T> getResult() {
+               return result;
+       }
+
+
+
+       /**
+        * Retrieve the erroneous.
+        *
+        * @return the erroneous
+        */
+       public boolean isErroneous() {
+               return erroneous;
+       }
+
+
+
+
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/DeleteCommand.java b/src/org/gss_project/gss/web/client/rest/DeleteCommand.java
new file mode 100644 (file)
index 0000000..2d439b5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.InsufficientPermissionsException;
+
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+
+/**
+ * @author kman
+ *
+ */
+public abstract class DeleteCommand extends RestCommand{
+
+       boolean complete = false;
+
+       public DeleteCommand(String pathToDelete){
+               this(pathToDelete, true);
+       }
+
+
+       public DeleteCommand(String pathToDelete, boolean showLoading){
+               setShowLoadingIndicator(showLoading);
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Deleting ",pathToDelete);
+               final String path;
+               if(pathToDelete.endsWith("/"))
+                       path = pathToDelete;
+               else
+                       path = pathToDelete+"/";
+               RequestBuilder builder = new RequestBuilder(RequestBuilder.DELETE, path);
+
+               try {
+                       handleHeaders(builder, path);
+                       builder.sendRequest("", new RequestCallback() {
+
+                               @Override
+                               public void onError(Request arg0, Throwable arg1) {
+                                       complete = true;
+                                       DeleteCommand.this.onError(arg1);
+                               }
+
+                               @Override
+                               public void onResponseReceived(Request arg0, Response arg1) {
+                                       complete=true;
+                                       if(arg1.getStatusCode() == 204)
+                                               onComplete();
+                                       else if(arg1.getStatusCode() == 403)
+                                               sessionExpired();
+                                       else if(arg1.getStatusCode() == 405)
+                                               DeleteCommand.this.onError(new InsufficientPermissionsException("You don't have permissions to delete this resource"));
+                                       else
+                                               DeleteCommand.this.onError(new RestException(path, arg1.getStatusCode(), arg1.getStatusText(), arg1.getText()));
+                               }
+
+                       });
+               } catch (Exception ex) {
+                       complete=true;
+                       onError(ex);
+               }
+       }
+
+       public boolean isComplete() {
+               return complete;
+       }
+
+       @Override
+       public boolean execute() {
+               boolean com = isComplete();
+               if(com){
+                       if(isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       return false;
+               }
+               return true;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/GetCommand.java b/src/org/gss_project/gss/web/client/rest/GetCommand.java
new file mode 100644 (file)
index 0000000..10ba347
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.GroupsResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.OthersResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.SearchResource;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TagsResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UploadStatusResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+import org.gss_project.gss.web.client.rest.resource.UserSearchResource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.Response;
+
+/**
+ * @author kman
+ */
+public abstract class GetCommand<T extends RestResource> extends RestCommand{
+
+       boolean complete = false;
+       T result = null;
+       Throwable exception = null;
+       Class<T> aclass;
+       private final String path;
+       private String username;
+       private boolean requestSent = false;
+       T cached;
+       
+       private static final long MAX_CACHE_AGE = 1000;
+       
+       private static class RequestData {
+               public String path;
+               public String username;
+               
+               public RequestData(String _path, String _username) {
+                       path = _path;
+                       username = _username;
+               }
+
+               @Override
+               public int hashCode() {
+                       final int prime = 31;
+                       int result = 1;
+                       result = prime * result + ((path == null) ? 0 : path.hashCode());
+                       result = prime * result + ((username == null) ? 0 : username.hashCode());
+                       return result;
+               }
+
+               @Override
+               public boolean equals(Object obj) {
+                       if (this == obj)
+                               return true;
+                       if (obj == null)
+                               return false;
+                       if (getClass() != obj.getClass())
+                               return false;
+                       RequestData other = (RequestData) obj;
+                       if (path == null) {
+                               if (other.path != null)
+                                       return false;
+                       } else if (!path.equals(other.path))
+                               return false;
+                       if (username == null) {
+                               if (other.username != null)
+                                       return false;
+                       } else if (!username.equals(other.username))
+                               return false;
+                       return true;
+               }
+       }
+       
+       private static class ResponseData {
+               public long timestamp;
+               public Object result;
+               public ResponseData(long _timestamp, Object _result) {
+                       timestamp = _timestamp;
+                       result = _result;
+               }
+       }
+       
+       private static Map<RequestData, ResponseData> cache = new HashMap<RequestData, ResponseData>();
+       
+
+       public GetCommand(Class<T> theclass, String pathToGet, T theCached){
+               this(theclass, pathToGet, true, theCached);
+       }
+
+       public GetCommand(Class<T> theclass, String pathToGet, boolean showLoading, T theCached){
+               setShowLoadingIndicator(showLoading);
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Getting ",pathToGet);
+               this.aclass = theclass;
+               if(pathToGet.indexOf("?") != -1)
+                       path = pathToGet;
+               else
+                       path =fixPath(pathToGet);
+               this.cached = theCached;
+       }
+
+       public GetCommand(Class<T> theclass, String aUsername , String pathToGet, T theCached){
+               this(theclass, aUsername, pathToGet, true, theCached);
+       }
+
+       public GetCommand(Class<T> theclass, String aUsername , String pathToGet, boolean showLoading, T theCached){
+               setShowLoadingIndicator(showLoading);
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Getting ",pathToGet);
+               this.aclass = theclass;
+               path = fixPath(pathToGet);
+               this.username = aUsername;
+               this.cached = theCached;
+       }
+
+       private void sendRequest(){
+               if(requestSent)
+                       return;
+               requestSent=true;
+               RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
+               if(cached!=null && cached.getLastModifiedSince() != null)
+                       builder.setHeader("If-Modified-Since", cached.getLastModifiedSince());
+               try {
+                       if(username == null)
+                               handleHeaders(builder, path);
+                       else
+                               handleHeaders(username, builder, path);
+                       builder.sendRequest("", new RestCallback(path) {
+
+                               @Override
+                               public Object deserialize(Response response) {
+                                       return deserializeResponse(path, response);
+                               }
+
+                               @Override
+                               public void handleError(Request request, Throwable _exception) {
+                                       result = null;
+                                       complete = true;
+                                       exception = _exception;
+                                       if(_exception instanceof RestException)
+                                               if(((RestException)_exception).getHttpStatusCode() == 304 && cached != null){
+                                                       GWT.log("Using cache:"+cached.getUri(), null);
+                                                       handleSuccess(cached);
+                                                       return;
+                                               }
+                                       
+                               }
+
+                               @Override
+                               public void handleSuccess(Object object) {
+                                       result = (T) object;
+                                       complete = true;
+                               }
+
+                       });
+               } catch (Exception ex) {
+                       complete = true;
+                       exception = ex;
+               }
+       }
+       public boolean isComplete() {
+               return complete;
+       }
+
+       public T getResult(){
+               return result;
+       }
+
+       @Override
+       public boolean execute() {
+               boolean com = isComplete();
+               RequestData key = new RequestData(path, username);
+               if (!com) {
+                       if (cache.containsKey(key)) {
+                               ResponseData resp = cache.get(key);
+                               if (resp==null) {
+                                       return true;
+                               }
+                               
+                               // Cache hit
+                               if (System.currentTimeMillis()-resp.timestamp>MAX_CACHE_AGE) {
+                                       // Cache stale, remove
+                                       cache.put(key,null);
+                               }
+                               else {
+                                       // Use cache data
+                                       if(isShowLoadingIndicator())
+                                               GSS.get().hideLoadingIndicator();
+                                       if (resp.result instanceof Throwable) {
+                                               // Error to be handled
+                                               Throwable ex = (Throwable) resp.result;
+                                               onError(ex);
+                                               return false;
+                                       }
+                                       result = (T) resp.result;
+                                       if (result != null) {
+                                               onComplete();
+                                       }
+                                       complete = true;
+                                       return false;
+                               }
+                       }
+               
+                       if(!requestSent) {
+                               cache.put(key,null);
+                               sendRequest();
+                       }
+               }
+               
+               if(com){
+                       if(isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       if(getResult() != null) {
+                               // Add to cache
+                               cache.put(key, new ResponseData(System.currentTimeMillis(), getResult()));
+                               onComplete();
+                       }
+                       else {
+                               cache.put(key, new ResponseData(System.currentTimeMillis(), exception));
+                               onError(exception);
+                       }
+                       return false;
+               }
+               return true;
+       }
+
+       public Object deserializeResponse(String aPath, Response response) {
+               RestResource result1 = null;
+               if(aclass.equals(FolderResource.class)){
+                       result1 = new FolderResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(FileResource.class)){
+                       result1 = new FileResource(aPath);
+                       result1.createFromJSON(response.getHeader("X-GSS-Metadata"));
+               }
+               else if(aclass.equals(GroupsResource.class)){
+                       result1 = new GroupsResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(TrashResource.class)){
+                       result1 = new TrashResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(SharedResource.class)){
+                       result1 = new SharedResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(OthersResource.class)){
+                       result1 = new OthersResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(OtherUserResource.class)){
+                       result1 = new OtherUserResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(GroupResource.class)){
+                       result1 = new GroupResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(GroupUserResource.class)){
+                       result1 = new GroupUserResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(UserResource.class)){
+                       result1 = new UserResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(TagsResource.class)){
+                       result1 = new TagsResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(SearchResource.class)){
+                       result1 = new SearchResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(UserSearchResource.class)){
+                       result1 = new UserSearchResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(UploadStatusResource.class)){
+                       result1 = new UploadStatusResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               return result1;
+       }
+
+       public T getCached() {
+               return cached;
+       }
+
+       public void setCached(T theCached) {
+               this.cached = theCached;
+       }
+       
+       public boolean usedCachedVersion(){
+               if(exception !=null && exception instanceof RestException)
+                       if(((RestException)exception).getHttpStatusCode() == 304){
+                               return true;
+                       }
+               return false;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/HeadCommand.java b/src/org/gss_project/gss/web/client/rest/HeadCommand.java
new file mode 100644 (file)
index 0000000..9b03807
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.ObjectNotFoundException;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.GroupsResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.Response;
+
+
+/**
+ * @author kman
+ *
+ */
+public  abstract class HeadCommand<T extends RestResource> extends RestCommand{
+
+       boolean complete = false;
+       T result = null;
+       Class<T> aclass;
+       private boolean requestSent = false;
+       T cached;
+       final String path;
+
+       public HeadCommand(Class<T> theclass, String pathToGet, T theCached){
+               this(theclass, pathToGet, true, theCached);
+       }
+
+       public HeadCommand(Class<T> theClass, String pathToGet, boolean showLoading, T theCached){
+               setShowLoadingIndicator(showLoading);
+               this.aclass = theClass;
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Getting ",pathToGet);
+
+               if(theClass.equals(FileResource.class))
+                       path = pathToGet;
+               else
+                       path = fixPath(pathToGet);
+               this.cached = theCached;
+
+       }
+
+       private void sendRequest(){
+               if(requestSent)
+                       return;
+               requestSent=true;
+               RequestBuilder builder = new RequestBuilder(RequestBuilder.HEAD, path);
+               if(cached!=null && cached.getLastModifiedSince() != null){
+                       GWT.log("ADDING IF MODIFIED HEADERS", null);
+                       builder.setHeader("If-Modified-Since", cached.getLastModifiedSince());
+               }
+               try {
+                       handleHeaders(builder, path);
+                       builder.sendRequest("", new RestCallback(path) {
+
+                               @Override
+                               public Object deserialize(Response response) {
+                                       return deserializeResponse(path, response);
+                               }
+
+                               @Override
+                               public void handleError(Request request, Throwable exception) {
+                                       if(exception instanceof RestException)
+                                               if(((RestException)exception).getHttpStatusCode() == 304 && cached != null){
+                                                       GWT.log("Using cache:"+cached.getUri(), null);
+                                                       handleSuccess(cached);
+                                                       return;
+                                               }
+                                       complete = true;
+                                       HeadCommand.this.onError(exception);
+                               }
+
+                               @Override
+                               public void handleSuccess(Object object) {
+                                       result = (T) object;
+                                       complete = true;
+                               }
+
+                       });
+               } catch (Exception ex) {
+                       complete = true;
+                       onError(ex);
+               }
+       }
+
+       public boolean isComplete() {
+               return complete;
+       }
+
+       public T getResult(){
+               return result;
+       }
+
+       @Override
+       public boolean execute() {
+               if(!requestSent)
+                       sendRequest();
+               boolean com = isComplete();
+               if(com){
+                       if(isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       if(getResult() != null)
+                               onComplete();
+                       else
+                               onError(new ObjectNotFoundException("Resource Not Found"));
+                       return false;
+               }
+               return true;
+       }
+
+       public  Object deserializeResponse(String aPath, Response response){
+               RestResource result1 = null;
+               if(aclass.equals(FolderResource.class)){
+                       result1 = new FolderResource(aPath);
+                       result1.createFromJSON(response.getText());
+
+               }
+               else if(aclass.equals(FileResource.class)){
+                       result1 = new FileResource(aPath);
+                       result1.createFromJSON(response.getHeader("X-GSS-Metadata"));
+               }
+               else if(aclass.equals(GroupsResource.class)){
+                       result1 = new GroupsResource(aPath);
+                       result1.createFromJSON(response.getText());
+               }
+               else if(aclass.equals(TrashResource.class)){
+                       result1 = new TrashResource(aPath);
+                       result1.createFromJSON(response.getText());
+
+               }
+               else if(aclass.equals(SharedResource.class)){
+                       result1 = new SharedResource(aPath);
+                       result1.createFromJSON(response.getText());
+
+               }
+               else if(aclass.equals(GroupResource.class)){
+                       result1 = new GroupResource(aPath);
+                       result1.createFromJSON(response.getText());
+
+               }
+               else if(aclass.equals(GroupUserResource.class)){
+                       result1 = new GroupUserResource(aPath);
+                       result1.createFromJSON(response.getText());
+
+               }
+               else if(aclass.equals(UserResource.class)){
+                       result1 = new UserResource(aPath);
+                       result1.createFromJSON(response.getText());
+
+               }
+               return result1;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/MultipleDeleteCommand.java b/src/org/gss_project/gss/web/client/rest/MultipleDeleteCommand.java
new file mode 100644 (file)
index 0000000..a760d43
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.InsufficientPermissionsException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+
+/**
+ * @author kman
+ */
+public abstract class MultipleDeleteCommand extends RestCommand {
+
+
+       Map<String, Throwable> errors = new HashMap<String, Throwable>();
+
+       List<String> successPaths = new ArrayList<String>();
+
+       String[] paths;
+
+       public MultipleDeleteCommand(String[] pathToDelete){
+               this(pathToDelete, true);
+       }
+
+       public MultipleDeleteCommand(String[] pathToDelete, boolean showLoading){
+               setShowLoadingIndicator(showLoading);
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Deleting "+pathToDelete.length+" items",null);
+               paths = pathToDelete;
+               for (final String pathg : pathToDelete) {
+                       GWT.log("[DEL]"+pathg, null);
+                       RequestBuilder builder = new RequestBuilder(RequestBuilder.DELETE, pathg);
+
+                       try {
+                               handleHeaders(builder, pathg);
+                               builder.sendRequest("", new RequestCallback() {
+
+                                       @Override
+                                       public void onError(Request arg0, Throwable arg1) {
+                                               errors.put(pathg, arg1);
+                                       }
+
+                                       @Override
+                                       public void onResponseReceived(Request arg0, Response arg1) {
+                                               if (arg1.getStatusCode() == 204)
+                                                       successPaths.add(pathg);
+                                               else if(arg1.getStatusCode() == 403)
+                                                       sessionExpired();
+                                               else if (arg1.getStatusCode() == 405)
+                                                       errors.put(pathg, new InsufficientPermissionsException("You don't have permissions to delete this resource"));
+                                               else
+                                                       errors.put(pathg, new RestException(pathg, arg1.getStatusCode(), arg1.getStatusText(), arg1.getText()));
+                                       }
+
+                               });
+                       } catch (Exception ex) {
+                               errors.put(pathg, ex);
+                       }
+               }
+       }
+
+       public boolean isComplete() {
+               return errors.size() + successPaths.size() == paths.length;
+       }
+
+       @Override
+       public boolean execute() {
+               boolean com = isComplete();
+               if (com) {
+                       if(hasErrors())
+                               for(String p : errors.keySet())
+                                       onError(p, errors.get(p));
+                       onComplete();
+                       if(isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       return false;
+               }
+               return true;
+       }
+
+       public boolean hasErrors(){
+               return errors.size() >0;
+       }
+
+
+       /**
+        * Retrieve the errors.
+        *
+        * @return the errors
+        */
+       public Map<String, Throwable> getErrors() {
+               return errors;
+       }
+
+       public void debug(){
+               GWT.log("-ERRORS-->"+getErrors().size(), null);
+               for(String p : getErrors().keySet())
+                       GWT.log("error:"+p, getErrors().get(p));
+       }
+
+       public abstract void onError(String path, Throwable throwable);
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/MultipleGetCommand.java b/src/org/gss_project/gss/web/client/rest/MultipleGetCommand.java
new file mode 100644 (file)
index 0000000..78a0546
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.GroupsResource;
+import org.gss_project.gss.web.client.rest.resource.OtherUserResource;
+import org.gss_project.gss.web.client.rest.resource.OthersResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.user.client.DeferredCommand;
+
+/**
+ * @author kman
+ */
+public abstract class MultipleGetCommand<T extends RestResource> extends RestCommand {
+
+       Class<T> aclass;
+       List<T> result = new ArrayList<T>();
+       Map<String, Throwable> errors = new HashMap<String, Throwable>();
+       Cached[] cached;
+       String[] paths;
+       private boolean requestSent=false;
+
+       public MultipleGetCommand(Class<T> aNewClass, String[] pathToGet, Cached[] theCached) {
+               this(aNewClass, pathToGet, true, theCached);
+       }
+
+       public MultipleGetCommand(Class<T> aNewClass, String[] pathToGet, boolean showLoading, Cached[] theCached) {
+               setShowLoadingIndicator(showLoading);
+               if (isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Getting "+pathToGet.length+" items", null);
+               aclass = aNewClass;
+               paths = pathToGet;
+               this.cached = theCached;
+               //sendRequest();
+       }
+
+       private void sendRequest() {
+               if (requestSent)
+                       return;
+               requestSent=true;
+               if (cached!=null)
+                       for (final Cached pathg : cached)
+                               DeferredCommand.addCommand(new GetCommand<T>(aclass,pathg.uri,false,(T)pathg.cache) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               MultipleGetCommand.this.result.add(getResult());
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               errors.put(pathg.uri, t);
+                                       }
+
+                               });
+               else
+                       for (final String pathg : paths)
+                               DeferredCommand.addCommand(new GetCommand<T>(aclass,pathg,false,null) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               MultipleGetCommand.this.result.add(getResult());
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               errors.put(pathg, t);
+                                       }
+
+                               });
+       }
+
+       public boolean isComplete() {
+               return result.size()+errors.size() == paths.length;
+       }
+
+       public List<T> getResult() {
+               if (aclass.equals(FolderResource.class))
+                       Collections.sort(result, new Comparator() {
+                               @Override
+                               public int compare(Object o1, Object o2) {
+                                       return ((FolderResource)o1).getName().compareTo(((FolderResource)o2).getName());
+                               }
+
+                       });
+               else if(aclass.equals(GroupResource.class))
+                       Collections.sort(result, new Comparator() {
+                               @Override
+                               public int compare(Object o1, Object o2) {
+                                       return ((GroupResource)o1).getName().compareTo(((GroupResource)o2).getName());
+                               }
+
+                       });
+               else if(aclass.equals(GroupUserResource.class))
+                       Collections.sort(result, new Comparator() {
+                               @Override
+                               public int compare(Object o1, Object o2) {
+                                       return ((GroupUserResource)o1).getName().compareTo(((GroupUserResource)o2).getName());
+                               }
+
+                       });
+               return result;
+       }
+
+       @Override
+       public boolean execute() {
+               if (!requestSent)
+                       sendRequest();
+               boolean com = isComplete();
+               if (com) {
+                       if (isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       if (hasErrors())
+                               for(String p : errors.keySet())
+                                       onError(p, errors.get(p));
+                       onComplete();
+                       return false;
+               }
+               return true;
+       }
+
+       /**
+        * @param p
+        * @param throwable
+        */
+       public abstract void onError(String p, Throwable throwable);
+
+       public Object deserializeResponse(String path, Response response) {
+               RestResource result1 = null;
+               if (aclass.equals(FolderResource.class)) {
+                       result1 = new FolderResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(FileResource.class)){
+                       result1 = new FileResource(path);
+                       result1.createFromJSON(response.getHeader("X-GSS-Metadata"));
+               }
+               else if (aclass.equals(GroupsResource.class)) {
+                       result1 = new GroupsResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(TrashResource.class)) {
+                       result1 = new TrashResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(SharedResource.class)) {
+                       result1 = new SharedResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(OthersResource.class)) {
+                       result1 = new OthersResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(OtherUserResource.class)) {
+                       result1 = new OtherUserResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(GroupResource.class)) {
+                       result1 = new GroupResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(GroupUserResource.class)) {
+                       result1 = new GroupUserResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               else if (aclass.equals(UserResource.class)) {
+                       result1 = new UserResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               return result1;
+       }
+
+       public boolean hasErrors() {
+               return errors.size() >0;
+       }
+
+       /**
+        * Retrieve the errors.
+        *
+        * @return the errors
+        */
+       public Map<String, Throwable> getErrors() {
+               return errors;
+       }
+
+       protected void debug() {
+               GWT.log("--->"+result.size(), null);
+               GWT.log("-ERRORS-->"+getErrors().size(), null);
+               for(String p : getErrors().keySet())
+                       GWT.log("error:"+p, getErrors().get(p));
+       }
+
+       public static class Cached {
+               public String uri;
+               public RestResource cache;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/MultipleHeadCommand.java b/src/org/gss_project/gss/web/client/rest/MultipleHeadCommand.java
new file mode 100644 (file)
index 0000000..b9373a3
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand.Cached;
+import org.gss_project.gss.web.client.rest.resource.FileResource;
+import org.gss_project.gss.web.client.rest.resource.FolderResource;
+import org.gss_project.gss.web.client.rest.resource.GroupResource;
+import org.gss_project.gss.web.client.rest.resource.GroupUserResource;
+import org.gss_project.gss.web.client.rest.resource.GroupsResource;
+import org.gss_project.gss.web.client.rest.resource.RestResource;
+import org.gss_project.gss.web.client.rest.resource.SharedResource;
+import org.gss_project.gss.web.client.rest.resource.TrashResource;
+import org.gss_project.gss.web.client.rest.resource.UserResource;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.user.client.DeferredCommand;
+
+
+/**
+ * @author kman
+ *
+ */
+public abstract class MultipleHeadCommand <T extends RestResource> extends RestCommand {
+       String[] paths;
+       Class<T> aclass;
+       List<T> result = new ArrayList<T>();
+       Map<String, Throwable> errors = new HashMap<String, Throwable>();
+       private boolean requestSent=false;
+       Cached[] cached;
+
+       public MultipleHeadCommand(Class<T> theClass, String[] pathToGet, Cached[] theCached) {
+               this(theClass, pathToGet, true, theCached);
+       }
+
+       public MultipleHeadCommand(Class<T> theClass, String[] pathToGet, boolean showLoading, Cached[] theCached) {
+               setShowLoadingIndicator(showLoading);
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Getting "+pathToGet.length+" items", null);
+               paths = pathToGet;
+               this.aclass = theClass;
+               this.cached = theCached;
+               //sendRequest();
+       }
+
+       private void sendRequest() {
+               if(requestSent)
+                       return;
+               requestSent=true;
+               if(cached!=null)
+                       for (final Cached c : cached){
+                               final String path;
+                               if(aclass.equals(FileResource.class)){
+                                       if(c.uri.indexOf("?") == -1)
+                                               path=c.uri+"?"+Math.random();
+                                       else
+                                               path=c.uri;
+                               }
+                               else
+                                       path = fixPath(c.uri);
+                               DeferredCommand.addCommand(new HeadCommand<T>(aclass,path,false, (T)c.cache) {
+
+                                       @Override
+                                       public void onComplete() {
+                                               MultipleHeadCommand.this.result.add(getResult());
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               errors.put(path, t);
+                                       }
+
+                               });
+                       }
+               else
+                       for (String pathg : paths) {
+                               final String path;
+                               if(aclass.equals(FileResource.class))
+                                       path = pathg;
+                               else
+                                       path = fixPath(pathg);
+                               DeferredCommand.addCommand(new HeadCommand<T>(aclass,path,false, null) {
+                                       @Override
+                                       public void onComplete() {
+                                               MultipleHeadCommand.this.result.add(getResult());
+                                       }
+
+                                       @Override
+                                       public void onError(Throwable t) {
+                                               errors.put(path, t);
+                                       }
+                               });
+                       }
+       }
+       public boolean isComplete() {
+               return result.size()+errors.size() == paths.length;
+       }
+
+       public List<T> getResult() {
+               return result;
+       }
+
+       @Override
+       public boolean execute() {
+               if(!requestSent)
+                       sendRequest();
+               boolean com = isComplete();
+               if (com) {
+                       if(isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       if(hasErrors())
+                               for(String p : errors.keySet())
+                                       onError(p, errors.get(p));
+                       onComplete();
+                       return false;
+               }
+               return true;
+       }
+
+       /**
+        * @param p
+        * @param throwable
+        */
+       public abstract void onError(String p, Throwable throwable);
+
+       public Object deserializeResponse(String path, Response response) {
+               RestResource result1 = null;
+               if (aclass.equals(FolderResource.class)) {
+                       result1 = new FolderResource(path);
+                       result1.createFromJSON(response.getText());
+               } else if (aclass.equals(FileResource.class)) {
+                       result1 = new FileResource(path);
+                       result1.createFromJSON(response.getHeader("X-GSS-Metadata"));
+               } else if (aclass.equals(GroupsResource.class)) {
+                       result1 = new GroupsResource(path);
+                       result1.createFromJSON(response.getText());
+               } else if (aclass.equals(TrashResource.class)) {
+                       result1 = new TrashResource(path);
+                       result1.createFromJSON(response.getText());
+               } else if (aclass.equals(SharedResource.class)) {
+                       result1 = new SharedResource(path);
+                       result1.createFromJSON(response.getText());
+               } else if (aclass.equals(GroupResource.class)) {
+                       result1 = new GroupResource(path);
+                       result1.createFromJSON(response.getText());
+               } else if (aclass.equals(GroupUserResource.class)) {
+                       result1 = new GroupUserResource(path);
+                       result1.createFromJSON(response.getText());
+               } else if (aclass.equals(UserResource.class)) {
+                       result1 = new UserResource(path);
+                       result1.createFromJSON(response.getText());
+               }
+               return result1;
+       }
+
+       public boolean hasErrors(){
+               return errors.size() >0;
+       }
+
+       /**
+        * Retrieve the errors.
+        *
+        * @return the errors
+        */
+       public Map<String, Throwable> getErrors() {
+               return errors;
+       }
+
+       public void debug(){
+               GWT.log("--->"+result.size(), null);
+               GWT.log("-ERRORS-->"+getErrors().size(), null);
+               for(String p : getErrors().keySet())
+                       GWT.log("error:"+p, getErrors().get(p));
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/MultiplePostCommand.java b/src/org/gss_project/gss/web/client/rest/MultiplePostCommand.java
new file mode 100644 (file)
index 0000000..527296c
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.InsufficientPermissionsException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+
+
+/**
+ * @author kman
+ *
+ */
+public abstract class MultiplePostCommand extends RestCommand {
+
+
+       Map<String, Throwable> errors = new HashMap<String, Throwable>();
+
+       List<String> successPaths = new ArrayList<String>();
+
+       String[] paths;
+
+       public MultiplePostCommand(String[] pathToDelete, final int okStatusCode){
+               this(pathToDelete, okStatusCode, true);
+       }
+
+       public MultiplePostCommand(String[] pathToDelete, String data, final int okStatusCode){
+               this(pathToDelete, data, okStatusCode, true);
+       }
+
+       public MultiplePostCommand(String[] pathToDelete, final int okStatusCode, boolean showLoading){
+               this(pathToDelete, "", okStatusCode, showLoading);
+       }
+
+       public MultiplePostCommand(String[] pathToDelete, String data, final int okStatusCode, boolean showLoading){
+               setShowLoadingIndicator(showLoading);
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Updating "+pathToDelete.length+" items", null);
+               paths = pathToDelete;
+               for (final String pathg : pathToDelete) {
+                       GWT.log("[DEL]"+pathg, null);
+                       RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, pathg);
+
+                       try {
+                               handleHeaders(builder, pathg);
+                               builder.sendRequest(data, new RequestCallback() {
+
+                                       @Override
+                                       public void onError(Request arg0, Throwable arg1) {
+                                               errors.put(pathg, arg1);
+                                       }
+
+                                       @Override
+                                       public void onResponseReceived(Request arg0, Response arg1) {
+                                               if (arg1.getStatusCode() == okStatusCode)
+                                                       successPaths.add(pathg);
+                                               else if(arg1.getStatusCode() == 403)
+                                                       sessionExpired();
+                                               else if (arg1.getStatusCode() == 405)
+                                                       errors.put(pathg, new InsufficientPermissionsException("You don't have permissions to delete this resource"));
+                                               else
+                                                       errors.put(pathg, new RestException(pathg, arg1.getStatusCode(), arg1.getStatusText(), arg1.getText()));
+                                       }
+
+                               });
+                       } catch (Exception ex) {
+                               errors.put(pathg, ex);
+                       }
+               }
+       }
+
+       public boolean isComplete() {
+               return errors.size() + successPaths.size() == paths.length;
+       }
+
+       @Override
+       public boolean execute() {
+               boolean com = isComplete();
+               if (com) {
+                       if(hasErrors())
+                               for(String p : errors.keySet())
+                                       onError(p, errors.get(p));
+                       onComplete();
+                       if(isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       return false;
+               }
+               return true;
+       }
+
+
+       /**
+        * @param p
+        * @param throwable
+        */
+       public abstract void onError(String p, Throwable throwable);
+
+       public boolean hasErrors(){
+               return errors.size() >0;
+       }
+
+
+       /**
+        * Retrieve the errors.
+        *
+        * @return the errors
+        */
+       public Map<String, Throwable> getErrors() {
+               return errors;
+       }
+
+       public void debug(){
+               GWT.log("-ERRORS-->"+getErrors().size(), null);
+               for(String p : getErrors().keySet())
+                       GWT.log("error:"+p, getErrors().get(p));
+       }
+
+       @Override
+       public void onError(Throwable t) {
+
+
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/PostCommand.java b/src/org/gss_project/gss/web/client/rest/PostCommand.java
new file mode 100644 (file)
index 0000000..8135996
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+
+
+/**
+ * @author kman
+ *
+ */
+public abstract class PostCommand extends RestCommand{
+       boolean complete = false;
+       String postBody=null;
+
+       public PostCommand(final String path, String data, final int okStatusCode) {
+               this(path, data, okStatusCode, true);
+       }
+
+       public PostCommand(final String path, String data, final int okStatusCode, boolean showLoading) {
+               setShowLoadingIndicator(showLoading);
+               if(isShowLoadingIndicator())
+                       GSS.get().showLoadingIndicator("Updating ",path);
+
+               RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, path);
+
+               try {
+                       handleHeaders(builder, path);
+                       builder.sendRequest(data, new RequestCallback() {
+
+                               @Override
+                               public void onError(Request arg0, Throwable arg1) {
+                                       complete = true;
+                                       PostCommand.this.onError(arg1);
+                               }
+
+                               @Override
+                               public void onResponseReceived(Request req, Response resp) {
+                                       complete=true;
+                                       int status = resp.getStatusCode();
+                                       // Normalize IE status 1223 to a regular 204.
+                                       if (status == 1223)
+                                               status = 204;
+
+                                       if (status == okStatusCode) {
+                                               postBody = resp.getText();
+                                               onComplete();
+                                       } else if (status == 403)
+                                               sessionExpired();
+                                       else
+                                               PostCommand.this.onError(new RestException(path, status, resp.getStatusText(), resp.getText()));
+                               }
+
+                       });
+               } catch (Exception ex) {
+                       complete=true;
+                       onError(ex);
+               }
+       }
+
+       public boolean isComplete() {
+               return complete;
+       }
+
+       @Override
+       public boolean execute() {
+               boolean com = isComplete();
+               if (com) {
+                       if (isShowLoadingIndicator())
+                               GSS.get().hideLoadingIndicator();
+                       return false;
+               }
+               return true;
+       }
+
+       public String getPostBody() {
+               return postBody;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/RestCallback.java b/src/org/gss_project/gss/web/client/rest/RestCallback.java
new file mode 100644 (file)
index 0000000..b8bee48
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+
+
+/**
+ * @author kman
+ *
+ */
+public abstract class RestCallback  implements RequestCallback {
+
+       private static final int HTTP_OK = 200;
+       private String path;
+       private int okcode = -1;
+
+       public RestCallback(String aPath) {
+               path = aPath;
+       }
+
+       public RestCallback(String aPath, int okCode) {
+               path = aPath;
+               okcode = okCode;
+       }
+
+       @Override
+       public void onError(Request request, Throwable exception) {
+               handleError(request, exception);
+       }
+
+       @Override
+       public void onResponseReceived(Request request, Response response) {
+               try {
+                       if (okcode == -1 && response.getStatusCode() == HTTP_OK)
+                               handleSuccess(deserialize(response));
+                       //this one is only used for trash handling where empty trash has 201 status code
+                       else if(okcode !=-1 && (response.getStatusCode() == okcode || response.getStatusCode() == HTTP_OK))
+                               handleSuccess(deserialize(response));
+                       else if(response.getStatusCode() == 403)
+                               RestCommand.sessionExpired();
+                       else {
+                               String statusText = "";
+                               String text = "";
+                               // Ignore JavaScript errors caused by non-existent text.
+                               try {
+                                       statusText = response.getStatusText();
+                               } catch (Exception e) { }
+                               try {
+                                       text = response.getText();
+                               } catch (Exception e) { }
+                               handleError(request, new RestException(path, response.getStatusCode(), statusText, text));
+                       }
+               } catch (Exception e) {
+                       handleError(request,e);
+               }
+       }
+
+       public abstract void handleSuccess(Object object);
+
+       public abstract void handleError(Request request, Throwable exception);
+
+       public abstract Object deserialize(Response response);
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/RestCommand.java b/src/org/gss_project/gss/web/client/rest/RestCommand.java
new file mode 100644 (file)
index 0000000..7a48620
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.SessionExpiredDialog;
+
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.user.client.IncrementalCommand;
+
+/**
+ * @author kman
+ */
+public abstract class RestCommand implements IncrementalCommand {
+       protected boolean showLoadingIndicator = true;
+
+       protected void handleHeaders(String username, RequestBuilder requestBuilder, String path) {
+               String date = getDate();
+               requestBuilder.setHeader("X-GSS-Date", date);
+
+               GSS app = GSS.get();
+               String token = app.getToken();
+               if (token == null)
+                       token = "aa";
+               String resource = path.substring(app.getApiPath().length()-1,path.length());
+               String sig = calculateSig(requestBuilder.getHTTPMethod(), date, resource, base64decode(token));
+               requestBuilder.setHeader("Authorization", username + " " + sig);
+               requestBuilder.setHeader("Accept", "application/json; charset=utf-8");
+       }
+
+       protected void handleHeaders(RequestBuilder requestBuilder, String path) {
+               if (GSS.get().getCurrentUserResource() != null) {
+                       String username = GSS.get().getCurrentUserResource().getUsername();
+                       handleHeaders(username, requestBuilder, path);
+               } else
+                       GSS.get().displayError("no username");
+       }
+
+       public static native String getDate()/*-{
+               return (new Date()).toUTCString();
+       }-*/;
+
+       public static native String getDate(Long ms)/*-{
+       return (new Date(ms)).toUTCString();
+       }-*/;
+
+       public static native String calculateSig(String method, String date, String resource, String token)/*-{
+               $wnd.b64pad = "=";
+               var q = resource.indexOf('?');
+               var res = q == -1? resource: resource.substring(0, q);
+               var data = method + date + res;
+               var sig = $wnd.b64_hmac_sha1(token, data);
+               return sig;
+       }-*/;
+
+       public static native String base64decode(String encStr)/*-{
+               if (typeof atob === 'function') {
+           return atob(encStr);
+        }
+        var base64s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        var bits;
+        var decOut = "";
+        var i = 0;
+        for(; i<encStr.length; i += 4){
+            bits = (base64s.indexOf(encStr.charAt(i)) & 0xff) <<18 | (base64s.indexOf(encStr.charAt(i +1)) & 0xff) <<12 | (base64s.indexOf(encStr.charAt(i +2)) & 0xff) << 6 | base64s.indexOf(encStr.charAt(i +3)) & 0xff;
+            decOut += String.fromCharCode((bits & 0xff0000) >>16, (bits & 0xff00) >>8, bits & 0xff);
+        }
+        if(encStr.charCodeAt(i -2) == 61){
+            return(decOut.substring(0, decOut.length -2));
+        }
+        else if(encStr.charCodeAt(i -1) == 61){
+            return(decOut.substring(0, decOut.length -1));
+        }
+        else {
+            return(decOut);
+        }
+       }-*/;
+
+       public void onComplete() {}
+
+       public abstract void onError(Throwable t);
+
+       public String fixPath(String pathToFix) {
+               if(pathToFix.endsWith("/"))
+                       return pathToFix;
+               return pathToFix+"/";
+       }
+
+       /**
+        * Retrieve the showLoadingIndicator.
+        *
+        * @return the showLoadingIndicator
+        */
+       public boolean isShowLoadingIndicator() {
+               return showLoadingIndicator;
+       }
+
+       /**
+        * Modify the showLoadingIndicator.
+        *
+        * @param newShowLoadingIndicator the showLoadingIndicator to set
+        */
+       public void setShowLoadingIndicator(boolean newShowLoadingIndicator) {
+               showLoadingIndicator = newShowLoadingIndicator;
+       }
+
+       static void sessionExpired() {
+               SessionExpiredDialog dlg = new SessionExpiredDialog();
+               dlg.center();
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/RestException.java b/src/org/gss_project/gss/web/client/rest/RestException.java
new file mode 100644 (file)
index 0000000..41fde20
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+
+/**
+ * @author kman
+ *
+ */
+public class RestException extends Throwable {
+
+       private int httpStatusCode;
+    private String httpStatusText;
+    private String text;
+
+    public RestException() {
+    }
+
+    public RestException(String message) {
+            super(message);
+    }
+
+    public RestException(Throwable innerException) {
+            super(innerException);
+    }
+
+    public RestException(String message, Throwable innerException) {
+            super(message, innerException);
+    }
+
+    public RestException(String aPath, int aStatusCode, String aStatusText, String aText) {
+            super("HTTP error: " + aStatusCode+"\nPapth:"+aPath + "\nStatus text:" + aStatusText + "\nText:" + aText);
+            httpStatusCode = aStatusCode;
+            httpStatusText = aStatusText;
+            text = aText;
+    }
+
+    public int getHttpStatusCode() {
+            return httpStatusCode;
+    }
+
+    public String getHttpStatusText() {
+            return httpStatusText;
+    }
+
+    public String getText() {
+            return text;
+    }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/RestGetCallback.java b/src/org/gss_project/gss/web/client/rest/RestGetCallback.java
new file mode 100644 (file)
index 0000000..e00915e
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest;
+
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+
+/**
+ * @author kman
+ */
+public abstract class RestGetCallback implements RequestCallback {
+
+       private static final int HTTP_OK = 200;
+
+       private AsyncCallback callback;
+       private String path;
+       private int okcode = -1;
+
+       public RestGetCallback(String aPath, AsyncCallback aCallback) {
+               callback = aCallback;
+               path = aPath;
+       }
+
+       public RestGetCallback(String aPath, AsyncCallback aCallback, int okCode) {
+               callback = aCallback;
+               path = aPath;
+               okcode = okCode;
+       }
+
+       @Override
+       public void onError(Request request, Throwable exception) {
+               callback.onFailure(exception);
+       }
+
+       @Override
+       public void onResponseReceived(Request request, Response response) {
+               try {
+                       if (okcode == -1 && response.getStatusCode() == HTTP_OK)
+                               callback.onSuccess(deserialize(response));
+                       //this one is only used for trash handling where empty trash has 201 status code
+                       else if(okcode !=-1 && (response.getStatusCode() == okcode || response.getStatusCode() == HTTP_OK))
+                               callback.onSuccess(deserialize(response));
+                       else
+                               callback.onFailure(new RestException(path, response.getStatusCode(), response.getStatusText(), response.getText()));
+               } catch (Exception e) {
+                       callback.onFailure(e);
+               }
+       }
+
+       public abstract Object deserialize(Response response);
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/FileResource.java b/src/org/gss_project/gss/web/client/rest/resource/FileResource.java
new file mode 100644 (file)
index 0000000..ce48f63
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.json.client.JSONString;
+
+/**
+ * @author kman
+ */
+public class FileResource extends RestResource {
+
+       public FileResource(String aUri) {
+               super(aUri);
+       }
+
+       String name;
+
+       String owner;
+
+       String createdBy;
+
+       String modifiedBy;
+
+       Date creationDate;
+
+       Date modificationDate;
+
+       String contentType;
+
+       Long contentLength;
+
+       boolean readForAll;
+
+       boolean versioned;
+
+       Integer version;
+
+       String etag;
+
+       boolean deleted = false;
+
+       List<String> tags = new ArrayList<String>();
+
+       Set<PermissionHolder> permissions = new HashSet<PermissionHolder>();
+
+       String folderURI;
+
+       String path;
+
+       String folderName;
+       Boolean shared;
+       
+       
+       
+       
+       /**
+        * Modify the shared.
+        *
+        * @param _shared the shared to set
+        */
+       public void setShared(Boolean _shared) {
+               this.shared = _shared;
+       }
+       
+       /**
+        * Retrieve the folderName.
+        *
+        * @return the folderName
+        */
+       public String getFolderName() {
+               return folderName;
+       }
+
+       /**
+        * Modify the folderName.
+        *
+        * @param aFolderName the folderName to set
+        */
+       public void setFolderName(String aFolderName) {
+               folderName = aFolderName;
+       }
+
+       /**
+        * Retrieve the path.
+        *
+        * @return the path
+        */
+       public String getPath() {
+               return path;
+       }
+
+       /**
+        * Modify the path.
+        *
+        * @param aPath the path to set
+        */
+       public void setPath(String aPath) {
+               path = aPath;
+       }
+
+       /**
+        * Retrieve the name.
+        *
+        * @return the name
+        */
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Modify the name.
+        *
+        * @param aName the name to set
+        */
+       public void setName(String aName) {
+               name = aName;
+       }
+
+       /**
+        * Retrieve the owner.
+        *
+        * @return the owner
+        */
+       public String getOwner() {
+               return owner;
+       }
+
+       /**
+        * Modify the owner.
+        *
+        * @param newOwner the owner to set
+        */
+       public void setOwner(String newOwner) {
+               owner = newOwner;
+       }
+
+       /**
+        * Retrieve the createdBy.
+        *
+        * @return the createdBy
+        */
+       public String getCreatedBy() {
+               return createdBy;
+       }
+
+       /**
+        * Modify the createdBy.
+        *
+        * @param aCreatedBy the createdBy to set
+        */
+       public void setCreatedBy(String aCreatedBy) {
+               createdBy = aCreatedBy;
+       }
+
+       /**
+        * Retrieve the modifiedBy.
+        *
+        * @return the modifiedBy
+        */
+       public String getModifiedBy() {
+               return modifiedBy;
+       }
+
+       /**
+        * Modify the modifiedBy.
+        *
+        * @param aModifiedBy the modifiedBy to set
+        */
+       public void setModifiedBy(String aModifiedBy) {
+               modifiedBy = aModifiedBy;
+       }
+
+       /**
+        * Retrieve the creationDate.
+        *
+        * @return the creationDate
+        */
+       public Date getCreationDate() {
+               return creationDate;
+       }
+
+       /**
+        * Modify the creationDate.
+        *
+        * @param aCreationDate the creationDate to set
+        */
+       public void setCreationDate(Date aCreationDate) {
+               creationDate = aCreationDate;
+       }
+
+       /**
+        * Retrieve the modificationDate.
+        *
+        * @return the modificationDate
+        */
+       public Date getModificationDate() {
+               return modificationDate;
+       }
+
+       /**
+        * Modify the modificationDate.
+        *
+        * @param aModificationDate the modificationDate to set
+        */
+       public void setModificationDate(Date aModificationDate) {
+               modificationDate = aModificationDate;
+       }
+
+       /**
+        * Retrieve the contentType.
+        *
+        * @return the contentType
+        */
+       public String getContentType() {
+               return contentType;
+       }
+
+       /**
+        * Modify the contentType.
+        *
+        * @param newContentType the contentType to set
+        */
+       public void setContentType(String newContentType) {
+               contentType = newContentType;
+       }
+
+       /**
+        * Retrieve the contentLength.
+        *
+        * @return the contentLength
+        */
+       public Long getContentLength() {
+               return contentLength;
+       }
+
+       /**
+        * Modify the contentLength.
+        *
+        * @param newContentLength the contentLength to set
+        */
+       public void setContentLength(Long newContentLength) {
+               contentLength = newContentLength;
+       }
+
+       /**
+        * Retrieve the readForAll.
+        *
+        * @return the readForAll
+        */
+       public boolean isReadForAll() {
+               return readForAll;
+       }
+
+       /**
+        * Modify the readForAll.
+        *
+        * @param newReadForAll the readForAll to set
+        */
+       public void setReadForAll(boolean newReadForAll) {
+               readForAll = newReadForAll;
+       }
+
+       /**
+        * Retrieve the versioned.
+        *
+        * @return the versioned
+        */
+       public boolean isVersioned() {
+               return versioned;
+       }
+
+       /**
+        * Modify the versioned.
+        *
+        * @param newVersioned the versioned to set
+        */
+       public void setVersioned(boolean newVersioned) {
+               versioned = newVersioned;
+       }
+
+       /**
+        * Retrieve the version.
+        *
+        * @return the version
+        */
+       public Integer getVersion() {
+               return version;
+       }
+
+       /**
+        * Modify the version.
+        *
+        * @param aVersion the version to set
+        */
+       public void setVersion(Integer aVersion) {
+               version = aVersion;
+       }
+
+       /**
+        * Retrieve the etag.
+        *
+        * @return the etag
+        */
+       public String getEtag() {
+               return etag;
+       }
+
+       /**
+        * Modify the etag.
+        *
+        * @param anEtag the etag to set
+        */
+       public void setEtag(String anEtag) {
+               etag = anEtag;
+       }
+
+       /**
+        * Retrieve the tags.
+        *
+        * @return the tags
+        */
+       public List<String> getTags() {
+               return tags;
+       }
+
+       /**
+        * Modify the tags.
+        *
+        * @param newTags the tags to set
+        */
+       public void setTags(List<String> newTags) {
+               tags = newTags;
+       }
+
+       /**
+        * Retrieve the permissions.
+        *
+        * @return the permissions
+        */
+       public Set<PermissionHolder> getPermissions() {
+               return permissions;
+       }
+
+       /**
+        * Modify the permissions.
+        *
+        * @param newPermissions the permissions to set
+        */
+       public void setPermissions(Set<PermissionHolder> newPermissions) {
+               permissions = newPermissions;
+       }
+
+       /**
+        * Retrieve the deleted.
+        *
+        * @return the deleted
+        */
+       public boolean isDeleted() {
+               return deleted;
+       }
+
+       /**
+        * Modify the deleted.
+        *
+        * @param newDeleted the deleted to set
+        */
+       public void setDeleted(boolean newDeleted) {
+               deleted = newDeleted;
+       }
+
+       /**
+        * Retrieve the folderURI.
+        *
+        * @return the folderURI
+        */
+       public String getFolderURI() {
+               return folderURI;
+       }
+
+       /**
+        * Modify the folderURI.
+        *
+        * @param aFolderURI the folderURI to set
+        */
+       public void setFolderURI(String aFolderURI) {
+               folderURI = aFolderURI;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject metadata = (JSONObject) JSONParser.parse(text);
+               name = unmarshallString(metadata, "name");
+               name = URL.decodeComponent(name);
+               path = unmarshallString(metadata, "path");
+               path = URL.decodeComponent(path);
+               owner = unmarshallString(metadata, "owner");
+               contentType = unmarshallString(metadata, "content");
+               readForAll = unmarshallBoolean(metadata, "readForAll");
+               versioned = unmarshallBoolean(metadata, "versioned");
+               createdBy = unmarshallString(metadata, "createdBy");
+               modifiedBy = unmarshallString(metadata, "modifiedBy");
+               setShared(unmarshallBoolean(metadata, "shared"));
+               if (metadata.get("version") != null)
+                       version = new Integer(metadata.get("version").toString());
+
+               deleted = unmarshallBoolean(metadata, "deleted");
+               if (deleted)
+                       GWT.log("FOUND A DELETED FILE:" + name, null);
+
+               if (metadata.get("folder") != null) {
+                       JSONObject folder = metadata.get("folder").isObject();
+                       folderURI = unmarshallString(folder, "uri");
+                       folderName = unmarshallString(folder, "name");
+                       if(folderName != null)
+                               folderName = URL.decodeComponent(folderName);
+               }
+
+               if (metadata.get("permissions") != null) {
+                       JSONArray perm = metadata.get("permissions").isArray();
+                       if (perm != null)
+                               for (int i = 0; i < perm.size(); i++) {
+                                       JSONObject obj = perm.get(i).isObject();
+                                       if (obj != null) {
+                                               PermissionHolder permission = new PermissionHolder();
+                                               if (obj.get("user") != null)
+                                                       permission.setUser(unmarshallString(obj, "user"));
+                                               if (obj.get("group") != null) {
+                                                       String group = unmarshallString(obj, "group");
+                                                       group = URL.decodeComponent(group);
+                                                       permission.setGroup(group);
+                                               }
+                                               permission.setRead(unmarshallBoolean(obj, "read"));
+                                               permission.setWrite(unmarshallBoolean(obj, "write"));
+                                               permission.setModifyACL(unmarshallBoolean(obj, "modifyACL"));
+                                               permissions.add(permission);
+                                       }
+                               }
+
+               }
+               if (metadata.get("tags") != null) {
+                       JSONArray perm = metadata.get("tags").isArray();
+                       if (perm != null)
+                               for (int i = 0; i < perm.size(); i++) {
+                                       JSONString obj = perm.get(i).isString();
+                                       if(obj != null)
+                                               tags.add(URL.decodeComponent(obj.stringValue()));
+                               }
+               }
+               if (metadata.get("creationDate") != null)
+                       creationDate = new Date(new Long(metadata.get("creationDate").toString()));
+               if (metadata.get("modificationDate") != null)
+                       modificationDate = new Date(new Long(metadata.get("modificationDate").toString()));
+               if (metadata.get("size") != null)
+                       contentLength = Long.parseLong(metadata.get("size").toString());
+       }
+
+       /**
+        * Return the file size in a humanly readable form, using SI units to denote
+        * size information, e.g. 1 KB = 1000 B (bytes).
+        *
+        * @return the fileSize
+        */
+       public String getFileSizeAsString() {
+               return getFileSizeAsString(contentLength);
+       }
+
+       /**
+        * Return the given size in a humanly readable form, using SI units to denote
+        * size information, e.g. 1 KB = 1000 B (bytes).
+        *
+        * @param size in bytes
+        * @return the size in human readable string
+        */
+       public static String getFileSizeAsString(long size) {
+               if (size < 1024)
+                       return String.valueOf(size) + " B";
+               else if (size < 1024 * 1024)
+                       return getSize(size, 1024D) + " KB";
+               else if (size < 1024 * 1024 * 1024)
+                       return getSize(size, (1024D * 1024D)) + " MB";
+               return getSize(size, (1024D * 1024D * 1024D)) + " GB";
+       }
+
+       private static String getSize(Long size, Double division) {
+               Double res = Double.valueOf(size.toString()) / division;
+               NumberFormat nf = NumberFormat.getFormat("######.#");
+               return nf.format(res);
+       }
+
+       public boolean isShared(){
+               return shared;
+       }
+
+       public boolean isShared(String ownerUser){
+               GWT.log("OWNER USER:"+ownerUser, null);
+               if (isReadForAll())
+                       return true;
+               if(permissions != null)
+                       for(PermissionHolder perm : permissions){
+                               if(perm.getUser() != null && !ownerUser.equals(perm.getUser()))
+                                       return true;
+                               if(perm.getGroup() != null)
+                                       return true;
+                       }
+               return false;
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               if(modificationDate != null)
+                       return getDate(modificationDate.getTime());
+               return null;
+       }
+}
+
diff --git a/src/org/gss_project/gss/web/client/rest/resource/FolderResource.java b/src/org/gss_project/gss/web/client/rest/resource/FolderResource.java
new file mode 100644 (file)
index 0000000..c6e630f
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * Copyright 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.gss_project.gss.web.client.rest.resource;
+
+import org.gss_project.gss.web.client.DisplayHelper;
+import org.gss_project.gss.web.client.GSS;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand.Cached;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.user.client.ui.TreeItem;
+
+/**
+ * @author kman
+ */
+public class FolderResource extends RestResource {
+
+       public FolderResource(String aUri) {
+               super(aUri);
+       }
+
+       String name;
+
+       String owner;
+
+       String createdBy;
+
+       String modifiedBy;
+
+       Date creationDate;
+
+       Date modificationDate;
+
+       List<String> filePaths = new LinkedList<String>();
+
+       List<String> subfolderPaths = new LinkedList<String>();
+
+       Set<PermissionHolder> permissions = new HashSet<PermissionHolder>();
+
+       List<FolderResource> folders = new ArrayList<FolderResource>();
+
+       List<FileResource> files = new ArrayList<FileResource>();
+
+       String parentURI;
+
+       boolean deleted = false;
+
+       boolean needsExpanding = false;
+
+       String parentName;
+
+       private boolean filesExpanded=false;
+
+       boolean readForAll;
+       
+       Boolean shared;
+       
+       
+       
+       
+       
+       /**
+        * Modify the shared.
+        *
+        * @param shared the shared to set
+        */
+       public void setShared(Boolean shared) {
+               this.shared = shared;
+       }
+
+       /**
+        * Modify the parentName.
+        *
+        * @param aParentName the parentName to set
+        */
+       public void setParentName(String aParentName) {
+               parentName = aParentName;
+       }
+
+       /**
+        * Retrieve the name.
+        *
+        * @return the name
+        */
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Modify the name.
+        *
+        * @param aName the name to set
+        */
+       public void setName(String aName) {
+               name = aName;
+       }
+
+       /**
+        * Retrieve the owner.
+        *
+        * @return the owner
+        */
+       public String getOwner() {
+               return owner;
+       }
+
+       /**
+        * Modify the owner.
+        *
+        * @param anOwner the owner to set
+        */
+       public void setOwner(String anOwner) {
+               owner = anOwner;
+       }
+
+       /**
+        * Retrieve the createdBy.
+        *
+        * @return the createdBy
+        */
+       public String getCreatedBy() {
+               return createdBy;
+       }
+
+       /**
+        * Modify the createdBy.
+        *
+        * @param aCreatedBy the createdBy to set
+        */
+       public void setCreatedBy(String aCreatedBy) {
+               createdBy = aCreatedBy;
+       }
+
+       /**
+        * Retrieve the modifiedBy.
+        *
+        * @return the modifiedBy
+        */
+       public String getModifiedBy() {
+               return modifiedBy;
+       }
+
+       /**
+        * Modify the modifiedBy.
+        *
+        * @param aModifiedBy the modifiedBy to set
+        */
+       public void setModifiedBy(String aModifiedBy) {
+               modifiedBy = aModifiedBy;
+       }
+
+       /**
+        * Retrieve the creationDate.
+        *
+        * @return the creationDate
+        */
+       public Date getCreationDate() {
+               return creationDate;
+       }
+
+       /**
+        * Modify the creationDate.
+        *
+        * @param aCreationDate the creationDate to set
+        */
+       public void setCreationDate(Date aCreationDate) {
+               creationDate = aCreationDate;
+       }
+
+       /**
+        * Retrieve the modificationDate.
+        *
+        * @return the modificationDate
+        */
+       public Date getModificationDate() {
+               return modificationDate;
+       }
+
+       /**
+        * Modify the modificationDate.
+        *
+        * @param aModificationDate the modificationDate to set
+        */
+       public void setModificationDate(Date aModificationDate) {
+               modificationDate = aModificationDate;
+       }
+
+       /**
+        * Retrieve the filePaths.
+        *
+        * @return the filePaths
+        */
+       public List<String> getFilePaths() {
+               return filePaths;
+       }
+
+       /**
+        * Modify the filePaths.
+        *
+        * @param newFilePaths the filePaths to set
+        */
+       public void setFilePaths(List<String> newFilePaths) {
+               filePaths = newFilePaths;
+       }
+
+       /**
+        * Retrieve the subfolderPaths.
+        *
+        * @return the subfolderPaths
+        */
+       public List<String> getSubfolderPaths() {
+               return subfolderPaths;
+       }
+
+       /**
+        * Modify the subfolderPaths.
+        *
+        * @param newSubfolderPaths the subfolderPaths to set
+        */
+       public void setSubfolderPaths(List<String> newSubfolderPaths) {
+               subfolderPaths = newSubfolderPaths;
+       }
+
+       /**
+        * Retrieve the permissions.
+        *
+        * @return the permissions
+        */
+       public Set<PermissionHolder> getPermissions() {
+               return permissions;
+       }
+
+       /**
+        * Modify the permissions.
+        *
+        * @param newPermissions the permissions to set
+        */
+       public void setPermissions(Set<PermissionHolder> newPermissions) {
+               permissions = newPermissions;
+       }
+
+       /**
+        * Retrieve the deleted.
+        *
+        * @return the deleted
+        */
+       public boolean isDeleted() {
+               return deleted;
+       }
+
+       /**
+        * Modify the deleted.
+        *
+        * @param newDeleted the deleted to set
+        */
+       public void setDeleted(boolean newDeleted) {
+               deleted = newDeleted;
+       }
+
+       public void removeSubfolderPath(String spath) {
+               if (subfolderPaths.remove(spath))
+                       return;
+               else if (subfolderPaths.remove(spath + "/"))
+                       return;
+               else
+                       subfolderPaths.remove(spath.substring(0, spath.length() - 1));
+       }
+
+       /**
+        * Retrieve the folders.
+        *
+        * @return the folders
+        */
+       public List<FolderResource> getFolders() {
+               return folders;
+       }
+
+       /**
+        * Modify the folders.
+        *
+        * @param newFolders the folders to set
+        */
+       public void setFolders(List<FolderResource> newFolders) {
+               folders = newFolders;
+       }
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<FileResource> getFiles() {
+               return files;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFiles the files to set
+        */
+       public void setFiles(List<FileResource> newFiles) {
+               files = newFiles;
+       }
+
+       /**
+        * Retrieve the parentURI.
+        *
+        * @return the parentURI
+        */
+       public String getParentURI() {
+               return parentURI;
+       }
+
+       /**
+        * Modify the parentURI.
+        *
+        * @param aParentURI the parentURI to set
+        */
+       public void setParentURI(String aParentURI) {
+               parentURI = aParentURI;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject json = (JSONObject) JSONParser.parse(text);
+               name = unmarshallString(json, "name");
+               owner = unmarshallString(json, "owner");
+               createdBy = unmarshallString(json, "createdBy");
+               modifiedBy = unmarshallString(json, "modifiedBy");
+               deleted = unmarshallBoolean(json, "deleted");
+               shared = unmarshallBoolean(json, "shared");
+               readForAll = unmarshallBoolean(json, "readForAll");
+               if (deleted)
+                       GWT.log("FOUND A DELETED FOLDER:" + name, null);
+
+               if (json.get("parent") != null) {
+                       JSONObject parent = json.get("parent").isObject();
+                       parentURI = unmarshallString(parent, "uri");
+                       parentName = unmarshallString(parent, "name");
+               }
+
+               if (json.get("permissions") != null) {
+                       JSONArray perm = json.get("permissions").isArray();
+                       if (perm != null)
+                               for (int i = 0; i < perm.size(); i++) {
+                                       JSONObject obj = perm.get(i).isObject();
+                                       if (obj != null) {
+                                               PermissionHolder permission = new PermissionHolder();
+                                               if (obj.get("user") != null)
+                                                       permission.setUser(unmarshallString(obj, "user"));
+                                               if (obj.get("group") != null)
+                                                       permission.setGroup(URL.decodeComponent(unmarshallString(obj, "group")));
+                                               permission.setRead(unmarshallBoolean(obj, "read"));
+                                               permission.setWrite(unmarshallBoolean(obj, "write"));
+                                               permission.setModifyACL(unmarshallBoolean(obj, "modifyACL"));
+                                               permissions.add(permission);
+                                       }
+                               }
+               }
+               if (json.get("folders") != null) {
+                       JSONArray subs = json.get("folders").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject so = subs.get(i).isObject();
+                                       if (so != null) {
+                                               String subUri = unmarshallString(so, "uri");
+                                               String subName = unmarshallString(so, "name");
+                                               if (subUri != null && subName != null) {
+                                                       if (!subUri.endsWith("/"))
+                                                               subUri = subUri + "/";
+                                                       FolderResource sub = new FolderResource(subUri);
+                                                       sub.setName(subName);
+                                                       sub.setParentURI(uri);
+                                                       sub.setParentName(name);
+                                                       sub.setNeedsExpanding(true);
+                                                       folders.add(sub);
+                                                       subfolderPaths.add(subUri);
+                                               }
+                                       }
+                               }
+               }
+               if (json.get("files") != null) {
+                       JSONArray subs = json.get("files").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject fo = subs.get(i).isObject();
+                                       if (fo != null) {
+                                               String fname = unmarshallString(fo, "name");
+                                               String fowner = unmarshallString(fo, "owner");
+                                               String fcontent = unmarshallString(fo, "content");
+                                               String fpath = unmarshallString(fo, "path");
+                                               Boolean fshared = unmarshallBoolean(fo, "shared");
+                                               fpath = URL.decodeComponent(fpath);
+                                               Integer fversion = null;
+                                               if (fo.get("version") != null)
+                                                       fversion = new Integer(fo.get("version").toString());
+                                               boolean fdeleted = unmarshallBoolean(fo, "deleted");
+                                               Date fcreationDate = null;
+                                               if (fo.get("creationDate") != null)
+                                                       fcreationDate = new Date(new Long(fo.get("creationDate").toString()));
+                                               Date fmodificationDate = null;
+                                               if (fo.get("modificationDate") != null)
+                                                       fmodificationDate = new Date(new Long(fo.get("modificationDate").toString()));
+                                               String furi = unmarshallString(fo, "uri");
+                                               Long fsize = 0L;
+                                               if (fo.get("size") != null)
+                                                       fsize = new Long(fo.get("size").toString());
+                                               filePaths.add(furi);
+                                               FileResource fs = new FileResource(furi);
+                                               fs.setName(fname);
+                                               fs.setOwner(fowner);
+                                               fs.setPath(fpath);
+                                               fs.setVersioned(unmarshallBoolean(fo, "versioned"));
+                                               fs.setVersion(fversion);
+                                               fs.setContentLength(fsize);
+                                               fs.setDeleted(fdeleted);
+                                               fs.setShared(fshared);
+                                               fs.setCreationDate(fcreationDate);
+                                               fs.setModificationDate(fmodificationDate);
+                                               fs.setContentType(fcontent);
+                                               files.add(fs);
+                                       }
+                               }
+               }
+               if (json.get("creationDate") != null)
+                       creationDate = new Date(new Long(json.get("creationDate").toString()));
+               if (json.get("modificationDate") != null)
+                       modificationDate = new Date(new Long(json.get("modificationDate").toString()));
+       }
+
+       public String getParentName(){
+               return parentName;
+       }
+
+       /**
+        * Retrieve the needsExpanding.
+        *
+        * @return the needsExpanding
+        */
+       public boolean isNeedsExpanding() {
+               return needsExpanding;
+       }
+
+       /**
+        * Modify the needsExpanding.
+        *
+        * @param newNeedsExpanding the needsExpanding to set
+        */
+       public void setNeedsExpanding(boolean newNeedsExpanding) {
+               needsExpanding = newNeedsExpanding;
+       }
+
+       public boolean isShared(){
+               return shared;
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               if(modificationDate != null)
+                       return getDate(modificationDate.getTime());
+               return null;
+       }
+
+       public MultipleGetCommand.Cached[] getCache(){
+               if(getSubfolderPaths().size() != getFolders().size()){
+                       GWT.log("MISMATCH IN PATH AND FOLDERS SIZE", null);
+                       return null;
+               }
+               MultipleGetCommand.Cached[] result = new MultipleGetCommand.Cached[getSubfolderPaths().size()];
+               for(int i=0; i<getFolders().size();i++){
+                       FolderResource r = getFolders().get(i);
+                       Cached c = new Cached();
+                       c.cache=r;
+                       c.uri=r.uri;
+                       result[i] = c;
+               }
+               return result;
+       }
+
+       public MultipleGetCommand.Cached[] getFileCache(){
+               if(getFilePaths().size() != getFiles().size()){
+                       GWT.log("MISMATCH IN PATH AND FILES SIZE", null);
+                       return null;
+               }
+               if(!filesExpanded)
+                       return null;
+               MultipleGetCommand.Cached[] result = new MultipleGetCommand.Cached[getFilePaths().size()];
+               for(int i=0; i<getFiles().size();i++){
+                       FileResource r = getFiles().get(i);
+                       Cached c = new Cached();
+                       c.cache=r;
+                       c.uri=r.uri;
+                       result[i] = c;
+               }
+               return result;
+       }
+
+       public void setFilesExpanded(boolean newFilesExpanded) {
+               filesExpanded = newFilesExpanded;
+       }
+       /**
+        * this method constructs the partial path of a given TreeItem using it's text
+        *
+        * @param selectedItem the selectedItem to check
+        */
+       private String constructPartialPath(TreeItem selectedItem){
+          String result = DisplayHelper.trim(selectedItem.getText());
+          TreeItem parent = selectedItem.getParentItem();
+          while (!(DisplayHelper.trim(parent.getText()).equals("My Shared") || DisplayHelper.trim(parent.getText()).equals("Other's Shared")||DisplayHelper.trim(parent.getText()).equals("Trash"))){
+             result = DisplayHelper.trim(parent.getText()) + "/" + result;
+             if(result.equals("My Shared")||result.equals("Other's Shared")) return result;
+             parent = parent.getParentItem();
+          }
+
+          return result;
+       }
+       /**
+        * examine whether a folder name like "Trash", "My Shared", "Other's Shared" is inside path
+        *
+        * @param selectedItem the selectedTreeItem to check
+        */
+
+       private boolean containsFolder(TreeItem selectedItem, String folderName){
+               TreeItem parent = selectedItem.getParentItem();
+               while (parent != null){
+                       String parentItemText = parent.getText();
+                       String parentItemTextTr = DisplayHelper.trim(parentItemText);
+                       if(parentItemTextTr.equals(folderName)) return true;
+                       parent = parent.getParentItem();
+                       }
+               return false;
+       }
+       @Override
+       public String constructUri(TreeItem treeItem, String path){
+               String constructedUri = "";
+               if(containsFolder(treeItem, "My Shared")){
+                       //case: selected folders below My Shared folder
+                       String partialUri = constructPartialPath(treeItem);
+                       constructedUri = constructedUri + "Files/shared/" + partialUri;
+                       return constructedUri;
+               }else if(containsFolder(treeItem, "Other's Shared")){
+                       //case: selected folders below Other's Shared folder
+                       String partialPath = constructPartialPath(treeItem);
+                       constructedUri = constructedUri + "Files/others/"+ partialPath;
+                       return constructedUri;
+               }
+               else if(getParentURI()==null){
+                       if(containsFolder(treeItem, "Trash")){
+                               //case: selected folders below Trash folder
+                               String partialUri = constructPartialPath(treeItem);
+                               constructedUri = constructedUri + "Files/trash/" + partialUri;
+                               return constructedUri;
+                       }
+                       //case: home folder is selected
+                       constructedUri = constructedUri + "Files/files/" + getName();
+                       return constructedUri;
+               }
+               else if(treeItem.getParentItem() == null){
+                       //this is the case when the user uses the browser's forward arrow to navigate through other's
+                       //shared folders and item.getParentItem is null only inside other's shared folder
+                       String apiPath = GSS.get().getApiPath();
+                       String newPath = getParentURI().substring(apiPath.lastIndexOf("/"));
+                       constructedUri = constructedUri + "Files"+ newPath + getName();
+                       return constructedUri;
+               }
+               else{
+                       String finalUri = getParentURI().substring(path.lastIndexOf("/")) + getName();
+                       constructedUri = constructedUri + "Files"+ finalUri;
+                       return constructedUri;
+               }
+
+       }
+
+       /**
+        * Retrieve the readForAll.
+        *
+        * @return the readForAll
+        */
+       public boolean isReadForAll() {
+               return readForAll;
+       }
+       /**
+        * Modify the readForAll.
+        *
+        * @param newReadForAll the readForAll to set
+        */
+       public void setReadForAll(boolean newReadForAll) {
+               readForAll = newReadForAll;
+       }
+       
+       
+       public int countNotDeletedSubfolders(){
+               int count=0;
+               for(FolderResource r : folders){
+                       if(!r.isDeleted())
+                               count++;
+               }
+               return count;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/GroupResource.java b/src/org/gss_project/gss/web/client/rest/resource/GroupResource.java
new file mode 100644 (file)
index 0000000..72b78eb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONParser;
+
+/**
+ * @author kman
+ */
+public class GroupResource extends RestResource {
+
+       public GroupResource(String aUri) {
+               super(aUri);
+       }
+
+       List<String> userPaths = new ArrayList<String>();
+
+       /**
+        * Retrieve the userPaths.
+        *
+        * @return the userPaths
+        */
+       public List<String> getUserPaths() {
+               return userPaths;
+       }
+
+       /**
+        * Modify the userPaths.
+        *
+        * @param newUserPaths the userPaths to set
+        */
+       public void setUserPaths(List<String> newUserPaths) {
+               userPaths = newUserPaths;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONArray array = (JSONArray) JSONParser.parse(text);
+               if (array != null)
+                       for (int i = 0; i < array.size(); i++)
+                               if(array.get(i).isString() != null)
+                                       getUserPaths().add(array.get(i).isString().stringValue());
+       }
+       @Override
+       public String getName() {
+               String[] names = uri.split("/");
+               return URL.decodeComponent(names[names.length - 1]);
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/GroupUserResource.java b/src/org/gss_project/gss/web/client/rest/resource/GroupUserResource.java
new file mode 100644 (file)
index 0000000..842a33f
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+
+
+/**
+ * @author kman
+ *
+ */
+public class GroupUserResource extends RestResource{
+
+       public GroupUserResource(String aUri) {
+               super(aUri);
+       }
+
+       String username;
+       String name;
+       String home;
+
+       /**
+        * Retrieve the username.
+        *
+        * @return the username
+        */
+       public String getUsername() {
+               return username;
+       }
+
+       /**
+        * Modify the username.
+        *
+        * @param aUsername the username to set
+        */
+       public void setUsername(String aUsername) {
+               username = aUsername;
+       }
+
+       /**
+        * Retrieve the name.
+        *
+        * @return the name
+        */
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Modify the name.
+        *
+        * @param aName the name to set
+        */
+       public void setName(String aName) {
+               name = aName;
+       }
+
+       /**
+        * Retrieve the home.
+        *
+        * @return the home
+        */
+       public String getHome() {
+               return home;
+       }
+
+       /**
+        * Modify the home.
+        *
+        * @param aHome the home to set
+        */
+       public void setHome(String aHome) {
+               home = aHome;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject json = (JSONObject) JSONParser.parse(text);
+               name = unmarshallString(json, "name");
+               home = unmarshallString(json, "home");
+               username = unmarshallString(json, "username");
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/GroupsResource.java b/src/org/gss_project/gss/web/client/rest/resource/GroupsResource.java
new file mode 100644 (file)
index 0000000..2f1f8df
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+/**
+ * @author kman
+ */
+public class GroupsResource extends RestResource {
+
+       public GroupsResource(String aUri) {
+               super(aUri);
+       }
+
+       List<String> groupPaths = new ArrayList<String>();
+
+       /**
+        * Retrieve the groupPaths.
+        *
+        * @return the groupPaths
+        */
+       public List<String> getGroupPaths() {
+               return groupPaths;
+       }
+
+       /**
+        * Modify the groupPaths.
+        *
+        * @param newGroupPaths the groupPaths to set
+        */
+       public void setGroupPaths(List<String> newGroupPaths) {
+               groupPaths = newGroupPaths;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONArray array = (JSONArray) JSONParser.parse(text);
+               if (array != null)
+                       for (int i = 0; i < array.size(); i++) {
+                               JSONObject js = array.get(i).isObject();
+                               if(js != null){
+                                       String groupUri = unmarshallString(js, "uri");
+                                       if(groupUri != null)
+                                               getGroupPaths().add(groupUri);
+                               }
+                       }
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/MyFolderResource.java b/src/org/gss_project/gss/web/client/rest/resource/MyFolderResource.java
new file mode 100644 (file)
index 0000000..9a0a307
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+
+/**
+ * @author kman
+ *
+ */
+public class MyFolderResource extends RestResourceWrapper{
+       
+       /**
+        * @param aUri
+        */
+       public MyFolderResource(FolderResource resource) {
+               super(resource);
+       }
+       
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/OtherUserResource.java b/src/org/gss_project/gss/web/client/rest/resource/OtherUserResource.java
new file mode 100644 (file)
index 0000000..4072ed2
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import org.gss_project.gss.web.client.rest.MultipleGetCommand;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand.Cached;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.user.client.ui.TreeItem;
+
+
+/**
+ * @author kman
+ *
+ */
+public class OtherUserResource extends RestResource{
+       public OtherUserResource(String aUri) {
+               super(aUri);
+       }
+
+       String username;
+       List<String> filePaths = new LinkedList<String>();
+       List<String> subfolderPaths = new LinkedList<String>();
+       List<FolderResource> folders = new ArrayList<FolderResource>();
+       List<FileResource> files = new ArrayList<FileResource>();
+
+       private boolean filesExpanded=false;
+       /**
+        * Retrieve the username.
+        *
+        * @return the username
+        */
+       public String getUsername() {
+               return username;
+       }
+
+       /**
+        * Modify the username.
+        *
+        * @param aUsername the username to set
+        */
+       public void setUsername(String aUsername) {
+               username = aUsername;
+       }
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<String> getFilePaths() {
+               return filePaths;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFiles the files to set
+        */
+       public void setFilePaths(List<String> newFiles) {
+               filePaths = newFiles;
+       }
+
+       /**
+        * Retrieve the subfolders.
+        *
+        * @return the subfolders
+        */
+       public List<String> getSubfolderPaths() {
+               return subfolderPaths;
+       }
+
+       /**
+        * Modify the subfolders.
+        *
+        * @param subfolders the subfolders to set
+        */
+       public void setSubfolderPaths(List<String> subfolders) {
+               subfolderPaths = subfolders;
+       }
+
+       /**
+        * Retrieve the folders.
+        *
+        * @return the folders
+        */
+       public List<FolderResource> getFolders() {
+               return folders;
+       }
+
+       /**
+        * Modify the folders.
+        *
+        * @param newFolders the folders to set
+        */
+       public void setFolders(List<FolderResource> newFolders) {
+               folders = newFolders;
+       }
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<FileResource> getFiles() {
+               return files;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFiles the files to set
+        */
+       public void setFiles(List<FileResource> newFiles) {
+               files = newFiles;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject json = (JSONObject) JSONParser.parse(text);
+               if (json.get("folders") != null) {
+                       JSONArray subs = json.get("folders").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject so = subs.get(i).isObject();
+                                       if (so != null) {
+                                               String subUri = unmarshallString(so, "uri");
+                                               String subName = unmarshallString(so, "name");
+                                               if (subUri != null && subName != null) {
+                                                       if (!subUri.endsWith("/"))
+                                                               subUri = subUri + "/";
+                                                       FolderResource sub = new FolderResource(subUri);
+                                                       sub.setName(subName);
+                                                       sub.setNeedsExpanding(true);
+                                                       folders.add(sub);
+                                                       subfolderPaths.add(subUri);
+                                               }
+                                       }
+                               }
+               }
+               if (json.get("files") != null) {
+                       JSONArray subs = json.get("files").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject fo = subs.get(i).isObject();
+                                       if (fo != null) {
+                                               String fname = unmarshallString(fo, "name");
+                                               String fowner = unmarshallString(fo, "owner");
+                                               String fcontent = unmarshallString(fo, "content");
+                                               Boolean fshared = unmarshallBoolean(fo,"shared");
+                                               boolean fversioned = unmarshallBoolean(fo,"versioned");
+                                               Integer fversion = null;
+                                               if (fo.get("version") != null)
+                                                       fversion = new Integer(fo.get("version").toString());
+                                               boolean fdeleted = unmarshallBoolean(fo, "deleted");
+                                               Date fcreationDate = null;
+                                               if (fo.get("creationDate") != null)
+                                                       fcreationDate = new Date(new Long(fo.get("creationDate").toString()));
+                                               Date fmodificationDate = null;
+                                               if (fo.get("modificationDate") != null)
+                                                       fmodificationDate = new Date(new Long(fo.get("modificationDate").toString()));
+                                               String furi = unmarshallString(fo,"uri");
+                                               Long fsize = 0L;
+                                               if(fo.get("size") != null)
+                                                       fsize = new Long(fo.get("size").toString());
+                                               filePaths.add(furi);
+                                               String fpath = unmarshallString(fo, "path");
+                                               fpath = URL.decodeComponent(fpath);
+                                               FileResource fs = new FileResource(furi);
+                                               fs.setName(fname);
+                                               fs.setPath(fpath);
+                                               fs.setOwner(fowner);
+                                               fs.setVersion(fversion);
+                                               fs.setContentLength(fsize);
+                                               fs.setDeleted(fdeleted);
+                                               fs.setCreationDate(fcreationDate);
+                                               fs.setModificationDate(fmodificationDate);
+                                               fs.setShared(fshared);
+                                               fs.setVersioned(fversioned);
+                                               fs.setContentType(fcontent);
+                                               files.add(fs);
+                                       }
+                               }
+               }
+       }
+
+       @Override
+       public String getName(){
+               String[] names = uri.split("/");
+               return names[names.length -1];
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+
+       public MultipleGetCommand.Cached[] getFileCache(){
+               if(getFilePaths().size() != getFiles().size()){
+                       GWT.log("MISMATCH IN PATH AND FILES SIZE", null);
+                       return null;
+               }
+               if(!filesExpanded)
+                       return null;
+               MultipleGetCommand.Cached[] result = new MultipleGetCommand.Cached[getFilePaths().size()];
+               for(int i=0; i<getFiles().size();i++){
+                       FileResource r = getFiles().get(i);
+                       Cached c = new Cached();
+                       c.cache=r;
+                       c.uri=r.uri;
+                       result[i] = c;
+               }
+               return result;
+       }
+
+       public void setFilesExpanded(boolean newFilesExpanded) {
+               filesExpanded = newFilesExpanded;
+       }
+
+       @Override
+       public String constructUri(TreeItem treeItem, String path){
+               String constructedUri = "Files/others/"+ getName();
+               return constructedUri;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/OthersFolderResource.java b/src/org/gss_project/gss/web/client/rest/resource/OthersFolderResource.java
new file mode 100644 (file)
index 0000000..87afdbe
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+
+/**
+ * @author kman
+ *
+ */
+public class OthersFolderResource extends RestResourceWrapper{
+       
+       /**
+        * @param aUri
+        */
+       public OthersFolderResource(FolderResource resource) {
+               super(resource);
+               this.resource = resource;
+               // TODO Auto-generated constructor stub
+       }
+       
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/OthersResource.java b/src/org/gss_project/gss/web/client/rest/resource/OthersResource.java
new file mode 100644 (file)
index 0000000..3121679
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.user.client.ui.TreeItem;
+
+/**
+ * @author kman
+ */
+public class OthersResource extends RestResource {
+
+       public OthersResource(String aUri) {
+               super(aUri);
+       }
+
+       List<String> others = new ArrayList<String>();
+       List<OtherUserResource> otherUsers = new ArrayList<OtherUserResource>();
+
+       /**
+        * Retrieve the others.
+        *
+        * @return the others
+        */
+       public List<String> getOthers() {
+               return others;
+       }
+
+       /**
+        * Modify the others.
+        *
+        * @param newOthers the others to set
+        */
+       public void setOthers(List<String> newOthers) {
+               others = newOthers;
+       }
+
+       public List<OtherUserResource> getOtherUsers() {
+               return otherUsers;
+       }
+
+       public void setOtherUsers(List<OtherUserResource> newOtherUsers) {
+               otherUsers = newOtherUsers;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONArray array = (JSONArray) JSONParser.parse(text);
+               if (array != null)
+                       for (int i = 0; i < array.size(); i++) {
+                               JSONObject js = array.get(i).isObject();
+                               if (js != null) {
+                                       String othersUri = unmarshallString(js, "uri");
+                                       String username = unmarshallString(js, "username");
+                                       if(othersUri != null){
+                                               getOthers().add(othersUri);
+                                               OtherUserResource r = new OtherUserResource(othersUri);
+                                               r.setUsername(username);
+                                               getOtherUsers().add(r);
+                                       }
+                               }
+                       }
+       }
+
+       public String getUsernameOfUri(String u){
+               if(!u.endsWith("/"))
+                       u=u+"/";
+               for(OtherUserResource o : getOtherUsers()){
+                       GWT.log("CHECKING USER URI:"+o.getUri(), null);
+                       String toCheck = o.getUri();
+                       if(!toCheck.endsWith("/"))
+                               toCheck=toCheck+"/";
+                       if(toCheck.equals(u))
+                               return o.getUsername();
+               }
+               return null;
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+
+       @Override
+       public String constructUri(TreeItem treeItem,String path){
+               String constructedUri = "Files/"+ path.substring(path.lastIndexOf("/")+1) + "others/";
+               return constructedUri;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/PermissionHolder.java b/src/org/gss_project/gss/web/client/rest/resource/PermissionHolder.java
new file mode 100644 (file)
index 0000000..208c7b7
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.io.Serializable;
+
+
+/**
+ * @author kman
+ *
+ */
+public class PermissionHolder implements Serializable{
+
+       private String user;
+       private String group;
+       private boolean read;
+       private boolean write;
+       private boolean modifyACL;
+
+       /**
+        * Retrieve the user.
+        *
+        * @return the user
+        */
+       public String getUser() {
+               return user;
+       }
+
+       /**
+        * Modify the user.
+        *
+        * @param aUser the user to set
+        */
+       public void setUser(String aUser) {
+               user = aUser;
+       }
+
+       /**
+        * Retrieve the group.
+        *
+        * @return the group
+        */
+       public String getGroup() {
+               return group;
+       }
+
+       /**
+        * Modify the group.
+        *
+        * @param aGroup the group to set
+        */
+       public void setGroup(String aGroup) {
+               group = aGroup;
+       }
+
+       /**
+        * Retrieve the read.
+        *
+        * @return the read
+        */
+       public boolean isRead() {
+               return read;
+       }
+
+       /**
+        * Modify the read.
+        *
+        * @param aRead the read to set
+        */
+       public void setRead(boolean aRead) {
+               read = aRead;
+       }
+
+       /**
+        * Retrieve the write.
+        *
+        * @return the write
+        */
+       public boolean isWrite() {
+               return write;
+       }
+
+       /**
+        * Modify the write.
+        *
+        * @param aWrite the write to set
+        */
+       public void setWrite(boolean aWrite) {
+               write = aWrite;
+       }
+
+       /**
+        * Retrieve the modifyACL.
+        *
+        * @return the modifyACL
+        */
+       public boolean isModifyACL() {
+               return modifyACL;
+       }
+
+       /**
+        * Modify the modifyACL.
+        *
+        * @param aModifyACL the modifyACL to set
+        */
+       public void setModifyACL(boolean aModifyACL) {
+               modifyACL = aModifyACL;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/QuotaHolder.java b/src/org/gss_project/gss/web/client/rest/resource/QuotaHolder.java
new file mode 100644 (file)
index 0000000..be4a91b
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.io.Serializable;
+
+import com.google.gwt.i18n.client.NumberFormat;
+
+
+/**
+ * @author kman
+ *
+ */
+public class QuotaHolder implements Serializable{
+       private Long fileCount = 0L;
+       private Long fileSize = 0L;
+       private Long quotaLeftSize = 0L;
+
+       /**
+        * Retrieve the fileCount.
+        *
+        * @return the fileCount
+        */
+       public Long getFileCount() {
+               return fileCount;
+       }
+
+       /**
+        * Modify the fileCount.
+        *
+        * @param aFileCount the fileCount to set
+        */
+       public void setFileCount(Long aFileCount) {
+               fileCount = aFileCount;
+       }
+
+       /**
+        * Retrieve the fileSize.
+        *
+        * @return the fileSize
+        */
+       public Long getFileSize() {
+               return fileSize;
+       }
+
+       /**
+        * Modify the fileSize.
+        *
+        * @param aFileSize the fileSize to set
+        */
+       public void setFileSize(Long aFileSize) {
+               fileSize = aFileSize;
+       }
+
+       /**
+        * Retrieve the quotaLeftSize.
+        *
+        * @return the quotaLeftSize
+        */
+       public Long getQuotaLeftSize() {
+               return quotaLeftSize;
+       }
+
+       /**
+        * Modify the quotaLeftSize.
+        *
+        * @param aQuotaLeftSize the quotaLeftSize to set
+        */
+       public void setQuotaLeftSize(Long aQuotaLeftSize) {
+               quotaLeftSize = aQuotaLeftSize;
+       }
+
+       public String getFileSizeAsString() {
+               if (fileSize < 1024)
+                       return String.valueOf(fileSize) + " B";
+               else if (fileSize < 1024*1024)
+                       return getSize(fileSize, 1024D) + " KB";
+               else if (fileSize < 1024*1024*1024)
+                       return getSize(fileSize,(1024D*1024D)) + " MB";
+               return getSize(fileSize , (1024D*1024D*1024D)) + " GB";
+       }
+
+       public String getQuotaLeftAsString() {
+               if (quotaLeftSize < 1024)
+                       return String.valueOf(quotaLeftSize) + " B";
+               else if (quotaLeftSize < 1024*1024)
+                       return getSize(quotaLeftSize, 1024D) + " KB";
+               else if (quotaLeftSize < 1024*1024*1024)
+                       return getSize(quotaLeftSize,(1024D*1024D)) + " MB";
+               return getSize(quotaLeftSize , (1024D*1024D*1024D)) + " GB";
+       }
+
+       private String getSize(Long size, Double division){
+               Double res = Double.valueOf(size.toString())/division;
+               NumberFormat nf = NumberFormat.getFormat("######.#");
+               return nf.format(res);
+       }
+
+       public long percentOfFreeSpace(){
+               return (long) ((double)quotaLeftSize*100/(fileSize+quotaLeftSize)+0.5);
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/RestResource.java b/src/org/gss_project/gss/web/client/rest/resource/RestResource.java
new file mode 100644 (file)
index 0000000..5618968
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.io.Serializable;
+
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.user.client.ui.TreeItem;
+
+
+/**
+ * @author kman
+ *
+ */
+public abstract class RestResource implements Serializable{
+       String uri;
+
+       public RestResource(String aUri) {
+               super();
+               setUri(aUri);
+       }
+
+       /**
+        * Retrieve the uri.
+        *
+        * @return the uri
+        */
+       public String getUri() {
+               return uri;
+       }
+
+       /**
+        * Modify the uri.
+        *
+        * @param aUri the path to set
+        */
+       public void setUri(String aUri) {
+               uri = aUri;
+               if (uri!=null) {
+                       // Remove any parameter part
+                       int qm = uri.indexOf('?');
+                       if (qm>=0) uri = uri.substring(0, qm);
+               }
+       }
+
+       public abstract void createFromJSON(String text);
+
+       protected String unmarshallString(JSONObject obj, String key){
+               if(obj.get(key) != null)
+                       if(obj.get(key).isString() != null)
+                               return obj.get(key).isString().stringValue();
+               return null;
+       }
+       
+       protected int unmarshallInt(JSONObject obj, String key){
+               if(obj.get(key) != null)
+                       if(obj.get(key).isNumber() != null)
+                               return (int) obj.get(key).isNumber().getValue();
+               return -1;
+       }
+
+       protected boolean unmarshallBoolean(JSONObject obj, String key){
+               if(obj.get(key) != null)
+                       if(obj.get(key).isBoolean() != null)
+                               return obj.get(key).isBoolean().booleanValue();
+               return false;
+       }
+
+       public static native String getDate(Long ms)/*-{
+               return (new Date(ms)).toUTCString();
+       }-*/;
+
+       public abstract String getLastModifiedSince();
+
+       public String constructUri(@SuppressWarnings("unused") TreeItem treeItem, @SuppressWarnings("unused") String path){
+               return "";
+       }
+
+       public String getName(){
+               String[] names = uri.split("/");
+               return names[names.length -1];
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/RestResourceWrapper.java b/src/org/gss_project/gss/web/client/rest/resource/RestResourceWrapper.java
new file mode 100644 (file)
index 0000000..b285d52
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+
+/**
+ * @author kman
+ *
+ */
+public class RestResourceWrapper extends RestResource{
+       FolderResource resource;
+       
+       public RestResourceWrapper(FolderResource resource) {
+               super(resource.getUri());
+               this.resource=resource;
+       }
+       
+       
+       /**
+        * Modify the resource.
+        *
+        * @param resource the resource to set
+        */
+       public void setResource(FolderResource resource) {
+               this.resource = resource;
+       }
+       /**
+        * Retrieve the resource.
+        *
+        * @return the resource
+        */
+       public FolderResource getResource() {
+               return resource;
+       }
+       
+       @Override
+       public void createFromJSON(String text) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/SearchResource.java b/src/org/gss_project/gss/web/client/rest/resource/SearchResource.java
new file mode 100644 (file)
index 0000000..c65e1a8
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+
+/**
+ * @author kman
+ */
+public class SearchResource extends RestResource {
+       int size;
+       public SearchResource(String aUri) {
+               super(aUri);
+       }
+
+       List<FileResource> files = new ArrayList<FileResource>();
+       List<String> filePaths = new LinkedList<String>();
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<String> getFilePaths() {
+               return filePaths;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFilePaths the files to set
+        */
+       public void setFilePaths(List<String> newFilePaths) {
+               filePaths = newFilePaths;
+       }
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<FileResource> getFiles() {
+               return files;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFiles the files to set
+        */
+       public void setFiles(List<FileResource> newFiles) {
+               files = newFiles;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONArray subs = JSONParser.parse(text).isArray();
+               if (subs != null)
+                       for (int i = 0; i < subs.size(); i++) {
+                               JSONObject fo = subs.get(i).isObject();
+                               if (fo != null) {
+                                       if(i==0&&unmarshallInt(fo, "length")!=-1){
+                                               setSize(unmarshallInt(fo, "length"));
+                                       }
+                                       else{
+                                       String fname = unmarshallString(fo, "name");
+                                       String fowner = unmarshallString(fo, "owner");
+                                       String fcontent = unmarshallString(fo, "content");
+                                       String fpath = unmarshallString(fo, "path");
+                                       Boolean fshared = unmarshallBoolean(fo,"shared");
+                                       boolean fversioned = unmarshallBoolean(fo,"versioned");
+                                       fpath = URL.decodeComponent(fpath);
+                                       Integer fversion = null;
+                                       if (fo.get("version") != null)
+                                               fversion = new Integer(fo.get("version").toString());
+                                       boolean fdeleted = unmarshallBoolean(fo, "deleted");
+                                       Date fcreationDate = null;
+                                       if (fo.get("creationDate") != null)
+                                               fcreationDate = new Date(new Long(fo.get("creationDate").toString()));
+                                       Date fmodificationDate = null;
+                                       if (fo.get("modificationDate") != null)
+                                               fmodificationDate = new Date(new Long(fo.get("modificationDate").toString()));
+                                       String furi = unmarshallString(fo,"uri");
+                                       Long fsize = 0L;
+                                       if(fo.get("size") != null)
+                                               fsize = new Long(fo.get("size").toString());
+                                       filePaths.add(furi);
+                                       FileResource fs = new FileResource(furi);
+                                       fs.setName(fname);
+                                       fs.setOwner(fowner);
+                                       fs.setVersion(fversion);
+                                       fs.setContentLength(fsize);
+                                       fs.setDeleted(fdeleted);
+                                       fs.setCreationDate(fcreationDate);
+                                       fs.setModificationDate(fmodificationDate);
+                                       fs.setContentType(fcontent);
+                                       fs.setPath(fpath);
+                                       fs.setShared(fshared);
+                                       fs.setVersioned(fversioned);
+                                       files.add(fs);
+                                       }
+                               }
+                       }
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+       
+       
+       /**
+        * Retrieve the size.
+        *
+        * @return the size
+        */
+       public int getSize() {
+               return size;
+       }
+       
+       
+       /**
+        * Modify the size.
+        *
+        * @param size the size to set
+        */
+       public void setSize(int size) {
+               this.size = size;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/SharedFolderResource.java b/src/org/gss_project/gss/web/client/rest/resource/SharedFolderResource.java
new file mode 100644 (file)
index 0000000..be84e75
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+
+/**
+ * @author kman
+ *
+ */
+public class SharedFolderResource extends RestResourceWrapper{
+       
+       /**
+        * @param aUri
+        */
+       public SharedFolderResource(FolderResource resource) {
+               super(resource);
+       }
+       
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/SharedResource.java b/src/org/gss_project/gss/web/client/rest/resource/SharedResource.java
new file mode 100644 (file)
index 0000000..08232c6
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import org.gss_project.gss.web.client.rest.MultipleGetCommand;
+import org.gss_project.gss.web.client.rest.MultipleGetCommand.Cached;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.user.client.ui.TreeItem;
+
+
+/**
+ * @author kman
+ *
+ */
+public class SharedResource extends RestResource{
+
+       public SharedResource(String aUri) {
+               super(aUri);
+       }
+
+       List<String> filePaths = new LinkedList<String>();
+       List<String> subfolderPaths = new LinkedList<String>();
+       List<FolderResource> folders = new ArrayList<FolderResource>();
+
+       List<FileResource> files = new ArrayList<FileResource>();
+
+       private boolean filesExpanded=false;
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<String> getFilePaths() {
+               return filePaths;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFilePaths the files to set
+        */
+       public void setFilePaths(List<String> newFilePaths) {
+               filePaths = newFilePaths;
+       }
+
+       /**
+        * Retrieve the subfolders.
+        *
+        * @return the subfolders
+        */
+       public List<String> getSubfolderPaths() {
+               return subfolderPaths;
+       }
+
+       /**
+        * Modify the subfolder paths.
+        *
+        * @param newSubfolderPaths the subfolder paths to set
+        */
+       public void setSubfolderPaths(List<String> newSubfolderPaths) {
+               subfolderPaths = newSubfolderPaths;
+       }
+
+       /**
+        * Retrieve the folders.
+        *
+        * @return the folders
+        */
+       public List<FolderResource> getFolders() {
+               return folders;
+       }
+
+       /**
+        * Modify the folders.
+        *
+        * @param newFolders the folders to set
+        */
+       public void setFolders(List<FolderResource> newFolders) {
+               folders = newFolders;
+       }
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<FileResource> getFiles() {
+               return files;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFiles the files to set
+        */
+       public void setFiles(List<FileResource> newFiles) {
+               files = newFiles;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject json = (JSONObject) JSONParser.parse(text);
+               if (json.get("folders") != null) {
+                       JSONArray subs = json.get("folders").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject so = subs.get(i).isObject();
+                                       if (so != null) {
+                                               String subUri = unmarshallString(so, "uri");
+                                               String subName = unmarshallString(so, "name");
+                                               if (subUri != null && subName != null) {
+                                                       if (!subUri.endsWith("/"))
+                                                               subUri = subUri + "/";
+                                                       FolderResource sub = new FolderResource(subUri);
+                                                       sub.setName(subName);
+                                                       sub.setNeedsExpanding(true);
+                                                       folders.add(sub);
+                                                       subfolderPaths.add(subUri);
+                                               }
+                                       }
+                               }
+               }
+               if (json.get("files") != null) {
+                       JSONArray subs = json.get("files").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject fo = subs.get(i).isObject();
+                                       if (fo != null) {
+                                               String fname = unmarshallString(fo, "name");
+                                               String fowner = unmarshallString(fo, "owner");
+                                               String fcontent = unmarshallString(fo, "content");
+                                               boolean fversioned = unmarshallBoolean(fo, "versioned");
+                                               Integer fversion = null;
+                                               if (fo.get("version") != null)
+                                                       fversion = new Integer(fo.get("version").toString());
+                                               boolean fdeleted = unmarshallBoolean(fo, "deleted");
+                                               Date fcreationDate = null;
+                                               if (fo.get("creationDate") != null)
+                                                       fcreationDate = new Date(new Long(fo.get("creationDate").toString()));
+                                               Date fmodificationDate = null;
+                                               if (fo.get("modificationDate") != null)
+                                                       fmodificationDate = new Date(new Long(fo.get("modificationDate").toString()));
+                                               String furi = unmarshallString(fo,"uri");
+                                               Long fsize = 0L;
+                                               if(fo.get("size") != null)
+                                                       fsize = new Long(fo.get("size").toString());
+                                               filePaths.add(furi);
+                                               String fpath = unmarshallString(fo, "path");
+                                               fpath = URL.decodeComponent(fpath);
+                                               FileResource fs = new FileResource(furi);
+                                               fs.setPath(fpath);
+                                               fs.setName(fname);
+                                               fs.setOwner(fowner);
+                                               fs.setVersion(fversion);
+                                               fs.setVersioned(unmarshallBoolean(fo, "versioned"));
+                                               fs.setContentLength(fsize);
+                                               fs.setDeleted(fdeleted);
+                                               fs.setShared(unmarshallBoolean(fo,"shared"));
+                                               fs.setVersioned(fversioned);
+                                               fs.setCreationDate(fcreationDate);
+                                               fs.setModificationDate(fmodificationDate);
+                                               fs.setContentType(fcontent);
+                                               files.add(fs);
+                                       }
+                               }
+               }
+       }
+
+       public List<String> getRootSharedFiles(){
+               List<String> res = new ArrayList<String>();
+               for(String f : getFilePaths()){
+                       boolean contained = false;
+                       for(String fo : getSubfolderPaths())
+                               if(f.startsWith(fo))
+                                       contained = true;
+                       if(!contained)
+                               res.add(f);
+               }
+               return res;
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+
+       public MultipleGetCommand.Cached[] getFileCache(){
+               if(getFilePaths().size() != getFiles().size()){
+                       GWT.log("MISMATCH IN PATH AND FILES SIZE", null);
+                       return null;
+               }
+               if(!filesExpanded)
+                       return null;
+               MultipleGetCommand.Cached[] result = new MultipleGetCommand.Cached[getFilePaths().size()];
+               for(int i=0; i<getFiles().size();i++){
+                       FileResource r = getFiles().get(i);
+                       Cached c = new Cached();
+                       c.cache=r;
+                       c.uri=r.uri;
+                       result[i] = c;
+               }
+               return result;
+       }
+
+       public void setFilesExpanded(boolean newFilesExpanded) {
+               filesExpanded = newFilesExpanded;
+       }
+
+       @Override
+       public String constructUri(TreeItem treeItem, String path){
+               String constructedUri = "Files/"+ getUri().substring(path.lastIndexOf("/")+1);
+               return constructedUri;
+       }
+
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/TagsResource.java b/src/org/gss_project/gss/web/client/rest/resource/TagsResource.java
new file mode 100644 (file)
index 0000000..b82cec8
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONParser;
+
+
+/**
+ * @author kman
+ *
+ */
+public class TagsResource extends RestResource{
+
+       public TagsResource(String aUri) {
+               super(aUri);
+       }
+
+       List<String> tags = new ArrayList<String>();
+
+       /**
+        * Retrieve the tags.
+        *
+        * @return the tags
+        */
+       public List<String> getTags() {
+               return tags;
+       }
+
+       /**
+        * Modify the tags.
+        *
+        * @param newTags the tags to set
+        */
+       public void setTags(List<String> newTags) {
+               tags = newTags;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONArray array = (JSONArray) JSONParser.parse(text);
+               if(array != null)
+                       for (int i = 0; i < array.size(); i++)
+                               getTags().add(array.get(i).isString().stringValue());
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/TrashFolderResource.java b/src/org/gss_project/gss/web/client/rest/resource/TrashFolderResource.java
new file mode 100644 (file)
index 0000000..b99ec7b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+
+/**
+ * @author kman
+ *
+ */
+public class TrashFolderResource extends RestResourceWrapper{
+       
+       /**
+        * @param aUri
+        */
+       public TrashFolderResource(FolderResource resource) {
+               super(resource);
+               
+       }
+       
+       
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/TrashResource.java b/src/org/gss_project/gss/web/client/rest/resource/TrashResource.java
new file mode 100644 (file)
index 0000000..567a4d4
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2009, 2010 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.gwt.http.client.URL;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+import com.google.gwt.user.client.ui.TreeItem;
+
+
+/**
+ * @author kman
+ *
+ */
+public class TrashResource extends RestResource{
+
+       public TrashResource(String aUri) {
+               super(aUri);
+       }
+
+       List<String> filePaths = new LinkedList<String>();
+       List<String> subfolderPaths = new LinkedList<String>();
+       List<FolderResource> folders = new ArrayList<FolderResource>();
+       List<FileResource> files = new ArrayList<FileResource>();
+
+       /**
+        * Retrieve the file paths.
+        *
+        * @return the file paths
+        */
+       public List<String> getFilePaths() {
+               return filePaths;
+       }
+
+       /**
+        * Modify the file paths.
+        *
+        * @param newFilePaths the file paths to set
+        */
+       public void setFilePaths(List<String> newFilePaths) {
+               filePaths = newFilePaths;
+       }
+
+       /**
+        * Retrieve the subfolder paths.
+        *
+        * @return the subfolder paths
+        */
+       public List<String> getSubfolderPaths() {
+               return subfolderPaths;
+       }
+
+       /**
+        * Modify the subfolder paths.
+        *
+        * @param newSubfolderPaths the subfolders to set
+        */
+       public void setSubfolderPaths(List<String> newSubfolderPaths) {
+               subfolderPaths = newSubfolderPaths;
+       }
+
+       /**
+        * Retrieve the folders.
+        *
+        * @return the folders
+        */
+       public List<FolderResource> getFolders() {
+               return folders;
+       }
+
+       /**
+        * Modify the folders.
+        *
+        * @param newFolders the folders to set
+        */
+       public void setFolders(List<FolderResource> newFolders) {
+               folders = newFolders;
+       }
+
+       /**
+        * Retrieve the files.
+        *
+        * @return the files
+        */
+       public List<FileResource> getFiles() {
+               return files;
+       }
+
+       /**
+        * Modify the files.
+        *
+        * @param newFiles the files to set
+        */
+       public void setFiles(List<FileResource> newFiles) {
+               files = newFiles;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject json = (JSONObject) JSONParser.parse(text);
+               if (json.get("folders") != null) {
+                       JSONArray subs = json.get("folders").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject so = subs.get(i).isObject();
+                                       if (so != null) {
+                                               String subUri = unmarshallString(so, "uri");
+                                               String subName = unmarshallString(so, "name");
+                                               subName = URL.decodeComponent(subName);
+                                               if (subUri != null && subName != null) {
+                                                       if (!subUri.endsWith("/"))
+                                                               subUri = subUri + "/";
+                                                       FolderResource sub = new FolderResource(subUri);
+                                                       sub.setName(subName);
+                                                       sub.setNeedsExpanding(true);
+                                                       folders.add(sub);
+                                                       subfolderPaths.add(subUri);
+                                               }
+                                       }
+                               }
+               }
+               if (json.get("files") != null) {
+                       JSONArray subs = json.get("files").isArray();
+                       if (subs != null)
+                               for (int i = 0; i < subs.size(); i++) {
+                                       JSONObject fo = subs.get(i).isObject();
+                                       if (fo != null) {
+                                               String fname = unmarshallString(fo, "name");
+                                               String fowner = unmarshallString(fo, "owner");
+                                               String fcontent = unmarshallString(fo, "content");
+                                               Boolean fshared = unmarshallBoolean(fo, "shared");                                              
+                                               Boolean fversioned = unmarshallBoolean(fo, "versioned");        
+                                               String fpath = unmarshallString(fo, "path");                                            
+                                               fpath = URL.decodeComponent(fpath);
+                                               Integer fversion = null;
+                                               if (fo.get("version") != null)
+                                                       fversion = new Integer(fo.get("version").toString());
+                                               boolean fdeleted = unmarshallBoolean(fo, "deleted");
+                                               Date fcreationDate = null;
+                                               if (fo.get("creationDate") != null)
+                                                       fcreationDate = new Date(new Long(fo.get("creationDate").toString()));
+                                               Date fmodificationDate = null;
+                                               if (fo.get("modificationDate") != null)
+                                                       fmodificationDate = new Date(new Long(fo.get("modificationDate").toString()));
+                                               String furi = unmarshallString(fo,"uri");
+                                               Long fsize = 0L;
+                                               if(fo.get("size") != null)
+                                                       fsize = new Long(fo.get("size").toString());
+                                               filePaths.add(furi);
+                                               FileResource fs = new FileResource(furi);
+                                               fs.setName(fname);
+                                               fs.setOwner(fowner);
+                                               fs.setVersion(fversion);
+                                               fs.setContentLength(fsize);
+                                               fs.setDeleted(fdeleted);
+                                               fs.setPath(fpath);
+                                               fs.setCreationDate(fcreationDate);
+                                               fs.setModificationDate(fmodificationDate);
+                                               fs.setContentType(fcontent);
+                                               fs.setShared(fshared);
+                                               fs.setVersioned(fversioned);
+                                               files.add(fs);
+                                       }
+                               }
+               }
+       }
+
+       public List<FolderResource> getTrashedFolders(){
+               List<FolderResource> res = new ArrayList<FolderResource>();
+               for(String s : subfolderPaths){
+                       String[] pathElements =  s.split("/");
+                       FolderResource tr = new FolderResource(s);
+                       tr.setName(URL.decodeComponent(pathElements[pathElements.length-1]));
+                       res.add(tr);
+               }
+               return res;
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+       @Override
+       public String constructUri(TreeItem treeItem, String path){
+               String constructedUri = "Files/"+ getUri().substring(path.lastIndexOf("/")+1);
+               if (!constructedUri.endsWith("/"))
+                       constructedUri += "/";
+               return constructedUri;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/UploadStatusResource.java b/src/org/gss_project/gss/web/client/rest/resource/UploadStatusResource.java
new file mode 100644 (file)
index 0000000..ac53506
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+
+
+/**
+ * @author kman
+ *
+ */
+public class UploadStatusResource extends RestResource{
+       long bytesTransferred;
+       long fileSize;
+
+       public UploadStatusResource(String aUri) {
+               super(aUri);
+       }
+
+       /**
+        * Retrieve the bytesTransferred.
+        *
+        * @return the bytesTransferred
+        */
+       public long getBytesTransferred() {
+               return bytesTransferred;
+       }
+
+       /**
+        * Modify the bytesTransferred.
+        *
+        * @param newBytesTransferred the bytesTransferred to set
+        */
+       public void setBytesTransferred(long newBytesTransferred) {
+               bytesTransferred = newBytesTransferred;
+       }
+
+       /**
+        * Retrieve the fileSize.
+        *
+        * @return the fileSize
+        */
+       public long getFileSize() {
+               return fileSize;
+       }
+
+       /**
+        * Modify the fileSize.
+        *
+        * @param newFileSize the fileSize to set
+        */
+       public void setFileSize(long newFileSize) {
+               fileSize = newFileSize;
+       }
+
+       public int percent(){
+               return new Long(bytesTransferred * 100 / fileSize).intValue();
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject json = (JSONObject) JSONParser.parse(text);
+               if(json.get("bytesTotal") != null)
+                       fileSize = new Long(json.get("bytesTotal").toString());
+               if(json.get("bytesUploaded") != null)
+                       bytesTransferred = new Long(json.get("bytesUploaded").toString());
+
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/UserResource.java b/src/org/gss_project/gss/web/client/rest/resource/UserResource.java
new file mode 100644 (file)
index 0000000..e56f139
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.Date;
+
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+
+/**
+ * @author kman
+ */
+public class UserResource extends RestResource {
+
+       public UserResource(String aUri) {
+               super(aUri);
+       }
+
+       private String name;
+
+       private String username;
+
+       private String email;
+
+       private Date creationDate;
+
+       private Date modificationDate;
+
+       private String filesPath;
+
+       private String trashPath;
+
+       private String sharedPath;
+
+       private String othersPath;
+
+       private String tagsPath;
+
+       private String groupsPath;
+
+       private QuotaHolder quota;
+
+       private String announcement;
+
+       private Date lastLogin;
+       
+       private Date currentLogin;
+
+       /**
+        * Retrieve the name.
+        *
+        * @return the name
+        */
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       /**
+        * Modify the name.
+        *
+        * @param aName the name to set
+        */
+       public void setName(String aName) {
+               name = aName;
+       }
+
+       /**
+        * Retrieve the username.
+        *
+        * @return the username
+        */
+       public String getUsername() {
+               return username;
+       }
+
+       /**
+        * Modify the username.
+        *
+        * @param aUsername the username to set
+        */
+       public void setUsername(String aUsername) {
+               username = aUsername;
+       }
+
+       /**
+        * Retrieve the email.
+        *
+        * @return the email
+        */
+       public String getEmail() {
+               return email;
+       }
+
+       /**
+        * Modify the email.
+        *
+        * @param anEmail the email to set
+        */
+       public void setEmail(String anEmail) {
+               email = anEmail;
+       }
+
+       /**
+        * Retrieve the creationDate.
+        *
+        * @return the creationDate
+        */
+       public Date getCreationDate() {
+               return creationDate;
+       }
+
+       /**
+        * Modify the creationDate.
+        *
+        * @param aCreationDate the creationDate to set
+        */
+       public void setCreationDate(Date aCreationDate) {
+               creationDate = aCreationDate;
+       }
+
+       /**
+        * Retrieve the modificationDate.
+        *
+        * @return the modificationDate
+        */
+       public Date getModificationDate() {
+               return modificationDate;
+       }
+
+       /**
+        * Modify the modificationDate.
+        *
+        * @param aModificationDate the modificationDate to set
+        */
+       public void setModificationDate(Date aModificationDate) {
+               modificationDate = aModificationDate;
+       }
+
+       /**
+        * Retrieve the filesPath.
+        *
+        * @return the filesPath
+        */
+       public String getFilesPath() {
+               return filesPath;
+       }
+
+       /**
+        * Modify the filesPath.
+        *
+        * @param aFilesPath the filesPath to set
+        */
+       public void setFilesPath(String aFilesPath) {
+               filesPath = aFilesPath;
+       }
+
+       /**
+        * Retrieve the trashPath.
+        *
+        * @return the trashPath
+        */
+       public String getTrashPath() {
+               return trashPath;
+       }
+
+       /**
+        * Modify the trashPath.
+        *
+        * @param aTrashPath the trashPath to set
+        */
+       public void setTrashPath(String aTrashPath) {
+               trashPath = aTrashPath;
+       }
+
+       /**
+        * Retrieve the sharedPath.
+        *
+        * @return the sharedPath
+        */
+       public String getSharedPath() {
+               return sharedPath;
+       }
+
+       /**
+        * Modify the sharedPath.
+        *
+        * @param aSharedPath the sharedPath to set
+        */
+       public void setSharedPath(String aSharedPath) {
+               sharedPath = aSharedPath;
+       }
+
+       /**
+        * Retrieve the othersPath.
+        *
+        * @return the othersPath
+        */
+       public String getOthersPath() {
+               return othersPath;
+       }
+
+       /**
+        * Modify the othersPath.
+        *
+        * @param anOthersPath the othersPath to set
+        */
+       public void setOthersPath(String anOthersPath) {
+               othersPath = anOthersPath;
+       }
+
+       /**
+        * Retrieve the tagsPath.
+        *
+        * @return the tagsPath
+        */
+       public String getTagsPath() {
+               return tagsPath;
+       }
+
+       /**
+        * Modify the tagsPath.
+        *
+        * @param aTagsPath the tagsPath to set
+        */
+       public void setTagsPath(String aTagsPath) {
+               tagsPath = aTagsPath;
+       }
+
+       /**
+        * Retrieve the groupsPath.
+        *
+        * @return the groupsPath
+        */
+       public String getGroupsPath() {
+               return groupsPath;
+       }
+
+       /**
+        * Modify the groupsPath.
+        *
+        * @param aGroupsPath the groupsPath to set
+        */
+       public void setGroupsPath(String aGroupsPath) {
+               groupsPath = aGroupsPath;
+       }
+
+       /**
+        * Retrieve the quota.
+        *
+        * @return the quota
+        */
+       public QuotaHolder getQuota() {
+               return quota;
+       }
+
+       /**
+        * Modify the quota.
+        *
+        * @param aQuota the quota to set
+        */
+       public void setQuota(QuotaHolder aQuota) {
+               quota = aQuota;
+       }
+
+
+       /**
+        * Retrieve the announcement.
+        *
+        * @return the announcement
+        */
+       public String getAnnouncement() {
+               return announcement;
+       }
+
+       /**
+        * Modify the announcement.
+        *
+        * @param anAnnouncement the announcement to set
+        */
+       public void setAnnouncement(String anAnnouncement) {
+               announcement = anAnnouncement;
+       }
+
+       /**
+        * Retrieve the lastLogin.
+        *
+        * @return the lastLogin
+        */
+       public Date getLastLogin() {
+               return lastLogin;
+       }
+
+       /**
+        * Retrieve the currentLogin.
+        *
+        * @return the currentLogin
+        */
+       public Date getCurrentLogin() {
+               return currentLogin;
+       }
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONObject json = (JSONObject) JSONParser.parse(text);
+               email = unmarshallString(json, "email");
+               name = unmarshallString(json, "name");
+               username = unmarshallString(json, "username");
+               filesPath = unmarshallString(json, "fileroot");
+               groupsPath = unmarshallString(json, "groups");
+               othersPath = unmarshallString(json, "others");
+               sharedPath = unmarshallString(json, "shared");
+               tagsPath = unmarshallString(json, "tags");
+               trashPath = unmarshallString(json, "trash");
+               announcement = unmarshallString(json, "announcement");
+               if (json.get("lastLogin") != null)
+                       lastLogin = new Date(new Long(json.get("lastLogin").toString()));
+               if (json.get("currentLogin") != null)
+                       currentLogin = new Date(new Long(json.get("currentLogin").toString()));                 
+               if (json.get("creationDate") != null)
+                       creationDate = new Date(new Long(json.get("creationDate").toString()));
+               if (json.get("modificationDate") != null)
+                       modificationDate = new Date(new Long(json.get("modificationDate").toString()));
+               if (json.get("quota") != null) {
+                       JSONObject qj = (JSONObject) json.get("quota");
+                       if (qj != null) {
+                               quota = new QuotaHolder();
+                               if(qj.get("totalFiles") != null)
+                                       quota.setFileCount(new Long(qj.get("totalFiles").toString()));
+                               if(qj.get("totalBytes") != null)
+                                       quota.setFileSize(new Long(qj.get("totalBytes").toString()));
+                               if(qj.get("bytesRemaining") != null)
+                                       quota.setQuotaLeftSize(new Long(qj.get("bytesRemaining").toString()));
+                       }
+               }
+       }
+
+       @Override
+       public String toString() {
+               String res = email + "\n" + name + "\n" + username + "\n" + filesPath + "\n" + groupsPath;
+               return res;
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/rest/resource/UserSearchResource.java b/src/org/gss_project/gss/web/client/rest/resource/UserSearchResource.java
new file mode 100644 (file)
index 0000000..0e074bd
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2009 Electronic Business Systems Ltd.
+ *
+ * This file is part of GSS.
+ *
+ * GSS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.gss_project.gss.web.client.rest.resource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+
+/**
+ * A container for the results of a search query for users.
+ *
+ * @author past
+ */
+public class UserSearchResource extends RestResource {
+
+       public UserSearchResource(String aUri) {
+               super(aUri);
+       }
+
+       List<UserResource> users = new ArrayList<UserResource>();
+
+       @Override
+       public void createFromJSON(String text) {
+               JSONArray json = JSONParser.parse(text).isArray();
+               if (json != null)
+                       for (int i = 0; i < json.size(); i++) {
+                               JSONObject j = json.get(i).isObject();
+                               if (j != null) {
+                                       String username = unmarshallString(j, "username");
+                                       String name = unmarshallString(j, "name");
+                                       String home = unmarshallString(j, "home");
+                                       UserResource user = new UserResource(home);
+                                       user.setName(name);
+                                       user.setUsername(username);
+                                       users.add(user);
+                               }
+                       }
+       }
+
+       /**
+        * Retrieve the users.
+        *
+        * @return the users
+        */
+       public List<UserResource> getUsers() {
+               return users;
+       }
+
+       /**
+        * Modify the users.
+        *
+        * @param newUsers the users to set
+        */
+       public void setUsers(List<UserResource> newUsers) {
+               users = newUsers;
+       }
+
+       @Override
+       public String getLastModifiedSince() {
+               return null;
+       }
+}
diff --git a/src/org/gss_project/gss/web/client/upArrow.png b/src/org/gss_project/gss/web/client/upArrow.png
new file mode 100644 (file)
index 0000000..a336947
Binary files /dev/null and b/src/org/gss_project/gss/web/client/upArrow.png differ
diff --git a/src/org/gss_project/gss/web/public/GSS.html b/src/org/gss_project/gss/web/public/GSS.html
new file mode 100644 (file)
index 0000000..5da5c94
--- /dev/null
@@ -0,0 +1,17 @@
+<html>
+       <head>
+               <title>Pithos</title>
+               <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+               <script language='javascript' src='org.gss_project.gss.web.GSS.nocache.js'></script>
+               <script type="text/javascript">
+               document.oncontextmenu = function() {
+                       return false;
+               }
+               </script>
+               <script type="text/javascript" src="sha1.js"></script>
+               <script type="text/javascript" language="javascript" src="lytebox.js"></script>
+               <link rel="stylesheet" href="lytebox.css" type="text/css" media="screen" />     </head>
+       <body>
+               <iframe src="javascript:''" id="__gwt_historyFrame" style="position:absolute;width:0;height:0;border:0"></iframe>
+       </body>
+</html>
diff --git a/src/org/gss_project/gss/web/public/error403.html b/src/org/gss_project/gss/web/public/error403.html
new file mode 100644 (file)
index 0000000..9064e6e
--- /dev/null
@@ -0,0 +1,24 @@
+<html>
+       <head>
+               <title>Pithos</title>
+               <link type="text/css" rel="stylesheet" href="/pithos/main.css">
+       </head>
+       <body>
+<div class="wrapper" >
+<div class="header"></div>
+<div class="image_logo">
+<table><tr>
+  <td><a href="/"><img src="/pithos/images/service-logo.png"></img></a>
+</tr></table>
+</div> <!-- image_logo -->
+<div style="clear: both; "> </div>
+<div class="page_main">
+               <center>
+               <p class="big">HTTP status 403
+               <p>You don't have permission to view the resource in the requested URI.
+               </center>
+</div>
+<div class="footer"></div>
+</div> <!-- wrapper -->
+       </body>
+</html>
diff --git a/src/org/gss_project/gss/web/public/error502.html b/src/org/gss_project/gss/web/public/error502.html
new file mode 100644 (file)
index 0000000..e94127f
--- /dev/null
@@ -0,0 +1,24 @@
+<html>
+       <head>
+               <title>Pithos</title>
+               <link type="text/css" rel="stylesheet" href="/pithos/main.css">
+       </head>
+       <body>
+<div class="wrapper" >
+<div class="header"></div>
+<div class="image_logo">
+<table><tr>
+  <td><a href="/"><img src="/pithos/images/service-logo.png"></img></a>
+</tr></table>
+</div> <!-- image_logo -->
+<div style="clear: both; "> </div>
+<div class="page_main">
+               <center>
+               <p class="big">HTTP status 502
+               <p>The server received an invalid response from the upstream server it accessed in attempting to fulfill the request.
+               </center>
+</div>
+<div class="footer"></div>
+</div> <!-- wrapper -->
+       </body>
+</html>
diff --git a/src/org/gss_project/gss/web/public/error503.html b/src/org/gss_project/gss/web/public/error503.html
new file mode 100644 (file)
index 0000000..24a1602
--- /dev/null
@@ -0,0 +1,25 @@
+<html>
+       <head>
+               <title>Pithos</title>
+               <link type="text/css" rel="stylesheet" href="/pithos/main.css">
+       </head>
+       <body>
+<div class="wrapper" >
+<div class="header"></div>
+<div class="image_logo">
+<table><tr>
+  <td><a href="/"><img src="/pithos/images/service-logo.png"></img></a>
+</tr></table>
+</div> <!-- image_logo -->
+<div style="clear: both; "> </div>
+<div class="page_main">
+               <center>
+               <p class="big">HTTP status 503
+               <p>We're very busy at the moment and can't handle your request.
+               Please try again in a while.
+               </center>
+</div>
+<div class="footer"></div>
+</div> <!-- wrapper -->
+       </body>
+</html>
diff --git a/src/org/gss_project/gss/web/public/gss.css b/src/org/gss_project/gss/web/public/gss.css
new file mode 100644 (file)
index 0000000..cfb17a0
--- /dev/null
@@ -0,0 +1,321 @@
+body {
+       background-color: #bec8e6;
+       color: black;
+       font-family: "Lucida Grande","Lucida Sans Unicode",Arial,Verdana,sans-serif;
+       font-size: small;
+       margin: 8px;
+       margin-top: 3px;
+}
+
+a {
+       color: darkblue;
+}
+
+a:visited {
+       color: darkblue;
+}
+
+.hidden-link {
+       text-decoration: none !important;
+       color: black !important;
+}
+
+.hidden-link:visited {
+       text-decoration: none !important;
+       color: black !important;
+}
+
+.gss-TopPanel {
+       font-size: 100%;
+}
+
+.gss-TopPanelLinks {
+       font-size: 100%;
+}
+
+.gss-AboutText {
+       width: 24em;
+       /* Restore the padding we remove when overriding the gwt-DialogBox style */
+       padding: 3px;
+}
+
+.gss-Groups {
+       background-color: white;
+       font-size: 80%;
+}
+
+.toolbar {
+       border: 1px solid #AAAAAA;
+       background-color: white;
+       font-size: 80%;
+       cursor: pointer;
+}
+
+.toolbarmenu {
+       font-size: 80%;
+       cursor: pointer;
+}
+
+.statusbar-inner {
+       border: none;
+       font-size: 90%;
+       vertical-align: middle;
+       font-weight: normal;
+}
+
+.gss-List {
+       background-color: white;
+       font-size: 80%;
+       cursor: default;
+       border-collapse: collapse;
+       /* prevents selecting text in table with shift and ctrl*/
+       -moz-user-select: none;
+}
+.gss-List thead tr{
+       border: 1px lightblue solid;
+       }
+       
+       .GK31MSKBKG{
+       border-bottom:none;
+       }
+.gss-ListHeader {
+       
+       background-color: #E0EDFE;
+       font-weight: bold;
+       cursor: pointer;
+}
+
+.gss-searchLabel {
+       font-weight: bold;
+       font-style: italic;
+       font-size: 90%;
+       padding:5px;
+}
+
+.gss-ListNavBar {
+       font-size: 80%;
+}
+
+.gss-SelectedRow {
+       background-color: #E0EDFE;
+}
+.gss-fileRow{
+       cursor: pointer;
+}
+
+.gss-Toolbar {
+}
+
+.gss-ToolButton {
+       font-size: 80%;
+       width: 10em;
+}
+
+.props-labels {
+       font-size: 80%;
+       font-weight: bold;
+}
+
+.props-toplabels {
+       font-size: 80%;
+       font-weight: bold;
+       font-style: italic;
+}
+
+.props-values {
+       font-size: 80%;
+}
+
+.gss-errorMessage {
+       font-size: 90%;
+       background-color: #ff9999;
+       cursor: pointer;
+}
+
+.gss-warnMessage {
+       font-size: 90%;
+       background-color: #eeee99;
+       cursor: pointer;
+}
+
+.gss-infoMessage {
+       font-size: 90%;
+       background-color: #ccffcc;
+       cursor: pointer;
+}
+
+.gss-clearMessage {
+       font-size: 90%;
+       font-weight: bold;
+       text-decoration: none;
+       color: black;
+}
+
+.gss-clearMessage:visited {
+       font-size: 90%;
+       font-weight: bold;
+       text-decoration: none;
+       color: black;
+}
+
+.gss-search {
+       color: black;
+}
+
+.gss-search-empty {
+       color: #d3d3d3;
+}
+
+.gss-DialogBox {
+}
+
+.gss-readForAllNote {
+       width: 240px;
+       text-align: justify;
+       font-style: italic;
+       font-size: 12px;
+       padding-left: 4;
+}
+
+/* Tooltips */
+a.info {
+       position: relative; /*this is the key*/
+       z-index: 24;
+       color: black;
+       text-decoration: none
+}
+
+a.info:hover {
+       z-index: 25;
+       background-color: yellow;
+}
+
+a.info div {
+       display: none
+}
+
+a.info:hover span {
+       cursor: pointer;
+}
+
+/* The span will only display on :hover state. */
+a.info:hover div {
+       display: block;
+       position: absolute;
+       bottom: 2em;
+       right: 1em;
+       width: 10em;
+       border: 1px solid lightblue;
+       background-color: #D0E4F6;
+       color: black;
+       text-align: center
+}
+
+table.gss-permList.props-labels {
+       font-weight: bold;
+}
+
+table.gss-permList {
+       border-spacing: 3px;
+       border-collapse: collapse;
+       
+}
+
+table.gss-permList td {
+       padding: 5px 5px 5px 5px;
+       font-size:80%;
+}
+
+.progressbar-text {
+       font-weight: bold;
+}
+
+.progressbar-remaining {
+       font-size: 12px;
+       font-style: italic;
+}
+
+.progressbar-outer {
+}
+
+.progressbar-inner {
+       border: 1px solid darkgrey;
+       margin: 1px;
+}
+
+.progressbar-bar {
+       width: 5px;
+       height: 15px;
+       margin: 0px;
+}
+
+.progressbar-fullbar {
+       background: #E0EDFE;
+}
+
+.progressbar-blankbar {
+       background: white;
+}
+
+.gss-uploadNote {
+       text-align: justify;
+       font-style: italic;
+       font-size: 12px;
+       padding-top: 16;
+       padding-bottom: 16;
+       padding-right: 4;
+       padding-left: 4;
+}
+
+.gss-MainTabBar {
+       padding-top: 4px;
+}
+
+.gss-MainTabPanelBottom {
+       border-bottom: none;
+       border-left: none;
+       border-right: none;
+       overflow: hidden;
+       padding: 6px;
+}
+
+.gss-TabPanelBottom {
+       border-color: darkgrey;
+       border-width: 1px 1px 1px;
+       overflow: hidden;
+       padding: 6px;
+}
+
+.gss-splitPanel {
+       background-color: white;
+       border: 1px solid darkgrey;
+}
+
+.gss-tag {     
+       display:inline;
+}
+
+/* Use the background color for the splitter. */
+.gwt-HorizontalSplitPanel .hsplitter {
+       cursor: move;
+       border: 0px; 
+       background: #bec8e6;
+}
+
+/* Avoid extended background color in tree nodes. */
+.gwt-TreeItem-selected .gwt-HTML {
+       display: inline;        
+}
+
+/*
+ * Remove the padding inside the dialog boxes so that our background color
+ * appears uniform in warnings and errors.
+ */
+.gwt-DialogBox .dialogMiddleCenter {
+       background:none repeat scroll 0 0 white;
+       padding: 0;
+}
+
+.droppableHover {
+        background-color: #C1DEFD;
+}
diff --git a/src/org/gss_project/gss/web/public/images/background.png b/src/org/gss_project/gss/web/public/images/background.png
new file mode 100644 (file)
index 0000000..26e3e9a
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/background.png differ
diff --git a/src/org/gss_project/gss/web/public/images/blank.gif b/src/org/gss_project/gss/web/public/images/blank.gif
new file mode 100644 (file)
index 0000000..1d11fa9
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/blank.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/bottom.png b/src/org/gss_project/gss/web/public/images/bottom.png
new file mode 100644 (file)
index 0000000..986934b
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/bottom.png differ
diff --git a/src/org/gss_project/gss/web/public/images/close_blue.png b/src/org/gss_project/gss/web/public/images/close_blue.png
new file mode 100644 (file)
index 0000000..297368c
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/close_blue.png differ
diff --git a/src/org/gss_project/gss/web/public/images/close_gold.png b/src/org/gss_project/gss/web/public/images/close_gold.png
new file mode 100644 (file)
index 0000000..d1b8476
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/close_gold.png differ
diff --git a/src/org/gss_project/gss/web/public/images/close_green.png b/src/org/gss_project/gss/web/public/images/close_green.png
new file mode 100644 (file)
index 0000000..83909e2
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/close_green.png differ
diff --git a/src/org/gss_project/gss/web/public/images/close_grey.png b/src/org/gss_project/gss/web/public/images/close_grey.png
new file mode 100644 (file)
index 0000000..bc83ac5
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/close_grey.png differ
diff --git a/src/org/gss_project/gss/web/public/images/close_red.png b/src/org/gss_project/gss/web/public/images/close_red.png
new file mode 100644 (file)
index 0000000..3d835bb
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/close_red.png differ
diff --git a/src/org/gss_project/gss/web/public/images/header.png b/src/org/gss_project/gss/web/public/images/header.png
new file mode 100644 (file)
index 0000000..16b33ef
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/header.png differ
diff --git a/src/org/gss_project/gss/web/public/images/loading.gif b/src/org/gss_project/gss/web/public/images/loading.gif
new file mode 100644 (file)
index 0000000..f864d5f
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/loading.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/next_blue.gif b/src/org/gss_project/gss/web/public/images/next_blue.gif
new file mode 100644 (file)
index 0000000..4666e44
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/next_blue.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/next_gold.gif b/src/org/gss_project/gss/web/public/images/next_gold.gif
new file mode 100644 (file)
index 0000000..c5ba21f
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/next_gold.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/next_green.gif b/src/org/gss_project/gss/web/public/images/next_green.gif
new file mode 100644 (file)
index 0000000..85a1433
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/next_green.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/next_grey.gif b/src/org/gss_project/gss/web/public/images/next_grey.gif
new file mode 100644 (file)
index 0000000..f1773cd
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/next_grey.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/next_red.gif b/src/org/gss_project/gss/web/public/images/next_red.gif
new file mode 100644 (file)
index 0000000..4ddff3d
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/next_red.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/page_shadow.png b/src/org/gss_project/gss/web/public/images/page_shadow.png
new file mode 100644 (file)
index 0000000..35c7470
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/page_shadow.png differ
diff --git a/src/org/gss_project/gss/web/public/images/pause_blue.png b/src/org/gss_project/gss/web/public/images/pause_blue.png
new file mode 100644 (file)
index 0000000..3d4e34f
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/pause_blue.png differ
diff --git a/src/org/gss_project/gss/web/public/images/pause_gold.png b/src/org/gss_project/gss/web/public/images/pause_gold.png
new file mode 100644 (file)
index 0000000..ee52969
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/pause_gold.png differ
diff --git a/src/org/gss_project/gss/web/public/images/pause_green.png b/src/org/gss_project/gss/web/public/images/pause_green.png
new file mode 100644 (file)
index 0000000..c52f28c
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/pause_green.png differ
diff --git a/src/org/gss_project/gss/web/public/images/pause_grey.png b/src/org/gss_project/gss/web/public/images/pause_grey.png
new file mode 100644 (file)
index 0000000..1c2e9e0
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/pause_grey.png differ
diff --git a/src/org/gss_project/gss/web/public/images/pause_red.png b/src/org/gss_project/gss/web/public/images/pause_red.png
new file mode 100644 (file)
index 0000000..5ee4dcf
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/pause_red.png differ
diff --git a/src/org/gss_project/gss/web/public/images/play_blue.png b/src/org/gss_project/gss/web/public/images/play_blue.png
new file mode 100644 (file)
index 0000000..c8cd259
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/play_blue.png differ
diff --git a/src/org/gss_project/gss/web/public/images/play_gold.png b/src/org/gss_project/gss/web/public/images/play_gold.png
new file mode 100644 (file)
index 0000000..766d651
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/play_gold.png differ
diff --git a/src/org/gss_project/gss/web/public/images/play_green.png b/src/org/gss_project/gss/web/public/images/play_green.png
new file mode 100644 (file)
index 0000000..6e832a4
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/play_green.png differ
diff --git a/src/org/gss_project/gss/web/public/images/play_grey.png b/src/org/gss_project/gss/web/public/images/play_grey.png
new file mode 100644 (file)
index 0000000..8e18760
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/play_grey.png differ
diff --git a/src/org/gss_project/gss/web/public/images/play_red.png b/src/org/gss_project/gss/web/public/images/play_red.png
new file mode 100644 (file)
index 0000000..887d644
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/play_red.png differ
diff --git a/src/org/gss_project/gss/web/public/images/prev_blue.gif b/src/org/gss_project/gss/web/public/images/prev_blue.gif
new file mode 100644 (file)
index 0000000..beba13e
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/prev_blue.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/prev_gold.gif b/src/org/gss_project/gss/web/public/images/prev_gold.gif
new file mode 100644 (file)
index 0000000..b481932
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/prev_gold.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/prev_green.gif b/src/org/gss_project/gss/web/public/images/prev_green.gif
new file mode 100644 (file)
index 0000000..2d4e14e
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/prev_green.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/prev_grey.gif b/src/org/gss_project/gss/web/public/images/prev_grey.gif
new file mode 100644 (file)
index 0000000..a7f2260
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/prev_grey.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/prev_red.gif b/src/org/gss_project/gss/web/public/images/prev_red.gif
new file mode 100644 (file)
index 0000000..f702e63
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/prev_red.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/service-logo.png b/src/org/gss_project/gss/web/public/images/service-logo.png
new file mode 100644 (file)
index 0000000..c517576
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/service-logo.png differ
diff --git a/src/org/gss_project/gss/web/public/images/tristate_checked.gif b/src/org/gss_project/gss/web/public/images/tristate_checked.gif
new file mode 100644 (file)
index 0000000..d67a5b6
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/tristate_checked.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/tristate_intermediate.gif b/src/org/gss_project/gss/web/public/images/tristate_intermediate.gif
new file mode 100644 (file)
index 0000000..5926436
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/tristate_intermediate.gif differ
diff --git a/src/org/gss_project/gss/web/public/images/tristate_unchecked.gif b/src/org/gss_project/gss/web/public/images/tristate_unchecked.gif
new file mode 100644 (file)
index 0000000..8b19c76
Binary files /dev/null and b/src/org/gss_project/gss/web/public/images/tristate_unchecked.gif differ
diff --git a/src/org/gss_project/gss/web/public/logout.html b/src/org/gss_project/gss/web/public/logout.html
new file mode 100644 (file)
index 0000000..0be39b2
--- /dev/null
@@ -0,0 +1,12 @@
+<html>
+       <head>
+               <title>Pithos</title>
+               <link type="text/css" rel="stylesheet" href="gss.css">
+       </head>
+       <body>
+               <center>
+               <p>Thank you for using Pithos.
+               <p><a href='/pithos/'>Login again</a>
+               </center>
+       </body>
+</html>
diff --git a/src/org/gss_project/gss/web/public/lytebox.css b/src/org/gss_project/gss/web/public/lytebox.css
new file mode 100644 (file)
index 0000000..5303fac
--- /dev/null
@@ -0,0 +1,93 @@
+#lbOverlay { position: fixed; top: 0; left: 0; z-index: 99998; width: 100%; height: 500px; }\r
+       #lbOverlay.grey { background-color: #000000; }\r
+       #lbOverlay.red { background-color: #330000; }\r
+       #lbOverlay.green { background-color: #003300; }\r
+       #lbOverlay.blue { background-color: #011D50; }\r
+       #lbOverlay.gold { background-color: #666600; }\r
+\r
+#lbMain { position: absolute; left: 0; width: 100%; z-index: 99999; text-align: center; line-height: 0; }\r
+#lbMain a img { border: none; }\r
+\r
+#lbOuterContainer { position: relative; background-color: #fff; width: 200px; height: 200px; margin: 0 auto; }\r
+       #lbOuterContainer.grey { border: 3px solid #888888; }\r
+       #lbOuterContainer.red { border: 3px solid #DD0000; }\r
+       #lbOuterContainer.green { border: 3px solid #00B000; }\r
+       #lbOuterContainer.blue { border: 3px solid #5F89D8; }\r
+       #lbOuterContainer.gold { border: 3px solid #B0B000; }\r
+\r
+#lbDetailsContainer {  font: 10px Verdana, Helvetica, sans-serif; background-color: #fff; width: 100%; line-height: 1.4em;     overflow: auto; margin: 0 auto; }\r
+       #lbDetailsContainer.grey { border: 3px solid #888888; border-top: none; }\r
+       #lbDetailsContainer.red { border: 3px solid #DD0000; border-top: none; }\r
+       #lbDetailsContainer.green { border: 3px solid #00B000; border-top: none; }\r
+       #lbDetailsContainer.blue { border: 3px solid #5F89D8; border-top: none; }\r
+       #lbDetailsContainer.gold { border: 3px solid #B0B000; border-top: none; }\r
+\r
+#lbImageContainer, #lbIframeContainer { padding: 10px; }\r
+#lbLoading {\r
+       position: absolute; top: 45%; left: 0%; height: 32px; width: 100%; text-align: center; line-height: 0; background: url(images/loading.gif) center no-repeat;\r
+}\r
+\r
+#lbHoverNav { position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 10; }\r
+#lbImageContainer>#lbHoverNav { left: 0; }\r
+#lbHoverNav a { outline: none; }\r
+\r
+#lbPrev { width: 49%; height: 100%; background: transparent url(images/blank.gif) no-repeat; display: block; left: 0; float: left; }\r
+       #lbPrev.grey:hover, #lbPrev.grey:visited:hover { background: url(images/prev_grey.gif) left 15% no-repeat; }\r
+       #lbPrev.red:hover, #lbPrev.red:visited:hover { background: url(images/prev_red.gif) left 15% no-repeat; }\r
+       #lbPrev.green:hover, #lbPrev.green:visited:hover { background: url(images/prev_green.gif) left 15% no-repeat; }\r
+       #lbPrev.blue:hover, #lbPrev.blue:visited:hover { background: url(images/prev_blue.gif) left 15% no-repeat; }\r
+       #lbPrev.gold:hover, #lbPrev.gold:visited:hover { background: url(images/prev_gold.gif) left 15% no-repeat; }\r
+       \r
+#lbNext { width: 49%; height: 100%; background: transparent url(images/blank.gif) no-repeat; display: block; right: 0; float: right; }\r
+       #lbNext.grey:hover, #lbNext.grey:visited:hover { background: url(images/next_grey.gif) right 15% no-repeat; }\r
+       #lbNext.red:hover, #lbNext.red:visited:hover { background: url(images/next_red.gif) right 15% no-repeat; }\r
+       #lbNext.green:hover, #lbNext.green:visited:hover { background: url(images/next_green.gif) right 15% no-repeat; }\r
+       #lbNext.blue:hover, #lbNext.blue:visited:hover { background: url(images/next_blue.gif) right 15% no-repeat; }\r
+       #lbNext.gold:hover, #lbNext.gold:visited:hover { background: url(images/next_gold.gif) right 15% no-repeat; }\r
+\r
+#lbPrev2, #lbNext2 { text-decoration: none; font-weight: bold; }\r
+       #lbPrev2.grey, #lbNext2.grey, #lbSpacer.grey { color: #333333; }\r
+       #lbPrev2.red, #lbNext2.red, #lbSpacer.red { color: #620000; }\r
+       #lbPrev2.green, #lbNext2.green, #lbSpacer.green { color: #003300; }\r
+       #lbPrev2.blue, #lbNext2.blue, #lbSpacer.blue { color: #01379E; }\r
+       #lbPrev2.gold, #lbNext2.gold, #lbSpacer.gold { color: #666600; }\r
+       \r
+#lbPrev2_Off, #lbNext2_Off { font-weight: bold; }\r
+       #lbPrev2_Off.grey, #lbNext2_Off.grey { color: #CCCCCC; }\r
+       #lbPrev2_Off.red, #lbNext2_Off.red { color: #FFCCCC; }\r
+       #lbPrev2_Off.green, #lbNext2_Off.green { color: #82FF82; }\r
+       #lbPrev2_Off.blue, #lbNext2_Off.blue { color: #B7CAEE; }\r
+       #lbPrev2_Off.gold, #lbNext2_Off.gold { color: #E1E100; }\r
+       \r
+#lbDetailsData { padding: 0 10px; }\r
+       #lbDetailsData.grey { color: #333333; }\r
+       #lbDetailsData.red { color: #620000; }\r
+       #lbDetailsData.green { color: #003300; }\r
+       #lbDetailsData.blue { color: #01379E; }\r
+       #lbDetailsData.gold { color: #666600; }\r
+\r
+#lbDetails { width: 60%; float: left; text-align: left; }\r
+#lbCaption { display: block; font-weight: bold; }\r
+#lbNumberDisplay { float: left; display: block; padding-bottom: 1.0em; }\r
+#lbNavDisplay { float: left; display: block; padding-bottom: 1.0em; }\r
+\r
+#lbClose { width: 64px; height: 28px; float: right; margin-bottom: 1px; }\r
+       #lbClose.grey { background: url(images/close_grey.png) no-repeat; }\r
+       #lbClose.red { background: url(images/close_red.png) no-repeat; }\r
+       #lbClose.green { background: url(images/close_green.png) no-repeat; }\r
+       #lbClose.blue { background: url(images/close_blue.png) no-repeat; }\r
+       #lbClose.gold { background: url(images/close_gold.png) no-repeat; }\r
+\r
+#lbPlay { width: 64px; height: 28px; float: right; margin-bottom: 1px; }\r
+       #lbPlay.grey { background: url(images/play_grey.png) no-repeat; }\r
+       #lbPlay.red { background: url(images/play_red.png) no-repeat; }\r
+       #lbPlay.green { background: url(images/play_green.png) no-repeat; }\r
+       #lbPlay.blue { background: url(images/play_blue.png) no-repeat; }\r
+       #lbPlay.gold { background: url(images/play_gold.png) no-repeat; }\r
+       \r
+#lbPause { width: 64px; height: 28px; float: right; margin-bottom: 1px; }\r
+       #lbPause.grey { background: url(images/pause_grey.png) no-repeat; }\r
+       #lbPause.red { background: url(images/pause_red.png) no-repeat; }\r
+       #lbPause.green { background: url(images/pause_green.png) no-repeat; }\r
+       #lbPause.blue { background: url(images/pause_blue.png) no-repeat; }\r
+       #lbPause.gold { background: url(images/pause_gold.png) no-repeat; }
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/public/lytebox.js b/src/org/gss_project/gss/web/public/lytebox.js
new file mode 100644 (file)
index 0000000..1cf7210
--- /dev/null
@@ -0,0 +1,843 @@
+//***********************************************************************************************************************************/\r
+//     LyteBox v3.22\r
+//\r
+//      Author: Markus F. Hay\r
+//  Website: http://www.dolem.com/lytebox\r
+//        Date: October 2, 2007\r
+//     License: Creative Commons Attribution 3.0 License (http://creativecommons.org/licenses/by/3.0/)\r
+// Browsers: Tested successfully on WinXP with the following browsers (using no DOCTYPE and Strict/Transitional/Loose DOCTYPES):\r
+//                             * Firefox: 2.0.0.7, 1.5.0.12\r
+//                             * Internet Explorer: 7.0, 6.0 SP2, 5.5 SP2\r
+//                             * Opera: 9.23\r
+//\r
+// Releases: For up-to-date and complete release information, visit http://www.dolem.com/forum/showthread.php?tid=62\r
+//                             * v3.22 (10/02/07)\r
+//                             * v3.21 (09/30/07)\r
+//                             * v3.20 (07/12/07)\r
+//                             * v3.10 (05/28/07)\r
+//                             * v3.00 (05/15/07)\r
+//                             * v2.02 (11/13/06)\r
+//\r
+//   Credit: LyteBox was originally derived from the Lightbox class (v2.02) that was written by Lokesh Dhakar. For more\r
+//                      information please visit http://huddletogether.com/projects/lightbox2/\r
+//***********************************************************************************************************************************/\r
+Array.prototype.removeDuplicates = function () { for (var i = 1; i < this.length; i++) { if (this[i][0] == this[i-1][0]) { this.splice(i,1); } } }\r
+Array.prototype.empty = function () { for (var i = 0; i <= this.length; i++) { this.shift(); } }\r
+String.prototype.trim = function () { return this.replace(/^\s+|\s+$/g, ''); }\r
+\r
+function LyteBox() {\r
+       /*** Start Global Configuration ***/\r
+               this.theme                              = 'grey';       // themes: grey (default), red, green, blue, gold\r
+               this.hideFlash                  = true;         // controls whether or not Flash objects should be hidden\r
+               this.outerBorder                = true;         // controls whether to show the outer grey (or theme) border\r
+               this.resizeSpeed                = 8;            // controls the speed of the image resizing (1=slowest and 10=fastest)\r
+               this.maxOpacity                 = 80;           // higher opacity = darker overlay, lower opacity = lighter overlay\r
+               this.navType                    = 1;            // 1 = "Prev/Next" buttons on top left and left (default), 2 = "<< prev | next >>" links next to image number\r
+               this.autoResize                 = true;         // controls whether or not images should be resized if larger than the browser window dimensions\r
+               this.doAnimations               = true;         // controls whether or not "animate" Lytebox, i.e. resize transition between images, fade in/out effects, etc.\r
+               \r
+               this.borderSize                 = 12;           // if you adjust the padding in the CSS, you will need to update this variable -- otherwise, leave this alone...\r
+       /*** End Global Configuration ***/\r
+       \r
+       /*** Configure Slideshow Options ***/\r
+               this.slideInterval              = 4000;         // Change value (milliseconds) to increase/decrease the time between "slides" (10000 = 10 seconds)\r
+               this.showNavigation             = true;         // true to display Next/Prev buttons/text during slideshow, false to hide\r
+               this.showClose                  = true;         // true to display the Close button, false to hide\r
+               this.showDetails                = true;         // true to display image details (caption, count), false to hide\r
+               this.showPlayPause              = true;         // true to display pause/play buttons next to close button, false to hide\r
+               this.autoEnd                    = true;         // true to automatically close Lytebox after the last image is reached, false to keep open\r
+               this.pauseOnNextClick   = false;        // true to pause the slideshow when the "Next" button is clicked\r
+        this.pauseOnPrevClick  = true;         // true to pause the slideshow when the "Prev" button is clicked\r
+       /*** End Slideshow Configuration ***/\r
+       \r
+       if(this.resizeSpeed > 10) { this.resizeSpeed = 10; }\r
+       if(this.resizeSpeed < 1) { resizeSpeed = 1; }\r
+       this.resizeDuration = (11 - this.resizeSpeed) * 0.15;\r
+       this.resizeWTimerArray          = new Array();\r
+       this.resizeWTimerCount          = 0;\r
+       this.resizeHTimerArray          = new Array();\r
+       this.resizeHTimerCount          = 0;\r
+       this.showContentTimerArray      = new Array();\r
+       this.showContentTimerCount      = 0;\r
+       this.overlayTimerArray          = new Array();\r
+       this.overlayTimerCount          = 0;\r
+       this.imageTimerArray            = new Array();\r
+       this.imageTimerCount            = 0;\r
+       this.timerIDArray                       = new Array();\r
+       this.timerIDCount                       = 0;\r
+       this.slideshowIDArray           = new Array();\r
+       this.slideshowIDCount           = 0;\r
+       this.imageArray  = new Array();\r
+       this.activeImage = null;\r
+       this.slideArray  = new Array();\r
+       this.activeSlide = null;\r
+       this.frameArray  = new Array();\r
+       this.activeFrame = null;\r
+       this.checkFrame();\r
+       this.isSlideshow = false;\r
+       this.isLyteframe = false;\r
+       /*@cc_on\r
+               /*@if (@_jscript)\r
+                       this.ie = (document.all && !window.opera) ? true : false;\r
+               /*@else @*/\r
+                       this.ie = false;\r
+               /*@end\r
+       @*/\r
+       this.ie7 = (this.ie && window.XMLHttpRequest);  \r
+       this.initialize();\r
+}\r
+LyteBox.prototype.initialize = function() {\r
+       this.updateLyteboxItems();\r
+       var objBody = this.doc.getElementsByTagName("body").item(0);    \r
+       if (this.doc.getElementById('lbOverlay')) {\r
+               objBody.removeChild(this.doc.getElementById("lbOverlay"));\r
+               objBody.removeChild(this.doc.getElementById("lbMain"));\r
+       }\r
+       var objOverlay = this.doc.createElement("div");\r
+               objOverlay.setAttribute('id','lbOverlay');\r
+               objOverlay.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               if ((this.ie && !this.ie7) || (this.ie7 && this.doc.compatMode == 'BackCompat')) {\r
+                       objOverlay.style.position = 'absolute';\r
+               }\r
+               objOverlay.style.display = 'none';\r
+               objBody.appendChild(objOverlay);\r
+       var objLytebox = this.doc.createElement("div");\r
+               objLytebox.setAttribute('id','lbMain');\r
+               objLytebox.style.display = 'none';\r
+               objBody.appendChild(objLytebox);\r
+       var objOuterContainer = this.doc.createElement("div");\r
+               objOuterContainer.setAttribute('id','lbOuterContainer');\r
+               objOuterContainer.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objLytebox.appendChild(objOuterContainer);\r
+       var objIframeContainer = this.doc.createElement("div");\r
+               objIframeContainer.setAttribute('id','lbIframeContainer');\r
+               objIframeContainer.style.display = 'none';\r
+               objOuterContainer.appendChild(objIframeContainer);\r
+       var objIframe = this.doc.createElement("iframe");\r
+               objIframe.setAttribute('id','lbIframe');\r
+               objIframe.setAttribute('name','lbIframe');\r
+               objIframe.style.display = 'none';\r
+               objIframeContainer.appendChild(objIframe);\r
+       var objImageContainer = this.doc.createElement("div");\r
+               objImageContainer.setAttribute('id','lbImageContainer');\r
+               objOuterContainer.appendChild(objImageContainer);\r
+       var objLyteboxImage = this.doc.createElement("img");\r
+               objLyteboxImage.setAttribute('id','lbImage');\r
+               objImageContainer.appendChild(objLyteboxImage);\r
+       var objLoading = this.doc.createElement("div");\r
+               objLoading.setAttribute('id','lbLoading');\r
+               objOuterContainer.appendChild(objLoading);\r
+       var objDetailsContainer = this.doc.createElement("div");\r
+               objDetailsContainer.setAttribute('id','lbDetailsContainer');\r
+               objDetailsContainer.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objLytebox.appendChild(objDetailsContainer);\r
+       var objDetailsData =this.doc.createElement("div");\r
+               objDetailsData.setAttribute('id','lbDetailsData');\r
+               objDetailsData.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objDetailsContainer.appendChild(objDetailsData);\r
+       var objDetails = this.doc.createElement("div");\r
+               objDetails.setAttribute('id','lbDetails');\r
+               objDetailsData.appendChild(objDetails);\r
+       var objCaption = this.doc.createElement("span");\r
+               objCaption.setAttribute('id','lbCaption');\r
+               objDetails.appendChild(objCaption);\r
+       var objHoverNav = this.doc.createElement("div");\r
+               objHoverNav.setAttribute('id','lbHoverNav');\r
+               objImageContainer.appendChild(objHoverNav);\r
+       var objBottomNav = this.doc.createElement("div");\r
+               objBottomNav.setAttribute('id','lbBottomNav');\r
+               objDetailsData.appendChild(objBottomNav);\r
+       var objPrev = this.doc.createElement("a");\r
+               objPrev.setAttribute('id','lbPrev');\r
+               objPrev.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objPrev.setAttribute('href','#');\r
+               objHoverNav.appendChild(objPrev);\r
+       var objNext = this.doc.createElement("a");\r
+               objNext.setAttribute('id','lbNext');\r
+               objNext.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objNext.setAttribute('href','#');\r
+               objHoverNav.appendChild(objNext);\r
+       var objNumberDisplay = this.doc.createElement("span");\r
+               objNumberDisplay.setAttribute('id','lbNumberDisplay');\r
+               objDetails.appendChild(objNumberDisplay);\r
+       var objNavDisplay = this.doc.createElement("span");\r
+               objNavDisplay.setAttribute('id','lbNavDisplay');\r
+               objNavDisplay.style.display = 'none';\r
+               objDetails.appendChild(objNavDisplay);\r
+       var objClose = this.doc.createElement("a");\r
+               objClose.setAttribute('id','lbClose');\r
+               objClose.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objClose.setAttribute('href','#');\r
+               objBottomNav.appendChild(objClose);\r
+       var objPause = this.doc.createElement("a");\r
+               objPause.setAttribute('id','lbPause');\r
+               objPause.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objPause.setAttribute('href','#');\r
+               objPause.style.display = 'none';\r
+               objBottomNav.appendChild(objPause);\r
+       var objPlay = this.doc.createElement("a");\r
+               objPlay.setAttribute('id','lbPlay');\r
+               objPlay.setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+               objPlay.setAttribute('href','#');\r
+               objPlay.style.display = 'none';\r
+               objBottomNav.appendChild(objPlay);\r
+};\r
+LyteBox.prototype.updateLyteboxItems = function() {    \r
+       var anchors = (this.isFrame) ? window.parent.frames[window.name].document.getElementsByTagName('a') : document.getElementsByTagName('a');\r
+       for (var i = 0; i < anchors.length; i++) {\r
+               var anchor = anchors[i];\r
+               var relAttribute = String(anchor.getAttribute('rel'));\r
+               if (anchor.getAttribute('href')) {\r
+                       if (relAttribute.toLowerCase().match('lytebox')) {\r
+                               anchor.onclick = function () { myLytebox.start(this, false, false); return false; }\r
+                       } else if (relAttribute.toLowerCase().match('lyteshow')) {\r
+                               anchor.onclick = function () { myLytebox.start(this, true, false); return false; }\r
+                       } else if (relAttribute.toLowerCase().match('lyteframe')) {\r
+                               anchor.onclick = function () { myLytebox.start(this, false, true); return false; }\r
+                       }\r
+               }\r
+       }\r
+};\r
+LyteBox.prototype.start = function(imageLink, doSlide, doFrame) {\r
+       if (this.ie && !this.ie7) {     this.toggleSelects('hide');     }\r
+       if (this.hideFlash) { this.toggleFlash('hide'); }\r
+       this.isLyteframe = (doFrame ? true : false);\r
+       var pageSize    = this.getPageSize();\r
+       var objOverlay  = this.doc.getElementById('lbOverlay');\r
+       var objBody             = this.doc.getElementsByTagName("body").item(0);\r
+       objOverlay.style.height = pageSize[1] + "px";\r
+       objOverlay.style.display = '';\r
+       this.appear('lbOverlay', (this.doAnimations ? 0 : this.maxOpacity));\r
+       var anchors = (this.isFrame) ? window.parent.frames[window.name].document.getElementsByTagName('a') : document.getElementsByTagName('a');\r
+       if (this.isLyteframe) {\r
+               this.frameArray = [];\r
+               this.frameNum = 0;\r
+               if ((imageLink.getAttribute('rel') == 'lyteframe')) {\r
+                       var rev = imageLink.getAttribute('rev');\r
+                       this.frameArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title'), (rev == null || rev == '' ? 'width: 400px; height: 400px; scrolling: auto;' : rev)));\r
+               } else {\r
+                       if (imageLink.getAttribute('rel').indexOf('lyteframe') != -1) {\r
+                               for (var i = 0; i < anchors.length; i++) {\r
+                                       var anchor = anchors[i];\r
+                                       if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))) {\r
+                                               var rev = anchor.getAttribute('rev');\r
+                                               this.frameArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title'), (rev == null || rev == '' ? 'width: 400px; height: 400px; scrolling: auto;' : rev)));\r
+                                       }\r
+                               }\r
+                               this.frameArray.removeDuplicates();\r
+                               while(this.frameArray[this.frameNum][0] != imageLink.getAttribute('href')) { this.frameNum++; }\r
+                       }\r
+               }\r
+       } else {\r
+               this.imageArray = [];\r
+               this.imageNum = 0;\r
+               this.slideArray = [];\r
+               this.slideNum = 0;\r
+               if ((imageLink.getAttribute('rel') == 'lytebox')) {\r
+                       this.imageArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title')));\r
+               } else {\r
+                       if (imageLink.getAttribute('rel').indexOf('lytebox') != -1) {\r
+                               for (var i = 0; i < anchors.length; i++) {\r
+                                       var anchor = anchors[i];\r
+                                       if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))) {\r
+                                               this.imageArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title')));\r
+                                       }\r
+                               }\r
+                               this.imageArray.removeDuplicates();\r
+                               while(this.imageArray[this.imageNum][0] != imageLink.getAttribute('href')) { this.imageNum++; }\r
+                       }\r
+                       if (imageLink.getAttribute('rel').indexOf('lyteshow') != -1) {\r
+                               for (var i = 0; i < anchors.length; i++) {\r
+                                       var anchor = anchors[i];\r
+                                       if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == imageLink.getAttribute('rel'))) {\r
+                                               this.slideArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title')));\r
+                                       }\r
+                               }\r
+                               this.slideArray.removeDuplicates();\r
+                               while(this.slideArray[this.slideNum][0] != imageLink.getAttribute('href')) { this.slideNum++; }\r
+                       }\r
+               }\r
+       }\r
+       var object = this.doc.getElementById('lbMain');\r
+               object.style.top = (this.getPageScroll() + (pageSize[3] / 15)) + "px";\r
+               object.style.display = '';\r
+       if (!this.outerBorder) {\r
+               this.doc.getElementById('lbOuterContainer').style.border = 'none';\r
+               this.doc.getElementById('lbDetailsContainer').style.border = 'none';\r
+       } else {\r
+               this.doc.getElementById('lbOuterContainer').style.borderBottom = '';\r
+               this.doc.getElementById('lbOuterContainer').setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+       }\r
+       this.doc.getElementById('lbOverlay').onclick = function() { myLytebox.end(); return false; }\r
+       this.doc.getElementById('lbMain').onclick = function(e) {\r
+               var e = e;\r
+               if (!e) {\r
+                       if (window.parent.frames[window.name] && (parent.document.getElementsByTagName('frameset').length <= 0)) {\r
+                               e = window.parent.window.event;\r
+                       } else {\r
+                               e = window.event;\r
+                       }\r
+               }\r
+               var id = (e.target ? e.target.id : e.srcElement.id);\r
+               if (id == 'lbMain') { myLytebox.end(); return false; }\r
+       }\r
+       this.doc.getElementById('lbClose').onclick = function() { myLytebox.end(); return false; }\r
+       this.doc.getElementById('lbPause').onclick = function() { myLytebox.togglePlayPause("lbPause", "lbPlay"); return false; }\r
+       this.doc.getElementById('lbPlay').onclick = function() { myLytebox.togglePlayPause("lbPlay", "lbPause"); return false; }        \r
+       this.isSlideshow = doSlide;\r
+       this.isPaused = (this.slideNum != 0 ? true : false);\r
+       if (this.isSlideshow && this.showPlayPause && this.isPaused) {\r
+               this.doc.getElementById('lbPlay').style.display = '';\r
+               this.doc.getElementById('lbPause').style.display = 'none';\r
+       }\r
+       if (this.isLyteframe) {\r
+               this.changeContent(this.frameNum);\r
+       } else {\r
+               if (this.isSlideshow) {\r
+                       this.changeContent(this.slideNum);\r
+               } else {\r
+                       this.changeContent(this.imageNum);\r
+               }\r
+       }\r
+};\r
+LyteBox.prototype.changeContent = function(imageNum) {\r
+       if (this.isSlideshow) {\r
+               for (var i = 0; i < this.slideshowIDCount; i++) { window.clearTimeout(this.slideshowIDArray[i]); }\r
+       }\r
+       this.activeImage = this.activeSlide = this.activeFrame = imageNum;\r
+       if (!this.outerBorder) {\r
+               this.doc.getElementById('lbOuterContainer').style.border = 'none';\r
+               this.doc.getElementById('lbDetailsContainer').style.border = 'none';\r
+       } else {\r
+               this.doc.getElementById('lbOuterContainer').style.borderBottom = '';\r
+               this.doc.getElementById('lbOuterContainer').setAttribute((this.ie ? 'className' : 'class'), this.theme);\r
+       }\r
+       this.doc.getElementById('lbLoading').style.display = '';\r
+       this.doc.getElementById('lbImage').style.display = 'none';\r
+       this.doc.getElementById('lbIframe').style.display = 'none';\r
+       this.doc.getElementById('lbPrev').style.display = 'none';\r
+       this.doc.getElementById('lbNext').style.display = 'none';\r
+       this.doc.getElementById('lbIframeContainer').style.display = 'none';\r
+       this.doc.getElementById('lbDetailsContainer').style.display = 'none';\r
+       this.doc.getElementById('lbNumberDisplay').style.display = 'none';\r
+       if (this.navType == 2 || this.isLyteframe) {\r
+               object = this.doc.getElementById('lbNavDisplay');\r
+               object.innerHTML = '&nbsp;&nbsp;&nbsp;<span id="lbPrev2_Off" style="display: none;" class="' + this.theme + '">&laquo; prev</span><a href="#" id="lbPrev2" class="' + this.theme + '" style="display: none;">&laquo; prev</a> <b id="lbSpacer" class="' + this.theme + '">||</b> <span id="lbNext2_Off" style="display: none;" class="' + this.theme + '">next &raquo;</span><a href="#" id="lbNext2" class="' + this.theme + '" style="display: none;">next &raquo;</a>';\r
+               object.style.display = 'none';\r
+       }\r
+       if (this.isLyteframe) {\r
+               var iframe = myLytebox.doc.getElementById('lbIframe');\r
+               var styles = this.frameArray[this.activeFrame][2];\r
+               var aStyles = styles.split(';');\r
+               for (var i = 0; i < aStyles.length; i++) {\r
+                       if (aStyles[i].indexOf('width:') >= 0) {\r
+                               var w = aStyles[i].replace('width:', '');\r
+                               iframe.width = w.trim();\r
+                       } else if (aStyles[i].indexOf('height:') >= 0) {\r
+                               var h = aStyles[i].replace('height:', '');\r
+                               iframe.height = h.trim();\r
+                       } else if (aStyles[i].indexOf('scrolling:') >= 0) {\r
+                               var s = aStyles[i].replace('scrolling:', '');\r
+                               iframe.scrolling = s.trim();\r
+                       } else if (aStyles[i].indexOf('border:') >= 0) {\r
+                               // Not implemented yet, as there are cross-platform issues with setting the border (from a GUI standpoint)\r
+                               //var b = aStyles[i].replace('border:', '');\r
+                               //iframe.style.border = b.trim();\r
+                       }\r
+               }\r
+               this.resizeContainer(parseInt(iframe.width), parseInt(iframe.height));\r
+       } else {\r
+               imgPreloader = new Image();\r
+               imgPreloader.onload = function() {\r
+                       var imageWidth = imgPreloader.width;\r
+                       var imageHeight = imgPreloader.height;\r
+                       if (myLytebox.autoResize) {\r
+                               var pagesize = myLytebox.getPageSize();\r
+                               var x = pagesize[2] - 150;\r
+                               var y = pagesize[3] - 150;\r
+                               if (imageWidth > x) {\r
+                                       imageHeight = Math.round(imageHeight * (x / imageWidth));\r
+                                       imageWidth = x; \r
+                                       if (imageHeight > y) { \r
+                                               imageWidth = Math.round(imageWidth * (y / imageHeight));\r
+                                               imageHeight = y; \r
+                                       }\r
+                               } else if (imageHeight > y) { \r
+                                       imageWidth = Math.round(imageWidth * (y / imageHeight));\r
+                                       imageHeight = y; \r
+                                       if (imageWidth > x) {\r
+                                               imageHeight = Math.round(imageHeight * (x / imageWidth));\r
+                                               imageWidth = x;\r
+                                       }\r
+                               }\r
+                       }\r
+                       var lbImage = myLytebox.doc.getElementById('lbImage')\r
+                       lbImage.src = (myLytebox.isSlideshow ? myLytebox.slideArray[myLytebox.activeSlide][0] : myLytebox.imageArray[myLytebox.activeImage][0]);\r
+                       lbImage.width = imageWidth;\r
+                       lbImage.height = imageHeight;\r
+                       myLytebox.resizeContainer(imageWidth, imageHeight);\r
+                       imgPreloader.onload = function() {};\r
+               }\r
+               imgPreloader.src = (this.isSlideshow ? this.slideArray[this.activeSlide][0] : this.imageArray[this.activeImage][0]);\r
+       }\r
+};\r
+LyteBox.prototype.resizeContainer = function(imgWidth, imgHeight) {\r
+       this.wCur = this.doc.getElementById('lbOuterContainer').offsetWidth;\r
+       this.hCur = this.doc.getElementById('lbOuterContainer').offsetHeight;\r
+       this.xScale = ((imgWidth  + (this.borderSize * 2)) / this.wCur) * 100;\r
+       this.yScale = ((imgHeight  + (this.borderSize * 2)) / this.hCur) * 100;\r
+       var wDiff = (this.wCur - this.borderSize * 2) - imgWidth;\r
+       var hDiff = (this.hCur - this.borderSize * 2) - imgHeight;\r
+       if (!(hDiff == 0)) {\r
+               this.hDone = false;\r
+               this.resizeH('lbOuterContainer', this.hCur, imgHeight + this.borderSize*2, this.getPixelRate(this.hCur, imgHeight));\r
+       } else {\r
+               this.hDone = true;\r
+       }\r
+       if (!(wDiff == 0)) {\r
+               this.wDone = false;\r
+               this.resizeW('lbOuterContainer', this.wCur, imgWidth + this.borderSize*2, this.getPixelRate(this.wCur, imgWidth));\r
+       } else {\r
+               this.wDone = true;\r
+       }\r
+       if ((hDiff == 0) && (wDiff == 0)) {\r
+               if (this.ie){ this.pause(250); } else { this.pause(100); } \r
+       }\r
+       this.doc.getElementById('lbPrev').style.height = imgHeight + "px";\r
+       this.doc.getElementById('lbNext').style.height = imgHeight + "px";\r
+       this.doc.getElementById('lbDetailsContainer').style.width = (imgWidth + (this.borderSize * 2) + (this.ie && this.doc.compatMode == "BackCompat" && this.outerBorder ? 2 : 0)) + "px";\r
+       this.showContent();\r
+};\r
+LyteBox.prototype.showContent = function() {\r
+       if (this.wDone && this.hDone) {\r
+               for (var i = 0; i < this.showContentTimerCount; i++) { window.clearTimeout(this.showContentTimerArray[i]); }\r
+               if (this.outerBorder) {\r
+                       this.doc.getElementById('lbOuterContainer').style.borderBottom = 'none';\r
+               }\r
+               this.doc.getElementById('lbLoading').style.display = 'none';\r
+               if (this.isLyteframe) {\r
+                       this.doc.getElementById('lbIframe').style.display = '';\r
+                       this.appear('lbIframe', (this.doAnimations ? 0 : 100));\r
+               } else {\r
+                       this.doc.getElementById('lbImage').style.display = '';\r
+                       this.appear('lbImage', (this.doAnimations ? 0 : 100));\r
+                       this.preloadNeighborImages();\r
+               }\r
+               if (this.isSlideshow) {\r
+                       if(this.activeSlide == (this.slideArray.length - 1)) {\r
+                               if (this.autoEnd) {\r
+                                       this.slideshowIDArray[this.slideshowIDCount++] = setTimeout("myLytebox.end('slideshow')", this.slideInterval);\r
+                               }\r
+                       } else {\r
+                               if (!this.isPaused) {\r
+                                       this.slideshowIDArray[this.slideshowIDCount++] = setTimeout("myLytebox.changeContent("+(this.activeSlide+1)+")", this.slideInterval);\r
+                               }\r
+                       }\r
+                       this.doc.getElementById('lbHoverNav').style.display = (this.showNavigation && this.navType == 1 ? '' : 'none');\r
+                       this.doc.getElementById('lbClose').style.display = (this.showClose ? '' : 'none');\r
+                       this.doc.getElementById('lbDetails').style.display = (this.showDetails ? '' : 'none');\r
+                       this.doc.getElementById('lbPause').style.display = (this.showPlayPause && !this.isPaused ? '' : 'none');\r
+                       this.doc.getElementById('lbPlay').style.display = (this.showPlayPause && !this.isPaused ? 'none' : '');\r
+                       this.doc.getElementById('lbNavDisplay').style.display = (this.showNavigation && this.navType == 2 ? '' : 'none');\r
+               } else {\r
+                       this.doc.getElementById('lbHoverNav').style.display = (this.navType == 1 && !this.isLyteframe ? '' : 'none');\r
+                       if ((this.navType == 2 && !this.isLyteframe && this.imageArray.length > 1) || (this.frameArray.length > 1 && this.isLyteframe)) {\r
+                               this.doc.getElementById('lbNavDisplay').style.display = '';\r
+                       } else {\r
+                               this.doc.getElementById('lbNavDisplay').style.display = 'none';\r
+                       }\r
+                       this.doc.getElementById('lbClose').style.display = '';\r
+                       this.doc.getElementById('lbDetails').style.display = '';\r
+                       this.doc.getElementById('lbPause').style.display = 'none';\r
+                       this.doc.getElementById('lbPlay').style.display = 'none';\r
+               }\r
+               this.doc.getElementById('lbImageContainer').style.display = (this.isLyteframe ? 'none' : '');\r
+               this.doc.getElementById('lbIframeContainer').style.display = (this.isLyteframe ? '' : 'none');\r
+               try {\r
+                       this.doc.getElementById('lbIframe').src = this.frameArray[this.activeFrame][0];\r
+               } catch(e) { }\r
+       } else {\r
+               this.showContentTimerArray[this.showContentTimerCount++] = setTimeout("myLytebox.showContent()", 200);\r
+       }\r
+};\r
+LyteBox.prototype.updateDetails = function() {\r
+       var object = this.doc.getElementById('lbCaption');\r
+       var sTitle = (this.isSlideshow ? this.slideArray[this.activeSlide][1] : (this.isLyteframe ? this.frameArray[this.activeFrame][1] : this.imageArray[this.activeImage][1]));\r
+       object.style.display = '';\r
+       object.innerHTML = (sTitle == null ? '' : sTitle);\r
+       this.updateNav();\r
+       this.doc.getElementById('lbDetailsContainer').style.display = '';\r
+       object = this.doc.getElementById('lbNumberDisplay');\r
+       if (this.isSlideshow && this.slideArray.length > 1) {\r
+               object.style.display = '';\r
+               object.innerHTML = "Image " + eval(this.activeSlide + 1) + " of " + this.slideArray.length;\r
+               this.doc.getElementById('lbNavDisplay').style.display = (this.navType == 2 && this.showNavigation ? '' : 'none');\r
+       } else if (this.imageArray.length > 1 && !this.isLyteframe) {\r
+               object.style.display = '';\r
+               object.innerHTML = "Image " + eval(this.activeImage + 1) + " of " + this.imageArray.length;\r
+               this.doc.getElementById('lbNavDisplay').style.display = (this.navType == 2 ? '' : 'none');\r
+       } else if (this.frameArray.length > 1 && this.isLyteframe) {\r
+               object.style.display = '';\r
+               object.innerHTML = "Page " + eval(this.activeFrame + 1) + " of " + this.frameArray.length;\r
+               this.doc.getElementById('lbNavDisplay').style.display = '';\r
+       } else {\r
+               this.doc.getElementById('lbNavDisplay').style.display = 'none';\r
+       }\r
+       this.appear('lbDetailsContainer', (this.doAnimations ? 0 : 100));\r
+};\r
+LyteBox.prototype.updateNav = function() {\r
+       if (this.isSlideshow) {\r
+               if (this.activeSlide != 0) {\r
+                       var object = (this.navType == 2 ? this.doc.getElementById('lbPrev2') : this.doc.getElementById('lbPrev'));\r
+                               object.style.display = '';\r
+                               object.onclick = function() {\r
+                                       if (myLytebox.pauseOnPrevClick) { myLytebox.togglePlayPause("lbPause", "lbPlay"); }\r
+                                       myLytebox.changeContent(myLytebox.activeSlide - 1); return false;\r
+                               }\r
+               } else {\r
+                       if (this.navType == 2) { this.doc.getElementById('lbPrev2_Off').style.display = ''; }\r
+               }\r
+               if (this.activeSlide != (this.slideArray.length - 1)) {\r
+                       var object = (this.navType == 2 ? this.doc.getElementById('lbNext2') : this.doc.getElementById('lbNext'));\r
+                               object.style.display = '';\r
+                               object.onclick = function() {\r
+                                       if (myLytebox.pauseOnNextClick) { myLytebox.togglePlayPause("lbPause", "lbPlay"); }\r
+                                       myLytebox.changeContent(myLytebox.activeSlide + 1); return false;\r
+                               }\r
+               } else {\r
+                       if (this.navType == 2) { this.doc.getElementById('lbNext2_Off').style.display = ''; }\r
+               }\r
+       } else if (this.isLyteframe) {\r
+               if(this.activeFrame != 0) {\r
+                       var object = this.doc.getElementById('lbPrev2');\r
+                               object.style.display = '';\r
+                               object.onclick = function() {\r
+                                       myLytebox.changeContent(myLytebox.activeFrame - 1); return false;\r
+                               }\r
+               } else {\r
+                       this.doc.getElementById('lbPrev2_Off').style.display = '';\r
+               }\r
+               if(this.activeFrame != (this.frameArray.length - 1)) {\r
+                       var object = this.doc.getElementById('lbNext2');\r
+                               object.style.display = '';\r
+                               object.onclick = function() {\r
+                                       myLytebox.changeContent(myLytebox.activeFrame + 1); return false;\r
+                               }\r
+               } else {\r
+                       this.doc.getElementById('lbNext2_Off').style.display = '';\r
+               }               \r
+       } else {\r
+               if(this.activeImage != 0) {\r
+                       var object = (this.navType == 2 ? this.doc.getElementById('lbPrev2') : this.doc.getElementById('lbPrev'));\r
+                               object.style.display = '';\r
+                               object.onclick = function() {\r
+                                       myLytebox.changeContent(myLytebox.activeImage - 1); return false;\r
+                               }\r
+               } else {\r
+                       if (this.navType == 2) { this.doc.getElementById('lbPrev2_Off').style.display = ''; }\r
+               }\r
+               if(this.activeImage != (this.imageArray.length - 1)) {\r
+                       var object = (this.navType == 2 ? this.doc.getElementById('lbNext2') : this.doc.getElementById('lbNext'));\r
+                               object.style.display = '';\r
+                               object.onclick = function() {\r
+                                       myLytebox.changeContent(myLytebox.activeImage + 1); return false;\r
+                               }\r
+               } else {\r
+                       if (this.navType == 2) { this.doc.getElementById('lbNext2_Off').style.display = ''; }\r
+               }\r
+       }\r
+       this.enableKeyboardNav();\r
+};\r
+LyteBox.prototype.enableKeyboardNav = function() { document.onkeydown = this.keyboardAction; };\r
+LyteBox.prototype.disableKeyboardNav = function() { document.onkeydown = ''; };\r
+LyteBox.prototype.keyboardAction = function(e) {\r
+       var keycode = key = escape = null;\r
+       keycode = (e == null) ? event.keyCode : e.which;\r
+       key             = String.fromCharCode(keycode).toLowerCase();\r
+       escape  = (e == null) ? 27 : e.DOM_VK_ESCAPE;\r
+       if ((key == 'x') || (key == 'c') || (keycode == escape)) {\r
+               myLytebox.end();\r
+       } else if ((key == 'p') || (keycode == 37)) {\r
+               if (myLytebox.isSlideshow) {\r
+                       if(myLytebox.activeSlide != 0) {\r
+                               myLytebox.disableKeyboardNav();\r
+                               myLytebox.changeContent(myLytebox.activeSlide - 1);\r
+                       }\r
+               } else if (myLytebox.isLyteframe) {\r
+                       if(myLytebox.activeFrame != 0) {\r
+                               myLytebox.disableKeyboardNav();\r
+                               myLytebox.changeContent(myLytebox.activeFrame - 1);\r
+                       }\r
+               } else {\r
+                       if(myLytebox.activeImage != 0) {\r
+                               myLytebox.disableKeyboardNav();\r
+                               myLytebox.changeContent(myLytebox.activeImage - 1);\r
+                       }\r
+               }\r
+       } else if ((key == 'n') || (keycode == 39)) {\r
+               if (myLytebox.isSlideshow) {\r
+                       if(myLytebox.activeSlide != (myLytebox.slideArray.length - 1)) {\r
+                               myLytebox.disableKeyboardNav();\r
+                               myLytebox.changeContent(myLytebox.activeSlide + 1);\r
+                       }\r
+               } else if (myLytebox.isLyteframe) {\r
+                       if(myLytebox.activeFrame != (myLytebox.frameArray.length - 1)) {\r
+                               myLytebox.disableKeyboardNav();\r
+                               myLytebox.changeContent(myLytebox.activeFrame + 1);\r
+                       }\r
+               } else {\r
+                       if(myLytebox.activeImage != (myLytebox.imageArray.length - 1)) {\r
+                               myLytebox.disableKeyboardNav();\r
+                               myLytebox.changeContent(myLytebox.activeImage + 1);\r
+                       }\r
+               }\r
+       }\r
+};\r
+LyteBox.prototype.preloadNeighborImages = function() {\r
+       if (this.isSlideshow) {\r
+               if ((this.slideArray.length - 1) > this.activeSlide) {\r
+                       preloadNextImage = new Image();\r
+                       preloadNextImage.src = this.slideArray[this.activeSlide + 1][0];\r
+               }\r
+               if(this.activeSlide > 0) {\r
+                       preloadPrevImage = new Image();\r
+                       preloadPrevImage.src = this.slideArray[this.activeSlide - 1][0];\r
+               }\r
+       } else {\r
+               if ((this.imageArray.length - 1) > this.activeImage) {\r
+                       preloadNextImage = new Image();\r
+                       preloadNextImage.src = this.imageArray[this.activeImage + 1][0];\r
+               }\r
+               if(this.activeImage > 0) {\r
+                       preloadPrevImage = new Image();\r
+                       preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];\r
+               }\r
+       }\r
+};\r
+LyteBox.prototype.togglePlayPause = function(hideID, showID) {\r
+       if (this.isSlideshow && hideID == "lbPause") {\r
+               for (var i = 0; i < this.slideshowIDCount; i++) { window.clearTimeout(this.slideshowIDArray[i]); }\r
+       }\r
+       this.doc.getElementById(hideID).style.display = 'none';\r
+       this.doc.getElementById(showID).style.display = '';\r
+       if (hideID == "lbPlay") {\r
+               this.isPaused = false;\r
+               if (this.activeSlide == (this.slideArray.length - 1)) {\r
+                       this.end();\r
+               } else {\r
+                       this.changeContent(this.activeSlide + 1);\r
+               }\r
+       } else {\r
+               this.isPaused = true;\r
+       }\r
+};\r
+LyteBox.prototype.end = function(caller) {\r
+       var closeClick = (caller == 'slideshow' ? false : true);\r
+       if (this.isSlideshow && this.isPaused && !closeClick) { return; }\r
+       this.disableKeyboardNav();\r
+       this.doc.getElementById('lbMain').style.display = 'none';\r
+       this.fade('lbOverlay', (this.doAnimations ? this.maxOpacity : 0));\r
+       this.toggleSelects('visible');\r
+       if (this.hideFlash) { this.toggleFlash('visible'); }\r
+       if (this.isSlideshow) {\r
+               for (var i = 0; i < this.slideshowIDCount; i++) { window.clearTimeout(this.slideshowIDArray[i]); }\r
+       }\r
+       if (this.isLyteframe) {\r
+                this.initialize();\r
+       }\r
+};\r
+LyteBox.prototype.checkFrame = function() {\r
+       if (window.parent.frames[window.name] && (parent.document.getElementsByTagName('frameset').length <= 0)) {\r
+               this.isFrame = true;\r
+               this.lytebox = "window.parent." + window.name + ".myLytebox";\r
+               this.doc = parent.document;\r
+       } else {\r
+               this.isFrame = false;\r
+               this.lytebox = "myLytebox";\r
+               this.doc = document;\r
+       }\r
+};\r
+LyteBox.prototype.getPixelRate = function(cur, img) {\r
+       var diff = (img > cur) ? img - cur : cur - img;\r
+       if (diff >= 0 && diff <= 100) { return 10; }\r
+       if (diff > 100 && diff <= 200) { return 15; }\r
+       if (diff > 200 && diff <= 300) { return 20; }\r
+       if (diff > 300 && diff <= 400) { return 25; }\r
+       if (diff > 400 && diff <= 500) { return 30; }\r
+       if (diff > 500 && diff <= 600) { return 35; }\r
+       if (diff > 600 && diff <= 700) { return 40; }\r
+       if (diff > 700) { return 45; }\r
+};\r
+LyteBox.prototype.appear = function(id, opacity) {\r
+       var object = this.doc.getElementById(id).style;\r
+       object.opacity = (opacity / 100);\r
+       object.MozOpacity = (opacity / 100);\r
+       object.KhtmlOpacity = (opacity / 100);\r
+       object.filter = "alpha(opacity=" + (opacity + 10) + ")";\r
+       if (opacity == 100 && (id == 'lbImage' || id == 'lbIframe')) {\r
+               try { object.removeAttribute("filter"); } catch(e) {}   /* Fix added for IE Alpha Opacity Filter bug. */\r
+               this.updateDetails();\r
+       } else if (opacity >= this.maxOpacity && id == 'lbOverlay') {\r
+               for (var i = 0; i < this.overlayTimerCount; i++) { window.clearTimeout(this.overlayTimerArray[i]); }\r
+               return;\r
+       } else if (opacity >= 100 && id == 'lbDetailsContainer') {\r
+               try { object.removeAttribute("filter"); } catch(e) {}   /* Fix added for IE Alpha Opacity Filter bug. */\r
+               for (var i = 0; i < this.imageTimerCount; i++) { window.clearTimeout(this.imageTimerArray[i]); }\r
+               this.doc.getElementById('lbOverlay').style.height = this.getPageSize()[1] + "px";\r
+       } else {\r
+               if (id == 'lbOverlay') {\r
+                       this.overlayTimerArray[this.overlayTimerCount++] = setTimeout("myLytebox.appear('" + id + "', " + (opacity+20) + ")", 1);\r
+               } else {\r
+                       this.imageTimerArray[this.imageTimerCount++] = setTimeout("myLytebox.appear('" + id + "', " + (opacity+10) + ")", 1);\r
+               }\r
+       }\r
+};\r
+LyteBox.prototype.fade = function(id, opacity) {\r
+       var object = this.doc.getElementById(id).style;\r
+       object.opacity = (opacity / 100);\r
+       object.MozOpacity = (opacity / 100);\r
+       object.KhtmlOpacity = (opacity / 100);\r
+       object.filter = "alpha(opacity=" + opacity + ")";\r
+       if (opacity <= 0) {\r
+               try {\r
+                       object.display = 'none';\r
+               } catch(err) { }\r
+       } else if (id == 'lbOverlay') {\r
+               this.overlayTimerArray[this.overlayTimerCount++] = setTimeout("myLytebox.fade('" + id + "', " + (opacity-20) + ")", 1);\r
+       } else {\r
+               this.timerIDArray[this.timerIDCount++] = setTimeout("myLytebox.fade('" + id + "', " + (opacity-10) + ")", 1);\r
+       }\r
+};\r
+LyteBox.prototype.resizeW = function(id, curW, maxW, pixelrate, speed) {\r
+       if (!this.hDone) {\r
+               this.resizeWTimerArray[this.resizeWTimerCount++] = setTimeout("myLytebox.resizeW('" + id + "', " + curW + ", " + maxW + ", " + pixelrate + ")", 100);\r
+               return;\r
+       }\r
+       var object = this.doc.getElementById(id);\r
+       var timer = speed ? speed : (this.resizeDuration/2);\r
+       var newW = (this.doAnimations ? curW : maxW);\r
+       object.style.width = (newW) + "px";\r
+       if (newW < maxW) {\r
+               newW += (newW + pixelrate >= maxW) ? (maxW - newW) : pixelrate;\r
+       } else if (newW > maxW) {\r
+               newW -= (newW - pixelrate <= maxW) ? (newW - maxW) : pixelrate;\r
+       }\r
+       this.resizeWTimerArray[this.resizeWTimerCount++] = setTimeout("myLytebox.resizeW('" + id + "', " + newW + ", " + maxW + ", " + pixelrate + ", " + (timer+0.02) + ")", timer+0.02);\r
+       if (parseInt(object.style.width) == maxW) {\r
+               this.wDone = true;\r
+               for (var i = 0; i < this.resizeWTimerCount; i++) { window.clearTimeout(this.resizeWTimerArray[i]); }\r
+       }\r
+};\r
+LyteBox.prototype.resizeH = function(id, curH, maxH, pixelrate, speed) {\r
+       var timer = speed ? speed : (this.resizeDuration/2);\r
+       var object = this.doc.getElementById(id);\r
+       var newH = (this.doAnimations ? curH : maxH);\r
+       object.style.height = (newH) + "px";\r
+       if (newH < maxH) {\r
+               newH += (newH + pixelrate >= maxH) ? (maxH - newH) : pixelrate;\r
+       } else if (newH > maxH) {\r
+               newH -= (newH - pixelrate <= maxH) ? (newH - maxH) : pixelrate;\r
+       }\r
+       this.resizeHTimerArray[this.resizeHTimerCount++] = setTimeout("myLytebox.resizeH('" + id + "', " + newH + ", " + maxH + ", " + pixelrate + ", " + (timer+.02) + ")", timer+.02);\r
+       if (parseInt(object.style.height) == maxH) {\r
+               this.hDone = true;\r
+               for (var i = 0; i < this.resizeHTimerCount; i++) { window.clearTimeout(this.resizeHTimerArray[i]); }\r
+       }\r
+};\r
+LyteBox.prototype.getPageScroll = function() {\r
+       if (self.pageYOffset) {\r
+               return this.isFrame ? parent.pageYOffset : self.pageYOffset;\r
+       } else if (this.doc.documentElement && this.doc.documentElement.scrollTop){\r
+               return this.doc.documentElement.scrollTop;\r
+       } else if (document.body) {\r
+               return this.doc.body.scrollTop;\r
+       }\r
+};\r
+LyteBox.prototype.getPageSize = function() {   \r
+       var xScroll, yScroll, windowWidth, windowHeight;\r
+       if (window.innerHeight && window.scrollMaxY) {\r
+               xScroll = this.doc.scrollWidth;\r
+               yScroll = (this.isFrame ? parent.innerHeight : self.innerHeight) + (this.isFrame ? parent.scrollMaxY : self.scrollMaxY);\r
+       } else if (this.doc.body.scrollHeight > this.doc.body.offsetHeight){\r
+               xScroll = this.doc.body.scrollWidth;\r
+               yScroll = this.doc.body.scrollHeight;\r
+       } else {\r
+               xScroll = this.doc.getElementsByTagName("html").item(0).offsetWidth;\r
+               yScroll = this.doc.getElementsByTagName("html").item(0).offsetHeight;\r
+               xScroll = (xScroll < this.doc.body.offsetWidth) ? this.doc.body.offsetWidth : xScroll;\r
+               yScroll = (yScroll < this.doc.body.offsetHeight) ? this.doc.body.offsetHeight : yScroll;\r
+       }\r
+       if (self.innerHeight) {\r
+               windowWidth = (this.isFrame) ? parent.innerWidth : self.innerWidth;\r
+               windowHeight = (this.isFrame) ? parent.innerHeight : self.innerHeight;\r
+       } else if (document.documentElement && document.documentElement.clientHeight) {\r
+               windowWidth = this.doc.documentElement.clientWidth;\r
+               windowHeight = this.doc.documentElement.clientHeight;\r
+       } else if (document.body) {\r
+               windowWidth = this.doc.getElementsByTagName("html").item(0).clientWidth;\r
+               windowHeight = this.doc.getElementsByTagName("html").item(0).clientHeight;\r
+               windowWidth = (windowWidth == 0) ? this.doc.body.clientWidth : windowWidth;\r
+               windowHeight = (windowHeight == 0) ? this.doc.body.clientHeight : windowHeight;\r
+       }\r
+       var pageHeight = (yScroll < windowHeight) ? windowHeight : yScroll;\r
+       var pageWidth = (xScroll < windowWidth) ? windowWidth : xScroll;\r
+       return new Array(pageWidth, pageHeight, windowWidth, windowHeight);\r
+};\r
+LyteBox.prototype.toggleFlash = function(state) {\r
+       var objects = this.doc.getElementsByTagName("object");\r
+       for (var i = 0; i < objects.length; i++) {\r
+               objects[i].style.visibility = (state == "hide") ? 'hidden' : 'visible';\r
+       }\r
+       var embeds = this.doc.getElementsByTagName("embed");\r
+       for (var i = 0; i < embeds.length; i++) {\r
+               embeds[i].style.visibility = (state == "hide") ? 'hidden' : 'visible';\r
+       }\r
+       if (this.isFrame) {\r
+               for (var i = 0; i < parent.frames.length; i++) {\r
+                       try {\r
+                               objects = parent.frames[i].window.document.getElementsByTagName("object");\r
+                               for (var j = 0; j < objects.length; j++) {\r
+                                       objects[j].style.visibility = (state == "hide") ? 'hidden' : 'visible';\r
+                               }\r
+                       } catch(e) { }\r
+                       try {\r
+                               embeds = parent.frames[i].window.document.getElementsByTagName("embed");\r
+                               for (var j = 0; j < embeds.length; j++) {\r
+                                       embeds[j].style.visibility = (state == "hide") ? 'hidden' : 'visible';\r
+                               }\r
+                       } catch(e) { }\r
+               }\r
+       }\r
+};\r
+LyteBox.prototype.toggleSelects = function(state) {\r
+       var selects = this.doc.getElementsByTagName("select");\r
+       for (var i = 0; i < selects.length; i++ ) {\r
+               selects[i].style.visibility = (state == "hide") ? 'hidden' : 'visible';\r
+       }\r
+       if (this.isFrame) {\r
+               for (var i = 0; i < parent.frames.length; i++) {\r
+                       try {\r
+                               selects = parent.frames[i].window.document.getElementsByTagName("select");\r
+                               for (var j = 0; j < selects.length; j++) {\r
+                                       selects[j].style.visibility = (state == "hide") ? 'hidden' : 'visible';\r
+                               }\r
+                       } catch(e) { }\r
+               }\r
+       }\r
+};\r
+LyteBox.prototype.pause = function(numberMillis) {\r
+       var now = new Date();\r
+       var exitTime = now.getTime() + numberMillis;\r
+       while (true) {\r
+               now = new Date();\r
+               if (now.getTime() > exitTime) { return; }\r
+       }\r
+};\r
+if (window.addEventListener) {\r
+       window.addEventListener("load",initLytebox,false);\r
+} else if (window.attachEvent) {\r
+       window.attachEvent("onload",initLytebox);\r
+} else {\r
+       window.onload = function() {initLytebox();}\r
+}\r
+function initLytebox() { myLytebox = new LyteBox(); }
\ No newline at end of file
diff --git a/src/org/gss_project/gss/web/public/main.css b/src/org/gss_project/gss/web/public/main.css
new file mode 100644 (file)
index 0000000..0809576
--- /dev/null
@@ -0,0 +1,138 @@
+/* kill defaults */\r
+\r
+html, body, p, ul, dl, li, h1, h2, h3, h4, img {\r
+margin: 0;\r
+padding: 0;\r
+}\r
+\r
+ul     {\r
+padding: 10px;\r
+}\r
+\r
+img    {\r
+border: 0;\r
+padding: 8;\r
+}\r
+\r
+/* ============= */\r
+p {\r
+       margin-bottom: 20px;\r
+}\r
+\r
+a {\r
+       text-decoration: none;\r
+       color: #4d6399;\r
+}\r
+\r
+a:hover        {\r
+       text-decoration: underline;\r
+}\r
+\r
+a:active {\r
+       border: none;\r
+}\r
+\r
+h1     {\r
+       font-size: 24px;\r
+       font-weight: bold;\r
+       margin-top: 23px;\r
+       margin-bottom: 29px;\r
+       text-align: center;\r
+}\r
+\r
+h2     {\r
+       font-size: 16px;\r
+       font-weight: bold;\r
+       margin-top: 23px;\r
+       margin-bottom: 9px;\r
+}\r
+\r
+h3     {\r
+       font-size: 12px;\r
+       font-weight: bold;\r
+       margin-top: 23px;\r
+       margin-bottom: 9px;\r
+}\r
+\r
+body {\r
+       background: url(/pithos/images/background.png);\r
+       font-family: 'Lucida Grande', Verdana, Helvetica, Arial, sans-serif;\r
+       font-size: 12px;\r
+       line-height: 20px;\r
+       color: #222;\r
+       margin: 0px 20px 0px 20px; \r
+       text-align: justify;\r
+}\r
+\r
+table {\r
+       font-family: 'Lucida Grande', Verdana, Helvetica, Arial, sans-serif;\r
+       font-size: 12px;\r
+       font-style: italic;\r
+}\r
+\r
+div.page_main  {\r
+       margin-left: 25px;\r
+       margin-right: 25px;\r
+       padding-left: 20px;\r
+       padding-right: 20px;\r
+}\r
+\r
+div.wrapper {\r
+       width: 1024px; \r
+       position: relative; \r
+       background: url(/pithos/images/page_shadow.png) repeat-y;\r
+       margin-left: auto;\r
+       margin-right: auto;\r
+}\r
+\r
+div.header{\r
+       width: 1024px;\r
+       position: relative;\r
+       background: url(/pithos/images/header.png) no-repeat;\r
+       margin-left: auto;\r
+       margin-right: auto;\r
+       padding:15px;\r
+}\r
+\r
+div.footer{\r
+       width: 1024px;\r
+       height: 26px;\r
+       background: url(/pithos/images/bottom.png) no-repeat;\r
+       margin-left: auto;\r
+       margin-right: auto;\r
+}\r
+\r
+div.disclaimer {\r
+       background: url(/pithos/images/background.png);\r
+       margin-top: 0;\r
+       text-align: center;\r
+       font-size: 10px;\r
+       padding-bottom: 25px;\r
+       text-decoration: none;\r
+}\r
+\r
+div.image_logo{\r
+       float:left;\r
+       width: 100%; \r
+       padding:0px;\r
+       margin:0px 0px 0px 11px;\r
+}\r
+\r
+div.logo-wrap img {\r
+       padding:0px;\r
+       margin:0px;\r
+       border:none;\r
+}\r
+\r
+p.big {\r
+       font-size: 36px;\r
+       font-weight: bold;\r
+}\r
+\r
+p.blurb {\r
+       width: 70%;\r
+}\r
+\r
+div.error {\r
+       color: #f00;\r
+}\r
diff --git a/src/org/gss_project/gss/web/public/sha1.js b/src/org/gss_project/gss/web/public/sha1.js
new file mode 100644 (file)
index 0000000..11014f8
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
+ * in FIPS PUB 180-1
+ * Version 2.1a Copyright Paul Johnston 2000 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
+function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
+function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
+function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
+function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
+function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function sha1_vm_test()
+{
+  return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
+}
+
+/*
+ * Calculate the SHA-1 of an array of big-endian words, and a bit length
+ */
+function core_sha1(x, len)
+{
+  /* append padding */
+  x[len >> 5] |= 0x80 << (24 - len % 32);
+  x[((len + 64 >> 9) << 4) + 15] = len;
+
+  var w = Array(80);
+  var a =  1732584193;
+  var b = -271733879;
+  var c = -1732584194;
+  var d =  271733878;
+  var e = -1009589776;
+
+  for(var i = 0; i < x.length; i += 16)
+  {
+    var olda = a;
+    var oldb = b;
+    var oldc = c;
+    var oldd = d;
+    var olde = e;
+
+    for(var j = 0; j < 80; j++)
+    {
+      if(j < 16) w[j] = x[i + j];
+      else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
+      var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
+                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
+      e = d;
+      d = c;
+      c = rol(b, 30);
+      b = a;
+      a = t;
+    }
+
+    a = safe_add(a, olda);
+    b = safe_add(b, oldb);
+    c = safe_add(c, oldc);
+    d = safe_add(d, oldd);
+    e = safe_add(e, olde);
+  }
+  return Array(a, b, c, d, e);
+
+}
+
+/*
+ * Perform the appropriate triplet combination function for the current
+ * iteration
+ */
+function sha1_ft(t, b, c, d)
+{
+  if(t < 20) return (b & c) | ((~b) & d);
+  if(t < 40) return b ^ c ^ d;
+  if(t < 60) return (b & c) | (b & d) | (c & d);
+  return b ^ c ^ d;
+}
+
+/*
+ * Determine the appropriate additive constant for the current iteration
+ */
+function sha1_kt(t)
+{
+  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
+         (t < 60) ? -1894007588 : -899497514;
+}
+
+/*
+ * Calculate the HMAC-SHA1 of a key and some data
+ */
+function core_hmac_sha1(key, data)
+{
+  var bkey = str2binb(key);
+  if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
+
+  var ipad = Array(16), opad = Array(16);
+  for(var i = 0; i < 16; i++)
+  {
+    ipad[i] = bkey[i] ^ 0x36363636;
+    opad[i] = bkey[i] ^ 0x5C5C5C5C;
+  }
+
+  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
+  return core_sha1(opad.concat(hash), 512 + 160);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+  return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function rol(num, cnt)
+{
+  return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * Convert an 8-bit or 16-bit string to an array of big-endian words
+ * In 8-bit function, characters >255 have their hi-byte silently ignored.
+ */
+function str2binb(str)
+{
+  var bin = Array();
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < str.length * chrsz; i += chrsz)
+    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
+  return bin;
+}
+
+/*
+ * Convert an array of big-endian words to a string
+ */
+function binb2str(bin)
+{
+  var str = "";
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < bin.length * 32; i += chrsz)
+    str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
+  return str;
+}
+
+/*
+ * Convert an array of big-endian words to a hex string.
+ */
+function binb2hex(binarray)
+{
+  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i++)
+  {
+    str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
+           hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of big-endian words to a base-64 string
+ */
+function binb2b64(binarray)
+{
+  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i += 3)
+  {
+    var triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16)
+                | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
+                |  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
+    for(var j = 0; j < 4; j++)
+    {
+      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
+      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
+    }
+  }
+  return str;
+}
diff --git a/src/org/gss_project/gss/web/public/suggest/corner.png b/src/org/gss_project/gss/web/public/suggest/corner.png
new file mode 100644 (file)
index 0000000..51aa458
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/corner.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/hborder.png b/src/org/gss_project/gss/web/public/suggest/hborder.png
new file mode 100644 (file)
index 0000000..1c8e78b
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/hborder.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topleft.png b/src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topleft.png
new file mode 100644 (file)
index 0000000..e1da98e
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topleft.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topright.png b/src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topright.png
new file mode 100644 (file)
index 0000000..a786ccc
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/ie6/corner_dialog_topright.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/ie6/hborder_blue_shadow.png b/src/org/gss_project/gss/web/public/suggest/ie6/hborder_blue_shadow.png
new file mode 100644 (file)
index 0000000..7b52b8e
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/ie6/hborder_blue_shadow.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/ie6/hborder_gray_shadow.png b/src/org/gss_project/gss/web/public/suggest/ie6/hborder_gray_shadow.png
new file mode 100644 (file)
index 0000000..f4d1844
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/ie6/hborder_gray_shadow.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/ie6/vborder_blue_shadow.png b/src/org/gss_project/gss/web/public/suggest/ie6/vborder_blue_shadow.png
new file mode 100644 (file)
index 0000000..6dcb44a
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/ie6/vborder_blue_shadow.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/ie6/vborder_gray_shadow.png b/src/org/gss_project/gss/web/public/suggest/ie6/vborder_gray_shadow.png
new file mode 100644 (file)
index 0000000..fccce49
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/ie6/vborder_gray_shadow.png differ
diff --git a/src/org/gss_project/gss/web/public/suggest/vborder.png b/src/org/gss_project/gss/web/public/suggest/vborder.png
new file mode 100644 (file)
index 0000000..435b816
Binary files /dev/null and b/src/org/gss_project/gss/web/public/suggest/vborder.png differ
diff --git a/war/WEB-INF/lib/commons-fileupload-1.2.jar b/war/WEB-INF/lib/commons-fileupload-1.2.jar
new file mode 100644 (file)
index 0000000..12539f5
Binary files /dev/null and b/war/WEB-INF/lib/commons-fileupload-1.2.jar differ
diff --git a/war/WEB-INF/lib/commons-io-1.3.2.jar b/war/WEB-INF/lib/commons-io-1.3.2.jar
new file mode 100644 (file)
index 0000000..865c9e4
Binary files /dev/null and b/war/WEB-INF/lib/commons-io-1.3.2.jar differ
diff --git a/war/WEB-INF/web.xml b/war/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..c46f02e
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app>
+               <error-page>
+                       <error-code>
+                   503
+               </error-code>
+               <location>
+                   /error503.html
+               </location>
+           </error-page>
+               <error-page>
+                       <error-code>
+                   502
+               </error-code>
+               <location>
+                   /error502.html
+               </location>
+           </error-page>
+               <error-page>
+                       <error-code>
+                   403
+               </error-code>
+               <location>
+                   /error403.html
+               </location>
+           </error-page>
+
+               <filter>
+                       <filter-name>CacheFilter</filter-name>
+                       <filter-class>org.gss_project.gss.server.CacheFilter</filter-class>
+               </filter>
+               <filter-mapping>
+                       <filter-name>CacheFilter</filter-name>
+                       <url-pattern>/*</url-pattern>
+               </filter-mapping>
+
+        <servlet>
+                <servlet-name>Login</servlet-name>
+                <servlet-class>org.gss_project.gss.server.Login</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>Policy</servlet-name>
+                <servlet-class>org.gss_project.gss.server.Policy</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>Registration</servlet-name>
+                <servlet-class>org.gss_project.gss.server.Registration</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>Invitations</servlet-name>
+                <servlet-class>org.gss_project.gss.server.Invitations</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>CouponHandler</servlet-name>
+                <servlet-class>org.gss_project.gss.server.CouponHandler</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>CouponVerifier</servlet-name>
+                <servlet-class>org.gss_project.gss.server.CouponVerifier</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>NonceIssuer</servlet-name>
+                <servlet-class>org.gss_project.gss.server.NonceIssuer</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>TokenRetriever</servlet-name>
+                <servlet-class>org.gss_project.gss.server.TokenRetriever</servlet-class>
+        </servlet>
+        <servlet>
+                <servlet-name>RESTHandler</servlet-name>
+                <servlet-class>org.gss_project.gss.server.rest.RequestHandler</servlet-class>
+                               <init-param>
+                                       <param-name>input</param-name>
+                                       <param-value>4096</param-value>
+                               </init-param>
+                               <init-param>
+                                       <param-name>output</param-name>
+                                       <param-value>4096</param-value>
+                               </init-param>
+        </servlet>
+
+        <servlet-mapping>
+                <servlet-name>Login</servlet-name>
+                <url-pattern>/login</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>Policy</servlet-name>
+                <url-pattern>/policy</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>Registration</servlet-name>
+                <url-pattern>/register</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>Invitations</servlet-name>
+                <url-pattern>/invites</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>CouponHandler</servlet-name>
+                <url-pattern>/coupon</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>CouponVerifier</servlet-name>
+                <url-pattern>/submitCoupon</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>NonceIssuer</servlet-name>
+                <url-pattern>/nonce</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>TokenRetriever</servlet-name>
+                <url-pattern>/token</url-pattern>
+        </servlet-mapping>
+        <servlet-mapping>
+                <servlet-name>RESTHandler</servlet-name>
+                <url-pattern>/rest/*</url-pattern>
+        </servlet-mapping>
+</web-app> 
\ No newline at end of file