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