X-Git-Url: https://code.grnet.gr/git/pithos-web-client/blobdiff_plain/9fbf55969228185fda73a2d61e6c865f4b8f9bb3..b100110012fe9be036039420710265283eef651c:/src/gr/grnet/pithos/web/client/Pithos.java diff --git a/src/gr/grnet/pithos/web/client/Pithos.java b/src/gr/grnet/pithos/web/client/Pithos.java index 47f1ac8..fcf9fb2 100644 --- a/src/gr/grnet/pithos/web/client/Pithos.java +++ b/src/gr/grnet/pithos/web/client/Pithos.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 GRNET S.A. All rights reserved. + * Copyright 2011-2012 GRNET S.A. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -53,9 +53,6 @@ import gr.grnet.pithos.web.client.rest.GetRequest; import gr.grnet.pithos.web.client.rest.HeadRequest; import gr.grnet.pithos.web.client.rest.PutRequest; import gr.grnet.pithos.web.client.rest.RestException; -import gr.grnet.pithos.web.client.tagtree.Tag; -import gr.grnet.pithos.web.client.tagtree.TagTreeView; -import gr.grnet.pithos.web.client.tagtree.TagTreeViewModel; import java.util.ArrayList; import java.util.Date; @@ -64,9 +61,13 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import org.apache.http.HttpStatus; + import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.RepeatingCommand; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; @@ -78,12 +79,19 @@ import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; import com.google.gwt.http.client.URL; -import com.google.gwt.i18n.client.NumberFormat; +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat; +import com.google.gwt.i18n.client.Dictionary; +import com.google.gwt.i18n.client.TimeZone; +import com.google.gwt.i18n.client.TimeZoneInfo; +import com.google.gwt.i18n.client.constants.TimeZoneConstants; 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; import com.google.gwt.json.client.JSONValue; +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.user.client.Command; @@ -94,12 +102,13 @@ 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.FlowPanel; 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.HorizontalSplitPanel; -import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.view.client.SelectionChangeEvent; @@ -114,6 +123,37 @@ public class Pithos implements EntryPoint, ResizeHandler { public static final String HOME_CONTAINER = "pithos"; public static final String TRASH_CONTAINER = "trash"; + + public static final Configuration config = GWT.create(Configuration.class); + + public interface Style extends CssResource { + String commandAnchor(); + + String statistics(); + + @ClassName("gwt-HTML") + String html(); + + String uploadAlert(); + + String uploadAlertLink(); + + String uploadAlertProgress(); + + String uploadAlertPercent(); + + String uploadAlertClose(); + } + + public interface Resources extends ClientBundle { + @Source("Pithos.css") + Style pithosCss(); + + @Source("gr/grnet/pithos/resources/close-popup.png") + ImageResource closePopup(); + } + + public static Resources resources = GWT.create(Resources.class); /** * Instantiate an application-level image bundle. This object will provide @@ -133,30 +173,28 @@ public class Pithos implements EntryPoint, ResizeHandler { return account; } - public void updateFolder(Folder f, boolean showfiles, Command callback) { - folderTreeView.updateFolder(f, showfiles, callback); + public void updateFolder(Folder f, boolean showfiles, Command callback, final boolean openParent) { + folderTreeView.updateFolder(f, showfiles, callback, openParent); } public void updateGroupNode(Group group) { groupTreeView.updateGroupNode(group); } - public void updateSharedFolder(Folder f, boolean showfiles) { - mysharedTreeView.updateFolder(f, showfiles); + public void updateMySharedRoot() { + mysharedTreeView.updateRoot(); + } + + public void updateSharedFolder(Folder f, boolean showfiles, Command callback) { + mysharedTreeView.updateFolder(f, showfiles, callback); } - public void updateOtherSharedFolder(Folder f, boolean showfiles) { - otherSharedTreeView.updateFolder(f, showfiles); + public void updateSharedFolder(Folder f, boolean showfiles) { + updateSharedFolder(f, showfiles, null); } - public List getAllTags() { - List tagList = new ArrayList(); - for (Folder f : account.getContainers()) { - for (String t : f.getTags()) { - tagList.add(new Tag(t)); - } - } - return tagList; + public void updateOtherSharedFolder(Folder f, boolean showfiles, Command callback) { + otherSharedTreeView.updateFolder(f, showfiles, callback); } public MysharedTreeView getMySharedTreeView() { @@ -177,6 +215,8 @@ public class Pithos implements EntryPoint, ResizeHandler { ImageResource tools(); } + private Throwable error; + /** * The Application Clipboard implementation; */ @@ -190,12 +230,12 @@ public class Pithos implements EntryPoint, ResizeHandler { /** * The panel that contains the various system messages. */ - private MessagePanel messagePanel = new MessagePanel(Pithos.images); + private MessagePanel messagePanel = new MessagePanel(this, Pithos.images); /** * The bottom panel that contains the status bar. */ - private StatusPanel statusPanel = null; + StatusPanel statusPanel = null; /** * The file list widget. @@ -243,9 +283,9 @@ public class Pithos implements EntryPoint, ResizeHandler { OtherSharedTreeView otherSharedTreeView = null; GroupTreeViewModel groupTreeViewModel; - private GroupTreeView groupTreeView; + GroupTreeView groupTreeView; - private TreeView selectedTree; + TreeView selectedTree; protected AccountResource account; Folder trash; @@ -254,17 +294,17 @@ public class Pithos implements EntryPoint, ResizeHandler { @SuppressWarnings("rawtypes") List selectionModels = new ArrayList(); - Button upload; - - private HTML usedBytes; - - private HTML totalBytes; - - private HTML usedPercent; + public Button upload; private HTML numOfFiles; - private Image toolsButton; + private Toolbar toolbar; + + private FileUploadDialog fileUploadDialog = new FileUploadDialog(this); + + UploadAlert uploadAlert; + + Date lastModified; @Override public void onModuleLoad() { @@ -273,6 +313,8 @@ public class Pithos implements EntryPoint, ResizeHandler { } private void initialize() { + lastModified = new Date(); //Initialize if-modified-since value with now. + resources.pithosCss().ensureInjected(); boolean bareContent = Window.Location.getParameter("noframe") != null; String contentWidth = bareContent ? "100%" : "75%"; @@ -289,46 +331,33 @@ public class Pithos implements EntryPoint, ResizeHandler { outer.setCellHorizontalAlignment(topPanel, HasHorizontalAlignment.ALIGN_CENTER); } + messagePanel.setVisible(false); + outer.add(messagePanel); + outer.setCellHorizontalAlignment(messagePanel, HasHorizontalAlignment.ALIGN_CENTER); + outer.setCellVerticalAlignment(messagePanel, HasVerticalAlignment.ALIGN_MIDDLE); + HorizontalPanel header = new HorizontalPanel(); header.addStyleName("pithos-header"); header.setWidth(contentWidth); if (bareContent) header.addStyleName("pithos-header-noframe"); - upload = new Button("Upload File", new ClickHandler() { + upload = new Button("Upload", new ClickHandler() { @Override - public void onClick(@SuppressWarnings("unused") ClickEvent event) { - new UploadFileCommand(Pithos.this, null, getSelection()).execute(); + public void onClick(ClickEvent event) { + if (getSelection() != null) + new UploadFileCommand(Pithos.this, null, getSelection()).execute(); } }); upload.addStyleName("pithos-uploadButton"); header.add(upload); header.setCellHorizontalAlignment(upload, HasHorizontalAlignment.ALIGN_LEFT); header.setCellVerticalAlignment(upload, HasVerticalAlignment.ALIGN_MIDDLE); -// header.setCellWidth(upload, "146px"); - messagePanel.setVisible(false); - header.add(messagePanel); - header.setCellHorizontalAlignment(messagePanel, HasHorizontalAlignment.ALIGN_CENTER); - header.setCellVerticalAlignment(messagePanel, HasVerticalAlignment.ALIGN_MIDDLE); + toolbar = new Toolbar(this); + header.add(toolbar); + header.setCellHorizontalAlignment(toolbar, HasHorizontalAlignment.ALIGN_CENTER); + header.setCellVerticalAlignment(toolbar, HasVerticalAlignment.ALIGN_MIDDLE); - toolsButton = new Image(images.tools()); - toolsButton.addStyleName("pithos-toolsButton"); - toolsButton.addClickHandler(new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - ToolsMenu menu = new ToolsMenu(Pithos.this, images, getSelectedTree(), getSelectedTree().getSelection(), getFileList().getSelectedFiles()); - if (!menu.isEmpty()) { - menu.setPopupPosition(event.getClientX(), event.getClientY()); - menu.show(); - } - } - }); - header.add(toolsButton); - header.setCellHorizontalAlignment(toolsButton, HasHorizontalAlignment.ALIGN_CENTER); - header.setCellVerticalAlignment(toolsButton, HasVerticalAlignment.ALIGN_MIDDLE); - header.setCellWidth(toolsButton, "40px"); - HorizontalPanel folderStatistics = new HorizontalPanel(); folderStatistics.addStyleName("pithos-folderStatistics"); numOfFiles = new HTML(); @@ -343,20 +372,33 @@ public class Pithos implements EntryPoint, ResizeHandler { header.setCellWidth(folderStatistics, "40px"); outer.add(header); outer.setCellHorizontalAlignment(header, HasHorizontalAlignment.ALIGN_CENTER); - // Inner contains the various lists.nner + // Inner contains the various lists inner.sinkEvents(Event.ONCONTEXTMENU); inner.setWidth("100%"); folderTreeSelectionModel = new SingleSelectionModel(); folderTreeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @Override - public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) { + public void onSelectionChange(SelectionChangeEvent event) { if (folderTreeSelectionModel.getSelectedObject() != null) { deselectOthers(folderTreeView, folderTreeSelectionModel); applyPermissions(folderTreeSelectionModel.getSelectedObject()); Folder f = folderTreeSelectionModel.getSelectedObject(); - showFiles(f); + updateFolder(f, true, new Command() { + + @Override + public void execute() { + updateStatistics(); + } + }, true); + showRelevantToolbarButtons(); } + else { + if (getSelectedTree().equals(folderTreeView)) + setSelectedTree(null); + if (getSelectedTree() == null) + showRelevantToolbarButtons(); + } } }); selectionModels.add(folderTreeSelectionModel); @@ -365,43 +407,19 @@ public class Pithos implements EntryPoint, ResizeHandler { folderTreeView = new FolderTreeView(folderTreeViewModel); treeViews.add(folderTreeView); - fileList = new FileList(this, images, folderTreeView); + fileList = new FileList(this, images); inner.add(fileList); - groupTreeViewModel = new GroupTreeViewModel(this); - groupTreeView = new GroupTreeView(groupTreeViewModel); - treeViews.add(groupTreeView); - trees = new VerticalPanel(); trees.setWidth("100%"); - - HorizontalPanel treeHeader = new HorizontalPanel(); - treeHeader.addStyleName("pithos-treeHeader"); - treeHeader.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); - treeHeader.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); - HorizontalPanel statistics = new HorizontalPanel(); - statistics.addStyleName("pithos-statistics"); - statistics.add(new HTML("Used: ")); - usedBytes = new HTML(); - statistics.add(usedBytes); - statistics.add(new HTML(" of ")); - totalBytes = new HTML(); - statistics.add(totalBytes); - statistics.add(new HTML(" (")); - usedPercent = new HTML(); - statistics.add(usedPercent); - statistics.add(new HTML(")")); - treeHeader.add(statistics); - treeHeader.setCellHorizontalAlignment(statistics, HasHorizontalAlignment.ALIGN_LEFT); - trees.add(treeHeader); - - trees.add(folderTreeView); - trees.add(groupTreeView); // Add the left and right panels to the split panel. splitPanel.setLeftWidget(trees); - splitPanel.setRightWidget(inner); - splitPanel.setSplitPosition("35%"); + FlowPanel right = new FlowPanel(); + right.getElement().setId("rightPanel"); + right.add(inner); + splitPanel.setRightWidget(right); + splitPanel.setSplitPosition("219px"); splitPanel.setSize("100%", "100%"); splitPanel.addStyleName("pithos-splitPanel"); splitPanel.setWidth(contentWidth); @@ -428,14 +446,17 @@ public class Pithos implements EntryPoint, ResizeHandler { // 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. - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - - @Override - public void execute() { + Scheduler.get().scheduleIncremental(new RepeatingCommand() { + + @Override + public boolean execute() { + if (!isCloudbarReady()) + return true; onWindowResized(Window.getClientHeight()); - } - }); - + return false; + } + }); + Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { @@ -453,6 +474,7 @@ public class Pithos implements EntryPoint, ResizeHandler { trash = f; break; } + trees.add(folderTreeView); folderTreeViewModel.initialize(account, new Command() { @Override @@ -460,123 +482,163 @@ public class Pithos implements EntryPoint, ResizeHandler { createMySharedTree(); } }); - groupTreeViewModel.initialize(); - showStatistics(); + + HorizontalPanel separator = new HorizontalPanel(); + separator.addStyleName("pithos-statisticsSeparator"); + separator.add(new HTML("")); + trees.add(separator); + + groupTreeViewModel = new GroupTreeViewModel(Pithos.this); + groupTreeView = new GroupTreeView(groupTreeViewModel); + treeViews.add(groupTreeView); + trees.add(groupTreeView); + folderTreeView.showStatistics(account); } } }); } }); - -// Scheduler.get().scheduleDeferred(new Command() { -// -// @Override -// public void execute() { -// displayError("lalala"); -// -// } -// }); + } + + public void scheduleResfresh() { + Scheduler.get().scheduleFixedDelay(new RepeatingCommand() { + + @Override + public boolean execute() { + final Folder f = getSelection(); + if (f == null) + return true; + + HeadRequest head = new HeadRequest(Folder.class, getApiPath(), getUsername(), "/" + f.getContainer()) { + + @Override + public void onSuccess(Folder _result) { + lastModified = new Date(); + if (getSelectedTree().equals(folderTreeView)) + updateFolder(f, true, new Command() { + + @Override + public void execute() { + scheduleResfresh(); + } + + }, false); + else if (getSelectedTree().equals(mysharedTreeView)) + updateSharedFolder(f, true, new Command() { + + @Override + public void execute() { + scheduleResfresh(); + } + }); + } + + @Override + public void onError(Throwable t) { + if (t instanceof RestException && ((RestException) t).getHttpStatusCode() == HttpStatus.SC_NOT_MODIFIED) + scheduleResfresh(); + else if (retries >= MAX_RETRIES) { + GWT.log("Error heading folder", t); + setError(t); + if (t instanceof RestException) + displayError("Error heading folder: " + ((RestException) t).getHttpStatusText()); + else + displayError("System error heading folder: " + t.getMessage()); + } + else {//retry + GWT.log("Retry " + retries); + Scheduler.get().scheduleDeferred(this); + } + } + + @Override + protected void onUnauthorized(Response response) { + if (retries >= MAX_RETRIES) + sessionExpired(); + else //retry + Scheduler.get().scheduleDeferred(this); + } + }; + head.setHeader("X-Auth-Token", getToken()); + head.setHeader("If-Modified-Since", DateTimeFormat.getFormat("EEE, dd MMM yyyy HH:mm:ss").format(lastModified, TimeZone.createTimeZone(0)) + " GMT"); + Scheduler.get().scheduleDeferred(head); + + return false; + } + }, 3000); } public void applyPermissions(Folder f) { if (f != null) { - if (f.isInTrash()) + if (f.isInTrash()) { upload.setEnabled(false); + disableUploadArea(); + } else { Boolean[] perms = f.getPermissions().get(username); if (f.getOwner().equals(username) || (perms != null && perms[1] != null && perms[1])) { upload.setEnabled(true); + enableUploadArea(); } - else + else { upload.setEnabled(false); + disableUploadArea(); + } } } - else + else { upload.setEnabled(false); + disableUploadArea(); + } } @SuppressWarnings({ "rawtypes", "unchecked" }) public void deselectOthers(TreeView _selectedTree, SingleSelectionModel model) { selectedTree = _selectedTree; - for (Composite c : treeViews) - if (c.equals(selectedTree)) - c.addStyleName("cellTreeWidget-selectedTree"); - else - c.removeStyleName("cellTreeWidget-selectedTree"); - for (SingleSelectionModel s : selectionModels) - if (!s.equals(model)) + if (!s.equals(model) && s.getSelectedObject() != null) s.setSelected(s.getSelectedObject(), false); } - public void showFiles(Folder f) { + public void showFiles(final Folder f) { Set files = f.getFiles(); showFiles(files); } public void showFiles(Set files) { - //Iterator iter = files.iterator(); - //fetchFile(iter, files); fileList.setFiles(new ArrayList(files)); } - protected void fetchFile(final Iterator iter, final Set files) { - if (iter.hasNext()) { - File file = iter.next(); - String path = file.getUri() + "?format=json"; - GetRequest getFile = new GetRequest(File.class, getApiPath(), username, path, file) { - @Override - public void onSuccess(@SuppressWarnings("unused") File _result) { - fetchFile(iter, files); - } - - @Override - public void onError(Throwable t) { - GWT.log("Error getting file", t); - if (t instanceof RestException) - displayError("Error getting file: " + ((RestException) t).getHttpStatusText()); - else - displayError("System error fetching file: " + t.getMessage()); - } - - @Override - protected void onUnauthorized(Response response) { - sessionExpired(); - } - }; - getFile.setHeader("X-Auth-Token", "0000"); - Scheduler.get().scheduleDeferred(getFile); - } - else - fileList.setFiles(new ArrayList(files)); - } - /** * Parse and store the user credentials to the appropriate fields. */ private boolean parseUserCredentials() { - username = Window.Location.getParameter("user"); - token = Window.Location.getParameter("token"); Configuration conf = (Configuration) GWT.create(Configuration.class); - if (username == null || username.length() == 0 || token == null || token.length() == 0) { - String cookie = conf.authCookie(); - String auth = Cookies.getCookie(cookie); - if (auth == null) { - authenticateUser(); - return false; - } - String[] authSplit = auth.split("\\" + conf.cookieSeparator(), 2); - if (authSplit.length != 2) { - authenticateUser(); - return false; - } - username = authSplit[0]; - token = authSplit[1]; - return true; + Dictionary otherProperties = Dictionary.getDictionary("otherProperties"); + String cookie = otherProperties.get("authCookie"); + String auth = Cookies.getCookie(cookie); + if (auth == null) { + authenticateUser(); + return false; } - - Cookies.setCookie(conf.authCookie(), username + conf.cookieSeparator() + token, null, "", "/", false); + if (auth.startsWith("\"")) + auth = auth.substring(1); + if (auth.endsWith("\"")) + auth = auth.substring(0, auth.length() - 1); + String[] authSplit = auth.split("\\" + conf.cookieSeparator(), 2); + if (authSplit.length != 2) { + authenticateUser(); + return false; + } + username = authSplit[0]; + token = authSplit[1]; + + String gotoUrl = Window.Location.getParameter("goto"); + if (gotoUrl != null && gotoUrl.length() > 0) { + Window.Location.assign(gotoUrl); + return false; + } return true; } @@ -584,11 +646,11 @@ public class Pithos implements EntryPoint, ResizeHandler { * Redirect the user to the login page for authentication. */ protected void authenticateUser() { - Configuration conf = (Configuration) GWT.create(Configuration.class); - Window.Location.assign(conf.loginUrl() + "?next=" + Window.Location.getHref()); + Dictionary otherProperties = Dictionary.getDictionary("otherProperties"); + Window.Location.assign(otherProperties.get("loginUrl") + Window.Location.getHref()); } - protected void fetchAccount(final Command callback) { + public void fetchAccount(final Command callback) { String path = "?format=json"; GetRequest getAccount = new GetRequest(AccountResource.class, getApiPath(), username, path) { @@ -602,6 +664,7 @@ public class Pithos implements EntryPoint, ResizeHandler { @Override public void onError(Throwable t) { GWT.log("Error getting account", t); + setError(t); if (t instanceof RestException) displayError("Error getting account: " + ((RestException) t).getHttpStatusText()); else @@ -621,13 +684,14 @@ public class Pithos implements EntryPoint, ResizeHandler { HeadRequest headAccount = new HeadRequest(AccountResource.class, getApiPath(), username, "", account) { @Override - public void onSuccess(@SuppressWarnings("unused") AccountResource _result) { - showStatistics(); + public void onSuccess(AccountResource _result) { + folderTreeView.showStatistics(account); } @Override public void onError(Throwable t) { GWT.log("Error getting account", t); + setError(t); if (t instanceof RestException) displayError("Error getting account: " + ((RestException) t).getHttpStatusText()); else @@ -643,18 +707,11 @@ public class Pithos implements EntryPoint, ResizeHandler { Scheduler.get().scheduleDeferred(headAccount); } - protected void showStatistics() { - usedBytes.setHTML(String.valueOf(account.getFileSizeAsString())); - totalBytes.setHTML(String.valueOf(account.getQuotaAsString())); - NumberFormat nf = NumberFormat.getPercentFormat(); - usedPercent.setHTML(nf.format(account.getUsedPercentage())); - } - protected void createHomeContainer(final AccountResource _account, final Command callback) { String path = "/" + Pithos.HOME_CONTAINER; PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) { @Override - public void onSuccess(@SuppressWarnings("unused") Resource result) { + public void onSuccess(Resource result) { if (!_account.hasTrashContainer()) createTrashContainer(callback); else @@ -664,6 +721,7 @@ public class Pithos implements EntryPoint, ResizeHandler { @Override public void onError(Throwable t) { GWT.log("Error creating pithos", t); + setError(t); if (t instanceof RestException) displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText()); else @@ -683,13 +741,14 @@ public class Pithos implements EntryPoint, ResizeHandler { String path = "/" + Pithos.TRASH_CONTAINER; PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) { @Override - public void onSuccess(@SuppressWarnings("unused") Resource result) { + public void onSuccess(Resource result) { fetchAccount(callback); } @Override public void onError(Throwable t) { GWT.log("Error creating pithos", t); + setError(t); if (t instanceof RestException) displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText()); else @@ -723,13 +782,19 @@ public class Pithos implements EntryPoint, ResizeHandler { protected void onWindowResized(int height) { // Adjust the split panel to take up the available room in the window. - int newHeight = height - splitPanel.getAbsoluteTop(); + int newHeight = height - splitPanel.getAbsoluteTop() - 153; if (newHeight < 1) newHeight = 1; splitPanel.setHeight("" + newHeight); inner.setHeight("" + newHeight); } - + + native boolean isCloudbarReady()/*-{ + if ($wnd.$("div.servicesbar") && $wnd.$("div.servicesbar").height() > 0) + return true; + return false; + }-*/; + @Override public void onResize(ResizeEvent event) { int height = event.getHeight(); @@ -743,6 +808,7 @@ public class Pithos implements EntryPoint, ResizeHandler { */ public void displayError(String msg) { messagePanel.displayError(msg); + onWindowResized(Window.getClientHeight()); } /** @@ -752,6 +818,7 @@ public class Pithos implements EntryPoint, ResizeHandler { */ public void displayWarning(String msg) { messagePanel.displayWarning(msg); + onWindowResized(Window.getClientHeight()); } /** @@ -761,6 +828,7 @@ public class Pithos implements EntryPoint, ResizeHandler { */ public void displayInformation(String msg) { messagePanel.displayInformation(msg); + onWindowResized(Window.getClientHeight()); } /** @@ -799,12 +867,14 @@ public class Pithos implements EntryPoint, ResizeHandler { } public static native void preventIESelection() /*-{ - $doc.body.onselectstart = function () { return false; }; + $doc.body.onselectstart = function() { + return false; + }; }-*/; public static native void enableIESelection() /*-{ if ($doc.body.onselectstart != null) - $doc.body.onselectstart = null; + $doc.body.onselectstart = null; }-*/; /** @@ -829,26 +899,27 @@ public class Pithos implements EntryPoint, ResizeHandler { History.newItem(key); } - public void deleteFolder(final Folder folder) { + public void deleteFolder(final Folder folder, final Command callback) { String path = getApiPath() + folder.getOwner() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(folder.getPrefix()) + "&t=" + System.currentTimeMillis(); RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path); builder.setHeader("X-Auth-Token", getToken()); try { builder.sendRequest("", new RequestCallback() { @Override - public void onResponseReceived(@SuppressWarnings("unused") Request request, Response response) { + public void onResponseReceived(Request request, Response response) { if (response.getStatusCode() == Response.SC_OK) { JSONValue json = JSONParser.parseStrict(response.getText()); JSONArray array = json.isArray(); int i = 0; if (array != null) { - deleteObject(folder, i, array); + deleteObject(folder, i, array, callback); } } } @Override - public void onError(@SuppressWarnings("unused") Request request, Throwable exception) { + public void onError(Request request, Throwable exception) { + setError(exception); displayError("System error unable to delete folder: " + exception.getMessage()); } }); @@ -857,22 +928,24 @@ public class Pithos implements EntryPoint, ResizeHandler { } } - void deleteObject(final Folder folder, final int i, final JSONArray array) { + void deleteObject(final Folder folder, final int i, final JSONArray array, final Command callback) { if (i < array.size()) { JSONObject o = array.get(i).isObject(); if (o != null && !o.containsKey("subdir")) { JSONString name = o.get("name").isString(); String path = "/" + folder.getContainer() + "/" + name.stringValue(); - DeleteRequest delete = new DeleteRequest(getApiPath(), folder.getOwner(), path) { + DeleteRequest delete = new DeleteRequest(getApiPath(), folder.getOwner(), URL.encode(path)) { @Override - public void onSuccess(@SuppressWarnings("unused") Resource result) { - deleteObject(folder, i + 1, array); + public void onSuccess(Resource result) { + deleteObject(folder, i + 1, array, callback); } @Override public void onError(Throwable t) { GWT.log("", t); + setError(t); displayError("System error unable to delete folder: " + t.getMessage()); + deleteObject(folder, i + 1, array, callback); } @Override @@ -886,13 +959,13 @@ public class Pithos implements EntryPoint, ResizeHandler { else if (o != null) { String subdir = o.get("subdir").isString().stringValue(); subdir = subdir.substring(0, subdir.length() - 1); - String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(subdir) + "&t=" + System.currentTimeMillis(); + String path = getApiPath() + folder.getOwner() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(subdir) + "&t=" + System.currentTimeMillis(); RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path); builder.setHeader("X-Auth-Token", getToken()); try { builder.sendRequest("", new RequestCallback() { @Override - public void onResponseReceived(@SuppressWarnings("unused") Request request, Response response) { + public void onResponseReceived(Request request, Response response) { if (response.getStatusCode() == Response.SC_OK) { JSONValue json = JSONParser.parseStrict(response.getText()); JSONArray array2 = json.isArray(); @@ -902,12 +975,13 @@ public class Pithos implements EntryPoint, ResizeHandler { array.set(l++, array2.get(j)); } } - deleteObject(folder, i + 1, array); + deleteObject(folder, i + 1, array, callback); } } @Override - public void onError(@SuppressWarnings("unused") Request request, Throwable exception) { + public void onError(Request request, Throwable exception) { + setError(exception); displayError("System error unable to delete folder: " + exception.getMessage()); } }); @@ -917,22 +991,38 @@ public class Pithos implements EntryPoint, ResizeHandler { } } else { + if (folder.isContainer()) { + updateFolder(folder, true, new Command() { + + @Override + public void execute() { + updateStatistics(); + if (callback != null) + callback.execute(); + } + }, false); + return; + } String path = folder.getUri(); - DeleteRequest deleteFolder = new DeleteRequest(getApiPath(), getUsername(), path) { + DeleteRequest deleteFolder = new DeleteRequest(getApiPath(), getUsername(), URL.encode(path)) { @Override - public void onSuccess(@SuppressWarnings("unused") Resource result) { + public void onSuccess(Resource result) { updateFolder(folder.getParent(), true, new Command() { @Override public void execute() { + folderTreeSelectionModel.setSelected(folder.getParent(), true); updateStatistics(); + if (callback != null) + callback.execute(); } - }); + }, true); } @Override public void onError(Throwable t) { GWT.log("", t); + setError(t); if (t instanceof RestException) { if (((RestException) t).getHttpStatusCode() != Response.SC_NOT_FOUND) displayError("Unable to delete folder: "+((RestException) t).getHttpStatusText()); @@ -963,13 +1053,14 @@ public class Pithos implements EntryPoint, ResizeHandler { String path = targetUri + "/" + file.getName(); PutRequest copyFile = new PutRequest(getApiPath(), targetUsername, path) { @Override - public void onSuccess(@SuppressWarnings("unused") Resource result) { + public void onSuccess(Resource result) { copyFiles(iter, targetUsername, targetUri, callback); } @Override public void onError(Throwable t) { GWT.log("", t); + setError(t); if (t instanceof RestException) { displayError("Unable to copy file: " + ((RestException) t).getHttpStatusText()); } @@ -983,9 +1074,10 @@ public class Pithos implements EntryPoint, ResizeHandler { } }; copyFile.setHeader("X-Auth-Token", getToken()); - copyFile.setHeader("X-Copy-From", file.getUri()); + copyFile.setHeader("X-Copy-From", URL.encodePathSegment(file.getUri())); if (!file.getOwner().equals(targetUsername)) - copyFile.setHeader("X-Source-Account", file.getOwner()); + copyFile.setHeader("X-Source-Account", URL.encodePathSegment(file.getOwner())); + copyFile.setHeader("Content-Type", file.getContentType()); Scheduler.get().scheduleDeferred(copyFile); } else if (callback != null) { @@ -1013,7 +1105,7 @@ public class Pithos implements EntryPoint, ResizeHandler { String path = targetUri + "/" + f.getName(); PutRequest createFolder = new PutRequest(getApiPath(), targetUsername, path) { @Override - public void onSuccess(@SuppressWarnings("unused") Resource result) { + public void onSuccess(Resource result) { GetRequest getFolder = new GetRequest(Folder.class, getApiPath(), f.getOwner(), "/" + f.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(f.getPrefix()), f) { @Override @@ -1031,6 +1123,7 @@ public class Pithos implements EntryPoint, ResizeHandler { @Override public void onError(Throwable t) { GWT.log("", t); + setError(t); if (t instanceof RestException) { displayError("Unable to get folder: " + ((RestException) t).getHttpStatusText()); } @@ -1050,7 +1143,8 @@ public class Pithos implements EntryPoint, ResizeHandler { @Override public void onError(Throwable t) { GWT.log("", t); - if (t instanceof RestException) { + setError(t); + if (t instanceof RestException) { displayError("Unable to create folder: " + ((RestException) t).getHttpStatusText()); } else @@ -1078,17 +1172,18 @@ public class Pithos implements EntryPoint, ResizeHandler { } public void updateTrash(boolean showFiles, Command callback) { - updateFolder(trash, showFiles, callback); + updateFolder(trash, showFiles, callback, true); } public void updateGroupsNode() { groupTreeView.updateGroupNode(null); } - public void addGroup(String groupname) { + public Group addGroup(String groupname) { Group newGroup = new Group(groupname); account.addGroup(newGroup); groupTreeView.updateGroupNode(null); + return newGroup; } public void removeGroup(Group group) { @@ -1100,8 +1195,14 @@ public class Pithos implements EntryPoint, ResizeHandler { return selectedTree; } + public void setSelectedTree(TreeView selected) { + selectedTree = selected; + } + public Folder getSelection() { - return selectedTree.getSelection(); + if (selectedTree != null) + return selectedTree.getSelection(); + return null; } public void showFolderStatistics(int folderFileCount) { @@ -1117,19 +1218,27 @@ public class Pithos implements EntryPoint, ResizeHandler { } public void updateRootFolder(Command callback) { - updateFolder(account.getPithos(), false, callback); + updateFolder(account.getPithos(), false, callback, true); } void createMySharedTree() { mysharedTreeSelectionModel = new SingleSelectionModel(); mysharedTreeSelectionModel.addSelectionChangeHandler(new Handler() { @Override - public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) { + public void onSelectionChange(SelectionChangeEvent event) { if (mysharedTreeSelectionModel.getSelectedObject() != null) { deselectOthers(mysharedTreeView, mysharedTreeSelectionModel); upload.setEnabled(false); + disableUploadArea(); updateSharedFolder(mysharedTreeSelectionModel.getSelectedObject(), true); + showRelevantToolbarButtons(); } + else { + if (getSelectedTree().equals(mysharedTreeView)) + setSelectedTree(null); + if (getSelectedTree() == null) + showRelevantToolbarButtons(); + } } }); selectionModels.add(mysharedTreeSelectionModel); @@ -1150,13 +1259,19 @@ public class Pithos implements EntryPoint, ResizeHandler { otherSharedTreeSelectionModel = new SingleSelectionModel(); otherSharedTreeSelectionModel.addSelectionChangeHandler(new Handler() { @Override - public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) { + public void onSelectionChange(SelectionChangeEvent event) { if (otherSharedTreeSelectionModel.getSelectedObject() != null) { deselectOthers(otherSharedTreeView, otherSharedTreeSelectionModel); - otherSharedTreeView.addStyleName("cellTreeWidget-selectedTree"); applyPermissions(otherSharedTreeSelectionModel.getSelectedObject()); - updateOtherSharedFolder(otherSharedTreeSelectionModel.getSelectedObject(), true); + updateOtherSharedFolder(otherSharedTreeSelectionModel.getSelectedObject(), true, null); + showRelevantToolbarButtons(); } + else { + if (getSelectedTree().equals(otherSharedTreeView)) + setSelectedTree(null); + if (getSelectedTree() == null) + showRelevantToolbarButtons(); + } } }); selectionModels.add(otherSharedTreeSelectionModel); @@ -1166,19 +1281,241 @@ public class Pithos implements EntryPoint, ResizeHandler { @Override public void execute() { otherSharedTreeView = new OtherSharedTreeView(otherSharedTreeViewModel); - trees.insert(otherSharedTreeView, 3); + trees.insert(otherSharedTreeView, 1); treeViews.add(otherSharedTreeView); + scheduleResfresh(); } }); } - public void logoff() { - Configuration conf = (Configuration) GWT.create(Configuration.class); - Cookies.removeCookie(conf.authCookie()); - Cookies.removeCookie(conf.authTokenCookie(), "/"); - for (String s: Cookies.getCookieNames()) - if (s.startsWith(conf.shibSessionCookiePrefix())) - Cookies.removeCookie(s, "/"); - Window.Location.assign(Window.Location.getPath()); + public native void log1(String message)/*-{ + $wnd.console.log(message); + }-*/; + + public String getErrorData() { + if (error != null) + return error.toString(); + return ""; + } + + public void setError(Throwable t) { + error = t; + } + + public void showRelevantToolbarButtons() { + toolbar.showRelevantButtons(); + } + + public FileUploadDialog getFileUploadDialog() { + if (fileUploadDialog == null) + fileUploadDialog = new FileUploadDialog(this); + return fileUploadDialog; + } + + public void hideUploadIndicator() { + upload.removeStyleName("pithos-uploadButton-loading"); + upload.setTitle(""); + } + + public void showUploadIndicator() { + upload.addStyleName("pithos-uploadButton-loading"); + upload.setTitle("Upload in progress. Click for details."); + } + + public void scheduleFolderHeadCommand(final Folder folder, final Command callback) { + if (folder == null) { + if (callback != null) + callback.execute(); + } + else { + HeadRequest headFolder = new HeadRequest(Folder.class, getApiPath(), folder.getOwner(), folder.getUri(), folder) { + + @Override + public void onSuccess(Folder _result) { + if (callback != null) + callback.execute(); + } + + @Override + public void onError(Throwable t) { + if (t instanceof RestException) { + if (((RestException) t).getHttpStatusCode() == Response.SC_NOT_FOUND) { + final String path = folder.getUri(); + PutRequest newFolder = new PutRequest(getApiPath(), folder.getOwner(), path) { + @Override + public void onSuccess(Resource _result) { + scheduleFolderHeadCommand(folder, callback); + } + + @Override + public void onError(Throwable _t) { + GWT.log("", _t); + setError(_t); + if(_t instanceof RestException){ + displayError("Unable to create folder: " + ((RestException) _t).getHttpStatusText()); + } + else + displayError("System error creating folder: " + _t.getMessage()); + } + + @Override + protected void onUnauthorized(Response response) { + sessionExpired(); + } + }; + newFolder.setHeader("X-Auth-Token", getToken()); + newFolder.setHeader("Content-Type", "application/folder"); + newFolder.setHeader("Accept", "*/*"); + newFolder.setHeader("Content-Length", "0"); + Scheduler.get().scheduleDeferred(newFolder); + } + else + displayError("Error heading folder: " + ((RestException) t).getHttpStatusText()); + } + else + displayError("System error heading folder: " + t.getMessage()); + + GWT.log("Error heading folder", t); + setError(t); + } + + @Override + protected void onUnauthorized(Response response) { + sessionExpired(); + } + }; + headFolder.setHeader("X-Auth-Token", getToken()); + Scheduler.get().scheduleDeferred(headFolder); + } + } + + public void scheduleFileHeadCommand(File f, final Command callback) { + HeadRequest headFile = new HeadRequest(File.class, getApiPath(), f.getOwner(), f.getUri(), f) { + + @Override + public void onSuccess(File _result) { + if (callback != null) + callback.execute(); + } + + @Override + public void onError(Throwable t) { + GWT.log("Error heading file", t); + setError(t); + if (t instanceof RestException) + displayError("Error heading file: " + ((RestException) t).getHttpStatusText()); + else + displayError("System error heading file: " + t.getMessage()); + } + + @Override + protected void onUnauthorized(Response response) { + sessionExpired(); + } + }; + headFile.setHeader("X-Auth-Token", getToken()); + Scheduler.get().scheduleDeferred(headFile); + } + + public boolean isMySharedSelected() { + return getSelectedTree().equals(getMySharedTreeView()); + } + + private Folder getUploadFolder() { + if (folderTreeView.equals(getSelectedTree()) || otherSharedTreeView.equals(getSelectedTree())) { + return getSelection(); + } + return null; + } + + private void updateUploadFolder() { + updateUploadFolder(null); + } + + private void updateUploadFolder(final JsArrayString urls) { + if (folderTreeView.equals(getSelectedTree()) || otherSharedTreeView.equals(getSelectedTree())) { + Folder f = getSelection(); + if (getSelectedTree().equals(getFolderTreeView())) + updateFolder(f, true, new Command() { + + @Override + public void execute() { + updateStatistics(); + if (urls != null) + selectUploadedFiles(urls); + } + }, false); + else + updateOtherSharedFolder(f, true, null); + } + } + + public native void disableUploadArea() /*-{ + var uploader = $wnd.$("#uploader").pluploadQueue(); + var dropElm = $wnd.document.getElementById('rightPanel'); + $wnd.plupload.removeAllEvents(dropElm, uploader.id); + }-*/; + + public native void enableUploadArea() /*-{ + var uploader = $wnd.$("#uploader").pluploadQueue(); + var dropElm = $wnd.document.getElementById('rightPanel'); + $wnd.plupload.removeAllEvents(dropElm, uploader.id); + if (uploader.runtime == 'html5') { + uploader.settings.drop_element = 'rightPanel'; + uploader.trigger('PostInit'); + } + }-*/; + + public void showUploadAlert(int nOfFiles) { + if (uploadAlert == null) + uploadAlert = new UploadAlert(this, nOfFiles); + if (!uploadAlert.isShowing()) + uploadAlert.setPopupPositionAndShow(new PopupPanel.PositionCallback() { + + @Override + public void setPosition(int offsetWidth, int offsetHeight) { + uploadAlert.setPopupPosition((Window.getClientWidth() - offsetWidth)/2, statusPanel.getAbsoluteTop() - offsetHeight); + } + }); + uploadAlert.setNumOfFiles(nOfFiles); + } + + public void hideUploadAlert() { + if (uploadAlert != null && uploadAlert.isShowing()) + uploadAlert.hide(); + } + + public void selectUploadedFiles(JsArrayString urls) { + List selectedUrls = new ArrayList(); + for (int i=0; i