dnd fix
[pithos] / src / gr / ebs / gss / client / FileList.java
1 /*
2  * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
3  *
4  * This file is part of GSS.
5  *
6  * GSS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 package gr.ebs.gss.client;
20 import gr.ebs.gss.client.commands.GetUserCommand;
21 import gr.ebs.gss.client.dnd.DnDSimpleFocusPanel;
22 import gr.ebs.gss.client.dnd.DnDTreeItem;
23 import gr.ebs.gss.client.rest.GetCommand;
24 import gr.ebs.gss.client.rest.MultipleHeadCommand;
25 import gr.ebs.gss.client.rest.RestCommand;
26 import gr.ebs.gss.client.rest.RestException;
27 import gr.ebs.gss.client.rest.resource.FileResource;
28 import gr.ebs.gss.client.rest.resource.FolderResource;
29 import gr.ebs.gss.client.rest.resource.OtherUserResource;
30 import gr.ebs.gss.client.rest.resource.SharedResource;
31 import gr.ebs.gss.client.rest.resource.TrashResource;
32 import gr.ebs.gss.client.rest.resource.UserResource;
33
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.List;
38
39 import com.google.gwt.core.client.GWT;
40 import com.google.gwt.dom.client.NativeEvent;
41 import com.google.gwt.event.dom.client.ClickEvent;
42 import com.google.gwt.event.dom.client.ClickHandler;
43 import com.google.gwt.http.client.URL;
44 import com.google.gwt.i18n.client.DateTimeFormat;
45 import com.google.gwt.resources.client.ClientBundle;
46 import com.google.gwt.resources.client.ImageResource;
47 import com.google.gwt.resources.client.ClientBundle.Source;
48 import com.google.gwt.user.client.DOM;
49 import com.google.gwt.user.client.DeferredCommand;
50 import com.google.gwt.user.client.Event;
51 import com.google.gwt.user.client.IncrementalCommand;
52 import com.google.gwt.user.client.Window;
53 import com.google.gwt.user.client.ui.AbstractImagePrototype;
54 import com.google.gwt.user.client.ui.Composite;
55 import com.google.gwt.user.client.ui.Grid;
56 import com.google.gwt.user.client.ui.HTML;
57 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
58 import com.google.gwt.user.client.ui.HorizontalPanel;
59 import com.google.gwt.user.client.ui.TreeItem;
60 import com.google.gwt.user.client.ui.Widget;
61 import com.google.gwt.user.client.ui.HTMLTable.Cell;
62
63 /**
64  * A composite that displays the list of files in a particular folder.
65  */
66 public class FileList extends Composite implements ClickHandler {
67
68         private HTML prevButton = new HTML("<a href='javascript:;'>&lt; Previous</a>", true);
69
70         private HTML nextButton = new HTML("<a href='javascript:;'>Next &gt;</a>", true);
71
72         private String showingStats = "";
73
74         private int startIndex = 0;
75
76         /**
77          * A constant that denotes the completion of an IncrementalCommand.
78          */
79         public static final boolean DONE = false;
80
81         private boolean clickControl = false;
82
83         private boolean clickShift = false;
84
85         private int firstShift = -1;
86
87         private ArrayList<Integer> selectedRows = new ArrayList<Integer>();
88
89         /**
90          * The context menu for the selected file.
91          */
92         final DnDSimpleFocusPanel contextMenu;
93
94         /**
95          * Specifies that the images available for this composite will be the ones
96          * available in FileContextMenu.
97          */
98         public interface Images extends ClientBundle,FileContextMenu.Images, Folders.Images {
99
100                 @Source("gr/ebs/gss/resources/blank.gif")
101                 ImageResource blank();
102
103                 @Source("gr/ebs/gss/resources/asc.png")
104                 ImageResource asc();
105
106                 @Source("gr/ebs/gss/resources/desc.png")
107                 ImageResource desc();
108
109                 @Source("gr/ebs/gss/resources/mimetypes/document_shared.png")
110                 ImageResource documentShared();
111
112                 @Source("gr/ebs/gss/resources/mimetypes/kcmfontinst.png")
113                 ImageResource wordprocessor();
114
115                 @Source("gr/ebs/gss/resources/mimetypes/log.png")
116                 ImageResource spreadsheet();
117
118                 @Source("gr/ebs/gss/resources/mimetypes/kpresenter_kpr.png")
119                 ImageResource presentation();
120
121                 @Source("gr/ebs/gss/resources/mimetypes/acroread.png")
122                 ImageResource pdf();
123
124                 @Source("gr/ebs/gss/resources/mimetypes/image.png")
125                 ImageResource image();
126
127                 @Source("gr/ebs/gss/resources/mimetypes/video2.png")
128                 ImageResource video();
129
130                 @Source("gr/ebs/gss/resources/mimetypes/knotify.png")
131                 ImageResource audio();
132
133                 @Source("gr/ebs/gss/resources/mimetypes/html.png")
134                 ImageResource html();
135
136                 @Source("gr/ebs/gss/resources/mimetypes/txt.png")
137                 ImageResource txt();
138
139                 @Source("gr/ebs/gss/resources/mimetypes/ark2.png")
140                 ImageResource zip();
141
142                 @Source("gr/ebs/gss/resources/mimetypes/kcmfontinst_shared.png")
143                 ImageResource wordprocessorShared();
144
145                 @Source("gr/ebs/gss/resources/mimetypes/log_shared.png")
146                 ImageResource spreadsheetShared();
147
148                 @Source("gr/ebs/gss/resources/mimetypes/kpresenter_kpr_shared.png")
149                 ImageResource presentationShared();
150
151                 @Source("gr/ebs/gss/resources/mimetypes/acroread_shared.png")
152                 ImageResource pdfShared();
153
154                 @Source("gr/ebs/gss/resources/mimetypes/image_shared.png")
155                 ImageResource imageShared();
156
157                 @Source("gr/ebs/gss/resources/mimetypes/video2_shared.png")
158                 ImageResource videoShared();
159
160                 @Source("gr/ebs/gss/resources/mimetypes/knotify_shared.png")
161                 ImageResource audioShared();
162
163                 @Source("gr/ebs/gss/resources/mimetypes/html_shared.png")
164                 ImageResource htmlShared();
165
166                 @Source("gr/ebs/gss/resources/mimetypes/txt_shared.png")
167                 ImageResource txtShared();
168
169                 @Source("gr/ebs/gss/resources/mimetypes/ark2_shared.png")
170                 ImageResource zipShared();
171
172         }
173
174         /**
175          * A label with the number of files in this folder.
176          */
177         private HTML countLabel = new HTML();
178
179         /**
180          * The table widget with the file list.
181          */
182         private FileTable table = new FileTable(GSS.VISIBLE_FILE_COUNT + 1, 8);
183
184         /**
185          * The navigation bar for paginating the results.
186          */
187         private HorizontalPanel navBar = new HorizontalPanel();
188
189         /**
190          * The number of files in this folder.
191          */
192         int folderFileCount;
193
194         /**
195          * Total folder size
196          */
197         long folderTotalSize;
198
199         /**
200          * A cache of the files in the list.
201          */
202         private List<FileResource> files;
203
204         /**
205          * The widget's image bundle.
206          */
207         private final Images images;
208
209         private String sortingProperty = "name";
210
211         private boolean sortingType = true;
212
213         private HTML nameLabel;
214
215         private HTML versionLabel;
216
217         private HTML sizeLabel;
218
219         private HTML dateLabel;
220
221         private HTML ownerLabel;
222
223         private HTML pathLabel;
224         private FileContextMenu menuShowing;
225         /**
226          * Construct the file list widget. This entails setting up the widget
227          * layout, fetching the number of files in the current folder from the
228          * server and filling the local file cache of displayed files with data from
229          * the server, as well.
230          *
231          * @param _images
232          */
233         public FileList(Images _images) {
234                 images = _images;
235
236                 prevButton.addClickHandler(this);
237                 nextButton.addClickHandler(this);
238
239                 contextMenu = new DnDSimpleFocusPanel(new HTML(AbstractImagePrototype.create(images.fileContextMenu()).getHTML()));
240                 GSS.get().getDragController().makeDraggable(contextMenu);
241
242                 // Setup the table.
243                 table.setCellSpacing(0);
244                 table.setCellPadding(2);
245                 table.setWidth("100%");
246
247                 // Hook up events.
248                 table.addClickHandler(new ClickHandler() {
249
250                         @Override
251                         public void onClick(ClickEvent event) {
252                                 Cell cell = table.getCellForEvent(event);
253                                 GWT.log("row clicked:"+cell.getRowIndex(), null);
254                                 onRowClicked(cell.getRowIndex(), true);
255                         }
256                 });
257
258                 // Create the 'navigation' bar at the upper-right.
259                 HorizontalPanel innerNavBar = new HorizontalPanel();
260                 innerNavBar.setStyleName("gss-ListNavBar");
261                 innerNavBar.setSpacing(8);
262                 innerNavBar.add(prevButton);
263                 innerNavBar.add(countLabel);
264                 innerNavBar.add(nextButton);
265                 navBar.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
266                 navBar.add(innerNavBar);
267                 navBar.setWidth("100%");
268
269                 initWidget(table);
270                 setStyleName("gss-List");
271
272                 initTable();
273                 DeferredCommand.addCommand(new IncrementalCommand() {
274
275                         @Override
276                         public boolean execute() {
277                                 return fetchRootFolder();
278                         }
279                 });
280                 sinkEvents(Event.ONCONTEXTMENU);
281                 sinkEvents(Event.ONMOUSEUP);
282                 sinkEvents(Event.ONMOUSEDOWN);
283                 sinkEvents(Event.ONCLICK);
284                 sinkEvents(Event.ONKEYDOWN);
285                 sinkEvents(Event.ONDBLCLICK);
286                 GSS.preventIESelection();
287         }
288
289         @Override
290         public void onClick(ClickEvent event) {
291                  if(event.getSource() == nextButton){
292                         // Move forward a page.
293                         clearSelectedRows();
294                         startIndex += GSS.VISIBLE_FILE_COUNT;
295                         if (startIndex >= folderFileCount)
296                                 startIndex -= GSS.VISIBLE_FILE_COUNT;
297                         else
298                                 update(false);
299                 } else if (event.getSource() == prevButton) {
300                         clearSelectedRows();
301                         // Move back a page.
302                         startIndex -= GSS.VISIBLE_FILE_COUNT;
303                         if (startIndex < 0)
304                                 startIndex = 0;
305                         else
306                                 update(false);
307                 }
308         }
309
310         @Override
311         public void onBrowserEvent(Event event) {
312                 if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && DOM.eventGetButton(event) == NativeEvent.BUTTON_RIGHT){
313                         if (DOM.eventGetCtrlKey(event))
314                                 clickControl = true;
315                         else
316                                 clickControl = false;
317                         if (DOM.eventGetShiftKey(event)) {
318                                 clickShift = true;
319                                 if (selectedRows.size() == 1)
320                                         firstShift = selectedRows.get(0) - startIndex;
321                                 //event.preventDefault();
322                         } else {
323                                 clickShift = false;
324                                 firstShift = -1;
325                                 //event.preventDefault();
326                         }
327                         int ri = table.getRowForEvent2(event);
328                         if(ri != -1)
329                                 if(!selectedRows.contains(ri-1))
330                                         onRowClicked(ri, false);
331                 }
332                 if (files == null || files.size() == 0) {
333                         if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && selectedRows.size() == 0) {
334                                 menuShowing = new FileContextMenu(images, false, true);
335                                 menuShowing=menuShowing.onEmptyEvent(event);
336                         }
337                         return;
338                 }
339                 if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && selectedRows.size() != 0) {
340                         GWT.log("*****GOING TO SHOW CONTEXT MENU ****", null);
341                         menuShowing =  new FileContextMenu(images, false, false);
342                         menuShowing=menuShowing.onEvent(event);
343                 } else if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && selectedRows.size() == 0) {
344                         menuShowing = new FileContextMenu(images, false, true);
345                         menuShowing=menuShowing.onEmptyEvent(event);
346                 } else if (DOM.eventGetType(event) == Event.ONDBLCLICK)
347                         if (getSelectedFiles().size() == 1) {
348                                 GSS app = GSS.get();
349                                 FileResource file = getSelectedFiles().get(0);
350                                 String dateString = RestCommand.getDate();
351                                 String resource = file.getUri().substring(app.getApiPath().length() - 1, file.getUri().length());
352                                 String sig = app.getCurrentUserResource().getUsername() + " " +
353                                                 RestCommand.calculateSig("GET", dateString, resource,
354                                                 RestCommand.base64decode(app.getToken()));
355                                 Window.open(file.getUri() + "?Authorization=" + URL.encodeComponent(sig) + "&Date=" + URL.encodeComponent(dateString), "_blank", "");
356                                 event.preventDefault();
357                                 return;
358                         }
359                 if (DOM.eventGetType(event) == Event.ONCLICK) {
360                         if (DOM.eventGetCtrlKey(event))
361                                 clickControl = true;
362                         else
363                                 clickControl = false;
364                         if (DOM.eventGetShiftKey(event)) {
365                                 clickShift = true;
366                                 if (selectedRows.size() == 1)
367                                         firstShift = selectedRows.get(0) - startIndex;
368                                 //event.preventDefault();
369                         } else {
370                                 clickShift = false;
371                                 firstShift = -1;
372                                 //event.preventDefault();
373                         }
374                 }
375                 super.onBrowserEvent(event);
376         }
377
378         /**
379          * Retrieve the root folder for the current user.
380          *
381          * @return true if the retrieval was successful
382          */
383         protected boolean fetchRootFolder() {
384                 UserResource user = GSS.get().getCurrentUserResource();
385                 if (user == null)
386                         return !DONE;
387                 // Update cache and clear selection.
388                 updateFileCache(true);
389                 return DONE;
390         }
391
392         private void onRowClicked(int row, boolean toggleSelection) {
393                 // Select the row that was clicked (-1 to account for header row).
394                 if (row > folderFileCount)
395                         return;
396                 if (clickShift) {
397                         GWT.log("Row is: " + row + " fs: " + firstShift, null);
398                         if (firstShift == -1){
399                                 firstShift = row;
400                                 makeRowDraggable(row);
401                         }
402                         else if (row > firstShift) {
403                                 clearSelectedRows();
404                                 for (int i = firstShift; i < row; i++) {
405                                         selectedRows.add(startIndex + i);
406                                         styleRow(i, true);
407                                         makeRowDraggable(i+1);
408                                 }
409                                 GSS.get().setCurrentSelection(getSelectedFiles());
410                                 contextMenu.setFiles(getSelectedFiles());
411                                 //makeRowDraggable(row);
412                         } else if (row != -1 && row == firstShift) {
413                                 selectedRows.add(row - 1);
414                                 styleRow(row, true);
415                                 styleRow(row - 1, true);
416                                 GSS.get().setCurrentSelection(getSelectedFiles());
417                                 contextMenu.setFiles(getSelectedFiles());
418                                 makeRowDraggable(row);
419                                 makeRowDraggable(row+1);
420                         } else if (row < firstShift) {
421                                 GWT.log("Row is:" + row + " fs:" + firstShift, null);
422                                 clearSelectedRows();
423
424                                 for (int i = firstShift; i >= row - 1; i--) {
425                                         selectedRows.add(startIndex + i);
426                                         styleRow(i, true);
427                                         makeRowDraggable(i+1);
428                                 }
429                                 GSS.get().setCurrentSelection(getSelectedFiles());
430                                 //makeRowDraggable(row);
431                                 contextMenu.setFiles(getSelectedFiles());
432                         }
433                 } else if (row > 0)
434                         selectRow(row - 1, toggleSelection);
435         }
436
437         /**
438          * Initializes the table so that it contains enough rows for a full page of
439          * files.
440          */
441         private void initTable() {
442                 nameLabel = new HTML("Name");
443                 nameLabel.addClickHandler(new ClickHandler() {
444
445                         @Override
446                         public void onClick(ClickEvent event) {
447                                 sortFiles("name");
448                         }
449
450                 });
451                 versionLabel = new HTML("Version");
452                 versionLabel.addClickHandler(new ClickHandler() {
453
454                         @Override
455                         public void onClick(ClickEvent event) {
456                                 sortFiles("version");
457                         }
458
459                 });
460                 sizeLabel = new HTML("Size");
461                 sizeLabel.addClickHandler(new ClickHandler() {
462
463                         @Override
464                         public void onClick(ClickEvent event) {
465                                 sortFiles("size");
466                         }
467
468                 });
469                 dateLabel = new HTML("Last modified");
470                 dateLabel.addClickHandler(new ClickHandler() {
471
472                         @Override
473                         public void onClick(ClickEvent event) {
474                                 sortFiles("date");
475                         }
476
477                 });
478                 ownerLabel = new HTML("Owner");
479                 ownerLabel.addClickHandler(new ClickHandler() {
480
481                         @Override
482                         public void onClick(ClickEvent event) {
483                                 sortFiles("owner");
484                         }
485
486                 });
487                 pathLabel = new HTML("Path");
488                 pathLabel.addClickHandler(new ClickHandler() {
489
490                         @Override
491                         public void onClick(ClickEvent event) {
492                                 sortFiles("path");
493                         }
494
495                 });
496                 // Create the header row.
497                 table.setText(0, 0, "");
498                 table.setWidget(0, 1, nameLabel);
499                 table.setWidget(0, 2, ownerLabel);
500                 table.setWidget(0, 3, pathLabel);
501                 table.setWidget(0, 4, versionLabel);
502                 table.setWidget(0, 5, sizeLabel);
503                 table.setWidget(0, 6, dateLabel);
504                 table.setWidget(0, 7, navBar);
505                 table.getRowFormatter().setStyleName(0, "gss-ListHeader");
506
507                 // Initialize the rest of the rows.
508                 for (int i = 1; i < GSS.VISIBLE_FILE_COUNT + 1; ++i) {
509                         table.setText(i, 0, "");
510                         table.setText(i, 1, "");
511                         table.setText(i, 2, "");
512                         table.setText(i, 3, "");
513                         table.setText(i, 4, "");
514                         table.setText(i, 5, "");
515                         table.setText(i, 6, "");
516                         table.setText(i, 7, "");
517                         table.getCellFormatter().setWordWrap(i, 0, false);
518                         table.getCellFormatter().setWordWrap(i, 1, false);
519                         table.getCellFormatter().setWordWrap(i, 2, false);
520                         table.getCellFormatter().setWordWrap(i, 3, false);
521                         table.getCellFormatter().setWordWrap(i, 4, false);
522                         table.getCellFormatter().setWordWrap(i, 5, false);
523                         table.getCellFormatter().setWordWrap(i, 6, false);
524                         table.getCellFormatter().setWordWrap(i, 7, false);
525                         table.getCellFormatter().setHorizontalAlignment(i, 4, HasHorizontalAlignment.ALIGN_CENTER);
526                 }
527                 prevButton.setVisible(false);
528                 nextButton.setVisible(false);
529         }
530
531         /**
532          * Selects the given row (relative to the current page).
533          *
534          * @param row the row to be selected
535          */
536         private void selectRow(final int row, boolean toggleSelection) {
537                 if (row < folderFileCount) {
538                         if (clickControl)
539                                 if (selectedRows.contains(row) && toggleSelection) {
540                                         int i = selectedRows.indexOf(startIndex + row);
541                                         selectedRows.remove(i);
542                                         styleRow(row, false);
543                                 } else {
544                                         selectedRows.add(startIndex + row);
545                                         styleRow(row, true);
546                                 }
547                         else if (selectedRows.size() == 1 && selectedRows.contains(row) && toggleSelection){
548                                 clearSelectedRows();
549                                 return;
550                         }
551                         else {
552                                 clearSelectedRows();
553                                 selectedRows.add(startIndex + row);
554                                 styleRow(row, true);
555                         }
556                         if (selectedRows.size() == 1)
557                                 GSS.get().setCurrentSelection(files.get(selectedRows.get(0)));
558                         else if(selectedRows.size() == 0)
559                                 GSS.get().setCurrentSelection(null);
560                         else
561                                 GSS.get().setCurrentSelection(getSelectedFiles());
562                         contextMenu.setFiles(getSelectedFiles());
563                         makeRowDraggable(row+1);
564                 }
565         }
566
567         public List<FileResource> getSelectedFiles() {
568                 List<FileResource> result = new ArrayList();
569                 for (int i : selectedRows)
570                         result.add(files.get(i));
571                 return result;
572         }
573
574         /**
575          * Make the specified row look like selected or not, according to the
576          * <code>selected</code> flag.
577          *
578          * @param row
579          * @param selected
580          */
581         void styleRow(final int row, final boolean selected) {
582                 if (row != -1 && row >= 0)
583                         if (selected)
584                                 table.getRowFormatter().addStyleName(row + 1, "gss-SelectedRow");
585                         else
586                                 table.getRowFormatter().removeStyleName(row + 1, "gss-SelectedRow");
587         }
588
589         /**
590          * Update the display of the file list.
591          */
592         void update(boolean sort) {
593                 int count = folderFileCount;
594                 int max = startIndex + GSS.VISIBLE_FILE_COUNT;
595                 if (max > count)
596                         max = count;
597                 folderTotalSize = 0;
598
599                 if (sort && files != null && files.size() != 0) {
600                         clearLabels();
601                         clearSelectedRows();
602
603                         Collections.sort(files, new Comparator<FileResource>() {
604
605                                 @Override
606                                 public int compare(FileResource arg0, FileResource arg1) {
607                                         AbstractImagePrototype descPrototype = AbstractImagePrototype.create(images.desc());
608                                         AbstractImagePrototype ascPrototype = AbstractImagePrototype.create(images.asc());
609                                         if (sortingType)
610                                                 if (sortingProperty.equals("version")) {
611                                                         versionLabel.setHTML("Version&nbsp;" + descPrototype.getHTML());
612                                                         return arg0.getVersion().compareTo(arg1.getVersion());
613                                                 } else if (sortingProperty.equals("owner")) {
614                                                         ownerLabel.setHTML("Owner&nbsp;" + descPrototype.getHTML());
615                                                         return arg0.getOwner().compareTo(arg1.getOwner());
616                                                 } else if (sortingProperty.equals("date")) {
617                                                         dateLabel.setHTML("Date modified&nbsp;" + descPrototype.getHTML());
618                                                         return arg0.getModificationDate().compareTo(arg1.getModificationDate());
619                                                 } else if (sortingProperty.equals("size")) {
620                                                         sizeLabel.setHTML("Size&nbsp;" + descPrototype.getHTML());
621                                                         return arg0.getContentLength().compareTo(arg1.getContentLength());
622                                                 } else if (sortingProperty.equals("name")) {
623                                                         nameLabel.setHTML("Name&nbsp;" + descPrototype.getHTML());
624                                                         return arg0.getName().compareTo(arg1.getName());
625                                                 } else if (sortingProperty.equals("path")) {
626                                                         pathLabel.setHTML("Path&nbsp;" + descPrototype.getHTML());
627                                                         return arg0.getUri().compareTo(arg1.getUri());
628                                                 } else {
629                                                         nameLabel.setHTML("Name&nbsp;" + descPrototype.getHTML());
630                                                         return arg0.getName().compareTo(arg1.getName());
631                                                 }
632                                         else if (sortingProperty.equals("version")) {
633                                                 versionLabel.setHTML("Version&nbsp;" + ascPrototype.getHTML());
634                                                 return arg1.getVersion().compareTo(arg0.getVersion());
635                                         } else if (sortingProperty.equals("owner")) {
636                                                 ownerLabel.setHTML("Owner&nbsp;" + ascPrototype.getHTML());
637                                                 return arg1.getOwner().compareTo(arg0.getOwner());
638                                         } else if (sortingProperty.equals("date")) {
639                                                 dateLabel.setHTML("Date modified&nbsp;" + ascPrototype.getHTML());
640                                                 return arg1.getModificationDate().compareTo(arg0.getModificationDate());
641                                         } else if (sortingProperty.equals("size")) {
642                                                 sizeLabel.setHTML("Size&nbsp;" + ascPrototype.getHTML());
643                                                 return arg1.getContentLength().compareTo(arg0.getContentLength());
644                                         } else if (sortingProperty.equals("name")) {
645                                                 nameLabel.setHTML("Name&nbsp;" + ascPrototype.getHTML());
646                                                 return arg1.getName().compareTo(arg0.getName());
647                                         } else if (sortingProperty.equals("path")) {
648                                                 pathLabel.setHTML("Path&nbsp;" + ascPrototype.getHTML());
649                                                 return arg1.getUri().compareTo(arg0.getUri());
650                                         } else {
651                                                 nameLabel.setHTML("Name&nbsp;" + ascPrototype.getHTML());
652                                                 return arg1.getName().compareTo(arg0.getName());
653                                         }
654                                 }
655
656                         });
657                 }
658
659
660                 // Show the selected files.
661                 int i = 1;
662                 for (; i < GSS.VISIBLE_FILE_COUNT + 1; ++i) {
663                         // Don't read past the end.
664                         // if (i > folderFileCount)
665                         // break;
666                         if (startIndex + i > folderFileCount)
667                                 break;
668                         // Add a new row to the table, then set each of its columns to the
669                         // proper values.
670                         FileResource file = files.get(startIndex + i - 1);
671                         table.setWidget(i, 0, getFileIcon(file).createImage());
672                         table.getRowFormatter().addStyleName(i, "gss-fileRow");
673
674                         //add view image link for image files
675                         String contentType = file.getContentType();
676                         HTML nameHtml = null;
677                         if (contentType.endsWith("png") || contentType.endsWith("gif") || contentType.endsWith("jpeg") )
678                                 nameHtml = new HTML( file.getName() + " <a href='" +
679                                                 GSS.get().getTopPanel().getFileMenu().getDownloadURL(file) +
680                                                 "' title='" + file.getOwner() + " : " + file.getPath() + file.getName() +
681                                                 "' rel='lytebox[mnf]' " +
682                                                 "onclick='myLytebox.start(this, false, false); return false;'>" +
683                                                 "(view)" + "</a>");
684                         else
685                                 nameHtml=new HTML( file.getName());
686                         table.setWidget(i, 1, nameHtml);
687
688                         if(GSS.get().findUserFullName(file.getOwner()) == null){
689                                 GetUserCommand guc = new GetUserCommand(file.getOwner());
690                                 guc.execute();
691                                 GSS.get().putUserToMap(file.getOwner(), file.getOwner());
692                         }
693                         table.setText(i, 2, GSS.get().getUserFullName(file.getOwner()));
694                         table.setText(i, 3, file.getPath());
695                         table.setText(i, 4, String.valueOf(file.getVersion()));
696                         table.setText(i, 5, String.valueOf(file.getFileSizeAsString()));
697                         final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
698                         table.setText(i, 6, formatter.format(file.getModificationDate()));
699                         folderTotalSize += file.getContentLength();
700                 }
701
702                 // Clear any remaining slots.
703                 for (; i < GSS.VISIBLE_FILE_COUNT + 1; ++i) {
704                         table.setHTML(i, 0, "&nbsp;");
705                         table.setHTML(i, 1, "&nbsp;");
706                         table.setHTML(i, 2, "&nbsp;");
707                         table.setHTML(i, 3, "&nbsp;");
708                         table.setHTML(i, 4, "&nbsp;");
709                         table.setHTML(i, 5, "&nbsp;");
710                         table.setHTML(i, 6, "&nbsp;");
711                         table.setHTML(i, 7, "&nbsp;");
712                 }
713
714                 if (folderFileCount == 0) {
715                         showingStats = "no files";
716                         prevButton.setVisible(false);
717                         nextButton.setVisible(false);
718                 } else if (folderFileCount < GSS.VISIBLE_FILE_COUNT) {
719                         if (folderFileCount == 1)
720                                 showingStats = "1 file";
721                         else
722                                 showingStats = folderFileCount + " files";
723                         showingStats += " (" + FileResource.getFileSizeAsString(folderTotalSize) + ")";
724                         prevButton.setVisible(false);
725                         nextButton.setVisible(false);
726                 } else {
727                         showingStats = "" + (startIndex + 1) + " - " + max + " of " + count + " files" + " (" + FileResource.getFileSizeAsString(folderTotalSize) + ")";
728                         prevButton.setVisible(startIndex != 0);
729                         nextButton.setVisible(startIndex + GSS.VISIBLE_FILE_COUNT < count);
730                 }
731                 updateCurrentlyShowingStats();
732
733         }
734
735         /**
736          * Return the proper icon based on the MIME type of the file.
737          *
738          * @param file
739          * @return the icon
740          */
741         private AbstractImagePrototype getFileIcon(FileResource file) {
742                 String mimetype = file.getContentType();
743                 boolean shared = false;
744                 Folders folders = GSS.get().getFolders();
745                 if(folders.getCurrent() != null && folders.isOthersSharedItem(folders.getCurrent())){
746                         DnDTreeItem otherUser = (DnDTreeItem) folders.getUserOfSharedItem(folders.getCurrent());
747                         if(otherUser==null)
748                                 shared = false;
749                         else{
750                                 String uname = otherUser.getOtherUserResource().getUsername();
751                                 if(uname==null)
752                                         uname = ((DnDTreeItem)folders.getSharesItem()).getOthersResource().getUsernameOfUri(otherUser.getOtherUserResource().getUri());
753                                 if(uname != null)
754                                         shared = file.isShared();
755                         }
756                 }
757                 else
758                         shared = file.isShared();
759                 if (mimetype == null)
760                         return shared ? AbstractImagePrototype.create(images.documentShared()) : AbstractImagePrototype.create(images.document());
761                 mimetype = mimetype.toLowerCase();
762                 if (mimetype.startsWith("application/pdf"))
763                         return shared ? AbstractImagePrototype.create(images.pdfShared()) : AbstractImagePrototype.create(images.pdf());
764                 else if (mimetype.endsWith("excel"))
765                         return shared ? AbstractImagePrototype.create(images.spreadsheetShared()) : AbstractImagePrototype.create(images.spreadsheet());
766                 else if (mimetype.endsWith("msword"))
767                         return shared ? AbstractImagePrototype.create(images.wordprocessorShared()) : AbstractImagePrototype.create(images.wordprocessor());
768                 else if (mimetype.endsWith("powerpoint"))
769                         return shared ? AbstractImagePrototype.create(images.presentationShared()) : AbstractImagePrototype.create(images.presentation());
770                 else if (mimetype.startsWith("application/zip") ||
771                                         mimetype.startsWith("application/gzip") ||
772                                         mimetype.startsWith("application/x-gzip") ||
773                                         mimetype.startsWith("application/x-tar") ||
774                                         mimetype.startsWith("application/x-gtar"))
775                         return shared ? AbstractImagePrototype.create(images.zipShared()) : AbstractImagePrototype.create(images.zip());
776                 else if (mimetype.startsWith("text/html"))
777                         return shared ? AbstractImagePrototype.create(images.htmlShared()) : AbstractImagePrototype.create(images.html());
778                 else if (mimetype.startsWith("text/plain"))
779                         return shared ? AbstractImagePrototype.create(images.txtShared()) : AbstractImagePrototype.create(images.txt());
780                 else if (mimetype.startsWith("image/"))
781                         return shared ? AbstractImagePrototype.create(images.imageShared()) : AbstractImagePrototype.create(images.image());
782                 else if (mimetype.startsWith("video/"))
783                         return shared ? AbstractImagePrototype.create(images.videoShared()) : AbstractImagePrototype.create(images.video());
784                 else if (mimetype.startsWith("audio/"))
785                         return shared ? AbstractImagePrototype.create(images.audioShared()) : AbstractImagePrototype.create(images.audio());
786                 return shared ? AbstractImagePrototype.create(images.documentShared()) : AbstractImagePrototype.create(images.document());
787         }
788
789         /**
790          * Update status panel with currently showing file stats.
791          */
792         public void updateCurrentlyShowingStats() {
793                 GSS.get().getStatusPanel().updateCurrentlyShowing(showingStats);
794         }
795
796         /**
797          * Adjust the height of the table by adding and removing rows as necessary.
798          *
799          * @param newHeight the new height to reach
800          */
801         void resizeTableHeight(final int newHeight) {
802                 GWT.log("Panel: " + newHeight + ", parent: " + table.getParent().getOffsetHeight(), null);
803                 // Fill the rest with empty slots.
804                 if (newHeight > table.getOffsetHeight())
805                         while (newHeight > table.getOffsetHeight()) {
806                                 table.resizeRows(table.getRowCount() + 1);
807                                 GWT.log("Table: " + table.getOffsetHeight() + ", rows: " + table.getRowCount(), null);
808                         }
809                 else
810                         while (newHeight < table.getOffsetHeight()) {
811                                 table.resizeRows(table.getRowCount() - 1);
812                                 GWT.log("Table: " + table.getOffsetHeight() + ", rows: " + table.getRowCount(), null);
813                         }
814         }
815
816         public void updateFileCache(boolean updateSelectedFolder, final boolean clearSelection) {
817                 updateFileCache(updateSelectedFolder, clearSelection, null);
818         }
819
820         public void updateFileCache(boolean updateSelectedFolder, final boolean clearSelection, final String newFilename) {
821                 if (!updateSelectedFolder && !GSS.get().getFolders().getCurrent().equals(GSS.get().getFolders().getTrashItem()))
822                         updateFileCache(clearSelection);
823                 else if (GSS.get().getFolders().getCurrent() != null) {
824                         final DnDTreeItem folderItem = (DnDTreeItem) GSS.get().getFolders().getCurrent();
825                         if (folderItem.getFolderResource() != null) {
826                                 if(GSS.get().getFolders().isFileItem(folderItem) || GSS.get().getFolders().isMySharedItem(folderItem)  || GSS.get().getFolders().isOthersSharedItem(folderItem) ){
827                                 update(true);
828                                 GetCommand<FolderResource> gf = new GetCommand<FolderResource>(FolderResource.class, folderItem.getFolderResource().getUri(),folderItem.getFolderResource()) {
829
830                                         @Override
831                                         public void onComplete() {
832                                                 folderItem.setUserObject(getResult());
833                                                                 if(GSS.get().getFolders().isFileItem(folderItem)){
834                                                         String[] filePaths = new String[folderItem.getFolderResource().getFilePaths().size()];
835                                                         int c=0;
836                                                         for(String fpath : folderItem.getFolderResource().getFilePaths()){
837                                                                 filePaths[c] = fpath + "?" + Math.random();
838                                                                 c++;
839                                                         }
840                                                         MultipleHeadCommand<FileResource> getFiles = new MultipleHeadCommand<FileResource>(FileResource.class, filePaths, folderItem.getFolderResource().getFileCache()){
841
842                                                                 @Override
843                                                                 public void onComplete(){
844                                                                         List<FileResource> result = getResult();
845                                                                         //remove random from path
846                                                                         for(FileResource r : result){
847                                                                                 String p = r.getUri();
848                                                                                 int indexOfQuestionMark = p.lastIndexOf('?');
849                                                                                 if(indexOfQuestionMark>0)
850                                                                                         r.setUri(p.substring(0, indexOfQuestionMark));
851                                                                                 GWT.log("FETCHED:"+r.getLastModifiedSince(), null);
852                                                                         }
853                                                                         folderItem.getFolderResource().setFiles(result);
854                                                                         folderItem.getFolderResource().setFilesExpanded(true);
855                                                                         updateFileCache(clearSelection, newFilename);
856                                                                 }
857
858                                                                 @Override
859                                                                 public void onError(String p, Throwable throwable) {
860                                                                         if(throwable instanceof RestException)
861                                                                                 GSS.get().displayError("Unable to retrieve file details:"+((RestException)throwable).getHttpStatusText());
862                                                                 }
863
864                                                                 @Override
865                                                                 public void onError(Throwable t) {
866                                                                         GWT.log("", t);
867                                                                         GSS.get().displayError("Unable to fetch files for folder " + folderItem.getFolderResource().getName());
868                                                                 }
869
870                                                         };
871                                                         DeferredCommand.addCommand(getFiles);
872                                                 }
873                                                 else
874                                                         updateFileCache(clearSelection, newFilename);
875                                         }
876
877                                         @Override
878                                         public void onError(Throwable t) {
879                                                 GWT.log("", t);
880                                                 GSS.get().displayError("Unable to fetch folder " + folderItem.getFolderResource().getName());
881                                         }
882                                 };
883                                 DeferredCommand.addCommand(gf);
884                                 }
885                         }
886                         else if (folderItem.getTrashResource() != null) {
887                                 GetCommand<TrashResource> gt = new GetCommand<TrashResource>(TrashResource.class, folderItem.getTrashResource().getUri(), null) {
888
889                                         @Override
890                                         public void onComplete() {
891                                                 folderItem.setUserObject(getResult());
892                                                 updateFileCache(clearSelection);
893                                         }
894
895                                         @Override
896                                         public void onError(Throwable t) {
897                                                 if (t instanceof RestException && (((RestException) t).getHttpStatusCode() == 204 || ((RestException) t).getHttpStatusCode() == 1223)) {
898                                                         folderItem.setUserObject(new TrashResource(folderItem.getTrashResource().getUri()));
899                                                         updateFileCache(clearSelection);
900                                                 } else {
901                                                         GWT.log("", t);
902                                                         GSS.get().displayError("Unable to fetch trash resource");
903                                                 }
904                                         }
905                                 };
906                                 DeferredCommand.addCommand(gt);
907                         } else if (folderItem.getSharedResource() != null) {
908                                 GetCommand<SharedResource> gt = new GetCommand<SharedResource>(SharedResource.class, folderItem.getSharedResource().getUri(), null) {
909
910                                         @Override
911                                         public void onComplete() {
912                                                 folderItem.setUserObject(getResult());
913                                                 for(FileResource r : folderItem.getSharedResource().getFiles()){
914                                                                         String p = r.getUri();
915                                                                         int indexOfQuestionMark = p.lastIndexOf('?');
916                                                                         if(indexOfQuestionMark>0)
917                                                                                 r.setUri(p.substring(0, indexOfQuestionMark));
918                                                                         GWT.log("FETCHED:"+r.getLastModifiedSince(), null);
919                                                                 }
920                                                                 folderItem.getSharedResource().setFilesExpanded(true);
921                                                                 updateFileCache(clearSelection, newFilename);
922                                                 
923                                         }
924
925                                         @Override
926                                         public void onError(Throwable t) {
927                                                 GWT.log("", t);
928                                                 GSS.get().displayError("Unable to fetch My Shares resource");
929                                         }
930                                 };
931                                 DeferredCommand.addCommand(gt);
932                         } else if (folderItem.getOtherUserResource() != null) {
933                                 GetCommand<OtherUserResource> gt = new GetCommand<OtherUserResource>(OtherUserResource.class, folderItem.getOtherUserResource().getUri(), null) {
934
935                                         @Override
936                                         public void onComplete() {
937                                                 folderItem.setUserObject(getResult());
938                                                 //updateFileCache(clearSelection, newFilename);
939                                                 for(FileResource r : folderItem.getOtherUserResource().getFiles()){
940                                                                         String p = r.getUri();
941                                                                         int indexOfQuestionMark = p.lastIndexOf('?');
942                                                                         if(indexOfQuestionMark>0)
943                                                                                 r.setUri(p.substring(0, indexOfQuestionMark));
944                                                                         GWT.log("FETCHED:"+r.getLastModifiedSince(), null);
945                                                                 }
946                                                                 folderItem.getOtherUserResource().setFilesExpanded(true);
947                                                                 updateFileCache(clearSelection, newFilename);
948                                                 
949                                         }
950
951                                         @Override
952                                         public void onError(Throwable t) {
953                                                 GWT.log("", t);
954                                                 GSS.get().displayError("Unable to fetch My Shares resource");
955                                         }
956                                 };
957                                 DeferredCommand.addCommand(gt);
958                         }
959                 } else
960                         updateFileCache(clearSelection);
961         }
962
963
964         private void updateFileCache(boolean clearSelection) {
965                 updateFileCache(clearSelection, null);
966         }
967
968         /**
969          * Update the file cache with data from the server.
970          *
971          * @param newFilename the new name of the previously selected file,
972          *                      if a rename operation has taken place
973          */
974         private void updateFileCache(boolean clearSelection, String newFilename) {
975                 if (clearSelection)
976                         clearSelectedRows();
977                 clearLabels();
978                 startIndex = 0;
979                 final TreeItem folderItem = GSS.get().getFolders().getCurrent();
980                 // Validation.
981                 if (folderItem == null || GSS.get().getFolders().isOthersShared(folderItem)) {
982                         setFiles(new ArrayList<FileResource>());
983                         update(true);
984                         return;
985                 }
986                 if (folderItem instanceof DnDTreeItem) {
987                         DnDTreeItem dnd = (DnDTreeItem) folderItem;
988                         if (dnd.getFolderResource() != null) {
989                                 if (GSS.get().getFolders().isTrashItem(dnd))
990                                         setFiles(new ArrayList<FileResource>());
991                                 else
992                                         setFiles(dnd.getFolderResource().getFiles());
993
994                         } else if (dnd.getTrashResource() != null)
995                                 setFiles(dnd.getTrashResource().getFiles());
996                         else if (dnd.getSharedResource() != null)
997                                 setFiles(dnd.getSharedResource().getFiles());
998                         else if (dnd.getOtherUserResource() != null)
999                                 setFiles(dnd.getOtherUserResource().getFiles());
1000                         else
1001                                 setFiles(dnd.getFolderResource().getFiles());
1002                         update(true);
1003
1004                         if (!clearSelection && selectedRows.size()==1 && newFilename!=null) {
1005                                 int row = -1;
1006                                 for (int i=1; i < GSS.VISIBLE_FILE_COUNT + 1; ++i) {
1007                                         if (startIndex + i > folderFileCount)
1008                                                 break;
1009                                         FileResource file = files.get(startIndex + i - 1);
1010                                         if (newFilename.equals(file.getName())) {
1011                                                 row = i-1;
1012                                                 break;
1013                                         }
1014                                 }
1015                                 clearSelectedRows();
1016                                 if (row!=-1)
1017                                         selectRow(row, true);
1018                         }
1019                 }
1020         }
1021
1022         /**
1023          * Fill the file cache with data.
1024          */
1025         public void setFiles(final List<FileResource> _files) {
1026                 if (_files.size() > 0 && !GSS.get().getFolders().isTrash(GSS.get().getFolders().getCurrent())) {
1027                         files = new ArrayList<FileResource>();
1028                         for (FileResource fres : _files)
1029                                 if (!fres.isDeleted())
1030                                         files.add(fres);
1031                 } else
1032                         files = _files;
1033                 Collections.sort(files, new Comparator<FileResource>() {
1034
1035                         @Override
1036                         public int compare(FileResource arg0, FileResource arg1) {
1037                                 return arg0.getName().compareTo(arg1.getName());
1038                         }
1039
1040                 });
1041                 folderFileCount = files.size();
1042         }
1043
1044         private void sortFiles(final String sortProperty) {
1045                 if (sortProperty.equals(sortingProperty))
1046                         sortingType = !sortingType;
1047                 else {
1048                         sortingProperty = sortProperty;
1049                         sortingType = true;
1050                 }
1051                 update(true);
1052         }
1053
1054         private void clearLabels() {
1055                 nameLabel.setText("Name");
1056                 versionLabel.setText("Version");
1057                 sizeLabel.setText("Size");
1058                 dateLabel.setText("Last modified");
1059                 ownerLabel.setText("Owner");
1060                 pathLabel.setText("Path");
1061         }
1062
1063         /**
1064          * Retrieve the table.
1065          *
1066          * @return the table
1067          */
1068         Grid getTable() {
1069                 return table;
1070         }
1071
1072         /**
1073          * Does the list contains the requested filename
1074          *
1075          * @param fileName
1076          * @return true/false
1077          */
1078         public boolean contains(String fileName) {
1079                 for (int i = 0; i < files.size(); i++)
1080                         if (files.get(i).getName().equals(fileName))
1081                                 return true;
1082                 return false;
1083         }
1084
1085         public void clearSelectedRows() {
1086                 for (int r : selectedRows) {
1087                         int row = r - startIndex;
1088                         styleRow(row, false);
1089                         makeRowNotDraggable(row+1);
1090                 }
1091                 selectedRows.clear();
1092                 Object sel = GSS.get().getCurrentSelection();
1093                 if (sel instanceof FileResource || sel instanceof List)
1094                         GSS.get().setCurrentSelection(null);
1095                 if(menuShowing != null && menuShowing.isShowing()){
1096                         menuShowing.hide();
1097                         menuShowing=null;
1098                 }
1099         }
1100
1101         /**
1102          *
1103          */
1104         public void selectAllRows() {
1105                 clearSelectedRows();
1106                 int count = folderFileCount;
1107                 if (count == 0)
1108                         return;
1109                 int max = startIndex + GSS.VISIBLE_FILE_COUNT;
1110                 if (max > count)
1111                         max = count;
1112                 int i = 1;
1113                 for (; i < GSS.VISIBLE_FILE_COUNT + 1; ++i) {
1114                         // Don't read past the end.
1115                         // if (i > folderFileCount)
1116                         // break;
1117                         if (startIndex + i > folderFileCount)
1118                                 break;
1119                         selectedRows.add(startIndex + i - 1);
1120                         styleRow(i - 1, true);
1121                         makeRowDraggable(i);
1122                 }
1123                 GSS.get().setCurrentSelection(getSelectedFiles());
1124                 contextMenu.setFiles(getSelectedFiles());
1125
1126
1127         }
1128
1129         private void makeRowDraggable(int row){
1130                 int contextRow = getWidgetRow(contextMenu, table);
1131                 if (contextRow != -1)
1132                         table.setWidget(contextRow, 0, getFileIcon(files.get(contextRow - 1)).createImage());
1133                 contextMenu.setWidget(new HTML(getFileIcon(files.get(row - 1)).getHTML()));
1134                 table.setWidget(row, 0, contextMenu);
1135                 //for(int i=1;i<table.getCellCount(row);i++)
1136                         //GSS.get().getDragController().makeDraggable(table.getWidget(row, i));
1137                 table.setWidget(row, 1, new DnDSimpleFocusPanel(table.getWidget(row, 1)));
1138                 ((DnDSimpleFocusPanel)table.getWidget(row, 1)).setFiles(getSelectedFiles());
1139                 GSS.get().getDragController().makeDraggable(table.getWidget(row, 1));
1140         }
1141         private void makeRowNotDraggable(int row){
1142                 if(table.getWidget(row, 1) instanceof DnDSimpleFocusPanel){
1143                         ((DnDSimpleFocusPanel)table.getWidget(row, 1)).setFiles(null);
1144                         GSS.get().getDragController().makeNotDraggable(table.getWidget(row, 1));
1145                         table.setWidget(row, 1, new DnDSimpleFocusPanel(((DnDSimpleFocusPanel)table.getWidget(row, 1)).getWidget()));
1146
1147                 }
1148         }
1149
1150         private int getWidgetRow(Widget widget, Grid grid) {
1151                 for (int row = 0; row < grid.getRowCount(); row++)
1152                         for (int col = 0; col < grid.getCellCount(row); col++) {
1153                                 Widget w = table.getWidget(row, col);
1154                                 if (w == widget)
1155                                         return row;
1156                         }
1157                 return -1;
1158         }
1159
1160 }