CSS fixes
[pithos-web-client] / src / gr / grnet / pithos / web / client / FileList.java
1 /*
2  * Copyright 2011 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials
15  *      provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * The views and conclusions contained in the software and
31  * documentation are those of the authors and should not be
32  * interpreted as representing official policies, either expressed
33  * or implied, of GRNET S.A.
34  */
35
36 package gr.grnet.pithos.web.client;
37
38 import gr.grnet.pithos.web.client.foldertree.File;
39 import gr.grnet.pithos.web.client.foldertree.Folder;
40 import gr.grnet.pithos.web.client.foldertree.FolderTreeView;
41
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.Comparator;
45 import java.util.Iterator;
46 import java.util.List;
47
48 import com.google.gwt.cell.client.ImageResourceCell;
49 import com.google.gwt.cell.client.SafeHtmlCell;
50 import com.google.gwt.cell.client.TextCell;
51 import com.google.gwt.cell.client.ValueUpdater;
52 import com.google.gwt.core.client.GWT;
53 import com.google.gwt.event.dom.client.ContextMenuEvent;
54 import com.google.gwt.event.dom.client.ContextMenuHandler;
55 import com.google.gwt.i18n.client.DateTimeFormat;
56 import com.google.gwt.resources.client.ImageResource;
57 import com.google.gwt.safehtml.client.SafeHtmlTemplates;
58 import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
59 import com.google.gwt.safehtml.shared.SafeHtml;
60 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
61 import com.google.gwt.user.cellview.client.CellTable;
62 import com.google.gwt.user.cellview.client.Column;
63 import com.google.gwt.user.client.Event;
64 import com.google.gwt.user.client.Window;
65 import com.google.gwt.user.client.ui.Composite;
66 import com.google.gwt.user.client.ui.VerticalPanel;
67 import com.google.gwt.view.client.ListDataProvider;
68 import com.google.gwt.view.client.MultiSelectionModel;
69 import com.google.gwt.view.client.ProvidesKey;
70
71 /**
72  * A composite that displays the list of files in a particular folder.
73  */
74 public class FileList extends Composite {
75
76         ListDataProvider<File> provider = new ListDataProvider<File>();
77
78     /**
79        * The styles applied to the table.
80        */
81     interface TableStyle extends CellTable.Style {
82     }
83
84         interface TableResources extends CellTable.Resources {
85             @Override
86                 @Source({CellTable.Style.DEFAULT_CSS, "PithosCellTable.css"})
87             TableStyle cellTableStyle();
88         }
89         
90         static interface Templates extends SafeHtmlTemplates {
91             Templates INSTANCE = GWT.create(Templates.class);
92
93             @Template("<div id='dragHelper' style='border:1px solid black; background-color:#ffffff; color:black; width:150px;z-index:100'></div>")
94             SafeHtml outerHelper();
95
96         @Template("<span id='{0}'>{0}</span>")
97         public SafeHtml filenameSpan(String filename);
98
99         @Template("<a href='{0}' title='{1}' rel='lytebox[mnf]' onclick='myLytebox.start(this, false, false); return false;'>(view)</a>")
100         public SafeHtml viewLink(String link, String title);
101
102         @Template("<table><tr><td rowspan='3'>{0}</td><td style='font-size:95%;' id='{1}'>{1}</td></tr><tr><td>{2}</td></tr></table>")
103         public SafeHtml rendelContactCell(String imageHtml, String name, String fileSize);
104
105         @Template("<span id='{0}' class='{1}'>{2}</span>")
106         public SafeHtml spanWithIdAndClass(String id, String cssClass, String content);
107         }
108
109         protected final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
110
111         /**
112          * Specifies that the images available for this composite will be the ones
113          * available in FileContextMenu.
114          */
115         public interface Images extends FolderTreeView.Images {
116
117                 @Source("gr/grnet/pithos/resources/blank.gif")
118                 ImageResource blank();
119
120                 @Source("gr/grnet/pithos/resources/asc.png")
121                 ImageResource asc();
122
123                 @Source("gr/grnet/pithos/resources/desc.png")
124                 ImageResource desc();
125
126                 @Source("gr/grnet/pithos/resources/mimetypes/document_shared.png")
127                 ImageResource documentShared();
128
129                 @Source("gr/grnet/pithos/resources/mimetypes/kcmfontinst.png")
130                 ImageResource wordprocessor();
131
132                 @Source("gr/grnet/pithos/resources/mimetypes/log.png")
133                 ImageResource spreadsheet();
134
135                 @Source("gr/grnet/pithos/resources/mimetypes/kpresenter_kpr.png")
136                 ImageResource presentation();
137
138                 @Source("gr/grnet/pithos/resources/mimetypes/acroread.png")
139                 ImageResource pdf();
140
141                 @Source("gr/grnet/pithos/resources/mimetypes/image.png")
142                 ImageResource image();
143
144                 @Source("gr/grnet/pithos/resources/mimetypes/video2.png")
145                 ImageResource video();
146
147                 @Source("gr/grnet/pithos/resources/mimetypes/knotify.png")
148                 ImageResource audio();
149
150                 @Source("gr/grnet/pithos/resources/mimetypes/html.png")
151                 ImageResource html();
152
153                 @Source("gr/grnet/pithos/resources/mimetypes/txt.png")
154                 ImageResource txt();
155
156                 @Source("gr/grnet/pithos/resources/mimetypes/ark2.png")
157                 ImageResource zip();
158
159                 @Source("gr/grnet/pithos/resources/mimetypes/kcmfontinst_shared.png")
160                 ImageResource wordprocessorShared();
161
162                 @Source("gr/grnet/pithos/resources/mimetypes/log_shared.png")
163                 ImageResource spreadsheetShared();
164
165                 @Source("gr/grnet/pithos/resources/mimetypes/kpresenter_kpr_shared.png")
166                 ImageResource presentationShared();
167
168                 @Source("gr/grnet/pithos/resources/mimetypes/acroread_shared.png")
169                 ImageResource pdfShared();
170
171                 @Source("gr/grnet/pithos/resources/mimetypes/image_shared.png")
172                 ImageResource imageShared();
173
174                 @Source("gr/grnet/pithos/resources/mimetypes/video2_shared.png")
175                 ImageResource videoShared();
176
177                 @Source("gr/grnet/pithos/resources/mimetypes/knotify_shared.png")
178                 ImageResource audioShared();
179
180                 @Source("gr/grnet/pithos/resources/mimetypes/html_shared.png")
181                 ImageResource htmlShared();
182
183                 @Source("gr/grnet/pithos/resources/mimetypes/txt_shared.png")
184                 ImageResource txtShared();
185
186                 @Source("gr/grnet/pithos/resources/mimetypes/ark2_shared.png")
187                 ImageResource zipShared();
188
189         }
190         
191         /**
192          * The number of files in this folder.
193          */
194         int folderFileCount;
195
196         /**
197          * Total folder size
198          */
199         long folderTotalSize;
200
201         /**
202          * A cache of the files in the list.
203          */
204         private List<File> files;
205
206         /**
207          * The widget's image bundle.
208          */
209         protected final Images images;
210         
211         protected CellTable<File> celltable;
212
213         private final MultiSelectionModel<File> selectionModel;
214
215         protected final List<SortableHeader> allHeaders = new ArrayList<SortableHeader>();
216
217         SortableHeader nameHeader;
218
219     FolderTreeView treeView;
220
221     protected Pithos app;
222
223     /**
224          * Construct the file list widget. This entails setting up the widget
225          * layout, fetching the number of files in the current folder from the
226          * server and filling the local file cache of displayed files with data from
227          * the server, as well.
228          *
229          * @param _images
230          */
231         public FileList(final Pithos _app, Images _images, FolderTreeView _treeView) {
232         app = _app;
233                 images = _images;
234         this.treeView = _treeView;
235
236         CellTable.Resources resources = GWT.create(TableResources.class);
237
238         ProvidesKey<File> keyProvider = new ProvidesKey<File>(){
239
240                         @Override
241                         public Object getKey(File item) {
242                                 return item.getUri();
243                         }
244                 };
245
246                 celltable = new CellTable<File>(10, resources, keyProvider);
247         celltable.setWidth("100%");
248         celltable.setStyleName("pithos-List");
249
250                 Column<File, ImageResource> status = new Column<File, ImageResource>(new ImageResourceCell() {
251                     @Override
252                 public boolean handlesSelection() {
253                     return false;
254                 }
255                 })
256         {
257                  @Override
258                  public ImageResource getValue(File entity) {
259                      return getFileIcon(entity);
260                  }
261             };
262             celltable.addColumn(status,"");
263
264         final Column<File,SafeHtml> nameColumn = new Column<File,SafeHtml>(new SafeHtmlCell()) {
265
266                         @Override
267                         public SafeHtml getValue(File object) {
268                                 SafeHtmlBuilder sb = new SafeHtmlBuilder();
269                 sb.append(Templates.INSTANCE.filenameSpan(object.getName()));
270                                 if (object.getContentType().endsWith("png") || object.getContentType().endsWith("gif") || object.getContentType().endsWith("jpeg")) {
271                                 sb.appendHtmlConstant("&nbsp;")
272                       .append(Templates.INSTANCE.viewLink(app.getApiPath() + object.getOwner() + object.getUri() + "?X-Auth-Token=" + app.getToken(), object.getName()));
273                                 }
274                                 
275                                 return sb.toSafeHtml();
276                         }
277                         
278                 };
279         celltable.addColumn(nameColumn, nameHeader = new SortableHeader("Name"));
280                 allHeaders.add(nameHeader);
281                 nameHeader.setUpdater(new FileValueUpdater(nameHeader, "name"));
282
283                 celltable.redrawHeaders();
284                 
285         Column<File,String> aColumn = new Column<File,String>(new TextCell()) {
286                         @Override
287                         public String getValue(File object) {
288                                 // TODO Auto-generated method stub
289                                 return object.getSizeAsString();
290                         }
291                 };
292         SortableHeader aheader = new SortableHeader("Size");
293         celltable.addColumn(aColumn, aheader);
294                 allHeaders.add(aheader);
295                 aheader.setUpdater(new FileValueUpdater(aheader, "size"));
296
297         aColumn = new Column<File,String>(new TextCell()) {
298                         @Override
299                         public String getValue(File object) {
300                                 return object.getLastModified() != null ? formatter.format(object.getLastModified()) : "";
301                         }
302                 };
303         aheader = new SortableHeader("Last Modified");
304                 celltable.addColumn(aColumn, aheader);
305                 allHeaders.add(aheader);
306                 aheader.setUpdater(new FileValueUpdater(aheader, "date"));
307                
308                 provider.addDataDisplay(celltable);
309
310                 VerticalPanel vp = new VerticalPanel();
311                 vp.setWidth("100%");
312                 vp.addStyleName("pithos-FileListContainer");
313
314         vp.add(celltable);
315
316                 vp.setCellWidth(celltable, "100%");
317         vp.addHandler(new ContextMenuHandler() {
318             @Override
319             public void onContextMenu(ContextMenuEvent event) {
320                 TreeView tree = app.getSelectedTree();
321                 if (tree != null && (tree.equals(app.getFolderTreeView()) || tree.equals(app.getOtherSharedTreeView()))) {
322                         Folder selectedFolder = app.getSelection();
323                         FileContextMenu contextMenu = new FileContextMenu(app, images, tree, selectedFolder, getSelectedFiles());
324                         int x = event.getNativeEvent().getClientX();
325                         int y = event.getNativeEvent().getClientY();
326                         contextMenu.setPopupPosition(x, y);
327                         contextMenu.show();
328                 }
329             }
330         }, ContextMenuEvent.getType());
331                 initWidget(vp);
332
333                 selectionModel = new MultiSelectionModel<File>(keyProvider);
334
335                 celltable.setSelectionModel(selectionModel, PithosSelectionEventManager.<File> createDefaultManager());
336 //              celltable.setPageSize(Pithos.VISIBLE_FILE_COUNT);
337                 
338                 sinkEvents(Event.ONCONTEXTMENU);
339 //              sinkEvents(Event.ONMOUSEUP);
340 //              sinkEvents(Event.ONMOUSEDOWN);
341 //              sinkEvents(Event.ONCLICK);
342 //              sinkEvents(Event.ONKEYDOWN);
343 //              sinkEvents(Event.ONDBLCLICK);
344                 Pithos.preventIESelection();
345         }
346
347         public List<File> getSelectedFiles() {
348         return new ArrayList<File>(selectionModel.getSelectedSet());
349         }
350         
351 //      @Override
352 //      public void onBrowserEvent(Event event) {
353 //
354 //              if (files == null || files.size() == 0) {
355 //                      if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
356 //                              contextMenu = new FileContextMenu(images, false, true);
357 //                contextMenu.show();
358 //                              event.preventDefault();
359 //                              event.cancelBubble(true);
360 //                      }
361 //                      return;
362 //              }
363 //              if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() != 0) {
364 //                      GWT.log("*****GOING TO SHOW CONTEXT MENU ****", null);
365 //                      contextMenu =  new FileContextMenu(images, false, false);
366 //                      contextMenu = contextMenu.onEvent(event);
367 //                      event.cancelBubble(true);
368 //                      event.preventDefault();
369 //              } else if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
370 //                      contextMenu = new FileContextMenu(images, false, true);
371 //                      contextMenu = contextMenu.onEmptyEvent(event);
372 //                      event.cancelBubble(true);
373 //                      event.preventDefault();
374 //              } else if (DOM.eventGetType(event) == Event.ONDBLCLICK)
375 //                      if (getSelectedFiles().size() == 1) {
376 //                              Pithos app = app;
377 //                              File file = getSelectedFiles().get(0);
378 //                              Window.open(file.getUri(), "_blank", "");
379 //                              event.preventDefault();
380 //                              return;
381 //                      }
382 //              super.onBrowserEvent(event);
383 //      }
384
385         /**
386          * Update the display of the file list.
387          */
388         void update(@SuppressWarnings("unused") boolean sort) {
389                 showCellTable();
390         }
391
392         /**
393          * Return the proper icon based on the MIME type of the file.
394          *
395          * @param file
396          * @return the icon
397          */
398         protected ImageResource getFileIcon(File file) {
399                 String mimetype = file.getContentType();
400                 boolean shared = file.isShared();
401                 if (mimetype == null)
402                         return shared ? images.documentShared() : images.document();
403                 mimetype = mimetype.toLowerCase();
404                 if (mimetype.startsWith("application/pdf"))
405                         return shared ? images.pdfShared() : images.pdf();
406                 else if (mimetype.endsWith("excel"))
407                         return shared ? images.spreadsheetShared() : images.spreadsheet();
408                 else if (mimetype.endsWith("msword"))
409                         return shared ? images.wordprocessorShared() : images.wordprocessor();
410                 else if (mimetype.endsWith("powerpoint"))
411                         return shared ? images.presentationShared() : images.presentation();
412                 else if (mimetype.startsWith("application/zip") ||
413                                         mimetype.startsWith("application/gzip") ||
414                                         mimetype.startsWith("application/x-gzip") ||
415                                         mimetype.startsWith("application/x-tar") ||
416                                         mimetype.startsWith("application/x-gtar"))
417                         return shared ? images.zipShared() : images.zip();
418                 else if (mimetype.startsWith("text/html"))
419                         return shared ? images.htmlShared() : images.html();
420                 else if (mimetype.startsWith("text/plain"))
421                         return shared ? images.txtShared() : images.txt();
422                 else if (mimetype.startsWith("image/"))
423                         return shared ? images.imageShared() : images.image();
424                 else if (mimetype.startsWith("video/"))
425                         return shared ? images.videoShared() : images.video();
426                 else if (mimetype.startsWith("audio/"))
427                         return shared ? images.audioShared() : images.audio();
428                 return shared ? images.documentShared() : images.document();
429         }
430
431         /**
432          * Fill the file cache with data.
433          */
434         public void setFiles(final List<File> _files) {
435                 files = new ArrayList<File>();
436         for (File fres : _files)
437                         files.add(fres);
438                 Collections.sort(files, new Comparator<File>() {
439
440                         @Override
441                         public int compare(File arg0, File arg1) {
442                                 return arg0.getName().compareTo(arg1.getName());
443                         }
444
445                 });
446                 folderFileCount = files.size();
447                 
448                 nameHeader.setSorted(true);
449                 nameHeader.toggleReverseSort();
450                 for (SortableHeader otherHeader : allHeaders) {
451                 if (otherHeader != nameHeader) {
452                     otherHeader.setSorted(false);
453                     otherHeader.setReverseSort(true);
454                 }
455             }
456
457         provider.setList(files);
458         selectionModel.clear();
459         app.showFolderStatistics(folderFileCount);
460         celltable.setPageSize(folderFileCount);
461         }
462
463         /**
464          * Does the list contains the requested filename
465          *
466          * @param fileName
467          * @return true/false
468          */
469         public boolean contains(String fileName) {
470                 for (int i = 0; i < files.size(); i++)
471                         if (files.get(i).getName().equals(fileName))
472                                 return true;
473                 return false;
474         }
475
476         public void clearSelectedRows() {
477                 Iterator<File> it = selectionModel.getSelectedSet().iterator();
478                 while(it.hasNext()){
479                         selectionModel.setSelected(it.next(),false);
480                 }
481         }
482         
483         /**
484          *
485          */
486         public void selectAllRows() {
487                 Iterator<File> it = provider.getList().iterator();
488                 while(it.hasNext()){
489                         selectionModel.setSelected(it.next(),true);
490                 }
491         }
492
493         protected void sortFiles(final String sortingProperty, final boolean sortingType){
494                 Collections.sort(files, new Comparator<File>() {
495
496             @Override
497             public int compare(File arg0, File arg1) {
498                     if (sortingType){
499                             if (sortingProperty.equals("version")) {
500                                     return arg0.getVersion() - arg1.getVersion();
501                             } else if (sortingProperty.equals("owner")) {
502                                     return arg0.getOwner().compareTo(arg1.getOwner());
503                             } else if (sortingProperty.equals("date")) {
504                                         if (arg0.getLastModified() != null && arg1.getLastModified() != null)
505                                                 return arg0.getLastModified().compareTo(arg1.getLastModified());
506                                         return 0;
507                             } else if (sortingProperty.equals("size")) {
508                                     return (int) (arg0.getBytes() - arg1.getBytes());
509                             } else if (sortingProperty.equals("name")) {
510                                     return arg0.getName().compareTo(arg1.getName());
511                             } else if (sortingProperty.equals("path")) {
512                                     return arg0.getUri().compareTo(arg1.getUri());
513                             } else {
514                                     return arg0.getName().compareTo(arg1.getName());
515                             }
516                     }
517                     else if (sortingProperty.equals("version")) {
518                             
519                             return arg1.getVersion() - arg0.getVersion();
520                     } else if (sortingProperty.equals("owner")) {
521                             
522                             return arg1.getOwner().compareTo(arg0.getOwner());
523                     } else if (sortingProperty.equals("date")) {
524                             
525                             return arg1.getLastModified().compareTo(arg0.getLastModified());
526                     } else if (sortingProperty.equals("size")) {
527                             return (int) (arg1.getBytes() - arg0.getBytes());
528                     } else if (sortingProperty.equals("name")) {
529                             
530                             return arg1.getName().compareTo(arg0.getName());
531                     } else if (sortingProperty.equals("path")) {
532                             
533                             return arg1.getUri().compareTo(arg0.getUri());
534                     } else {
535                             
536                             return arg1.getName().compareTo(arg0.getName());
537                     }
538             }
539
540                 });
541         }
542         
543         final class FileValueUpdater implements ValueUpdater<String>{
544                 private String property;
545                 private SortableHeader header;
546                 /**
547                  * 
548                  */
549                 public FileValueUpdater(SortableHeader header,String property) {
550                         this.property=property;
551                         this.header=header;
552                 }
553                 @Override
554                 public void update(@SuppressWarnings("unused") String value) {
555                         header.setSorted(true);
556                         header.toggleReverseSort();
557
558                 for (SortableHeader otherHeader : allHeaders) {
559                   if (otherHeader != header) {
560                     otherHeader.setSorted(false);
561                     otherHeader.setReverseSort(true);
562                   }
563                 }
564                 celltable.redrawHeaders();
565                 sortFiles(property, header.getReverseSort());
566                 FileList.this.update(true);                     
567                 }
568                 
569         }
570
571         /**
572          * Shows the files in the cellTable 
573      */
574         private void showCellTable(){
575                 provider.setList(files);
576                 
577                 provider.refresh();
578                 
579                 //celltable.redraw();
580                 celltable.redrawHeaders();              
581         }
582 }