2 * Copyright 2011 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
36 package gr.grnet.pithos.web.client;
38 import com.google.gwt.event.dom.client.ContextMenuEvent;
39 import com.google.gwt.event.dom.client.ContextMenuHandler;
41 import com.google.gwt.user.cellview.client.Column;
42 import gr.grnet.pithos.web.client.commands.UploadFileCommand;
43 import gr.grnet.pithos.web.client.foldertree.File;
44 import gr.grnet.pithos.web.client.foldertree.Folder;
45 import gr.grnet.pithos.web.client.foldertree.FolderTreeView;
47 import java.util.ArrayList;
48 import java.util.Collections;
49 import java.util.Comparator;
50 import java.util.Iterator;
51 import java.util.List;
53 import com.google.gwt.cell.client.ImageResourceCell;
54 import com.google.gwt.cell.client.SafeHtmlCell;
55 import com.google.gwt.cell.client.TextCell;
56 import com.google.gwt.cell.client.ValueUpdater;
57 import com.google.gwt.core.client.GWT;
58 import com.google.gwt.dom.client.Style.Cursor;
59 import com.google.gwt.event.dom.client.ClickEvent;
60 import com.google.gwt.event.dom.client.ClickHandler;
61 import com.google.gwt.i18n.client.DateTimeFormat;
62 import com.google.gwt.resources.client.ClientBundle;
63 import com.google.gwt.resources.client.ImageResource;
64 import com.google.gwt.safehtml.client.SafeHtmlTemplates;
65 import com.google.gwt.safehtml.shared.SafeHtml;
66 import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
67 import com.google.gwt.user.cellview.client.CellTable;
68 import com.google.gwt.user.client.Event;
69 import com.google.gwt.user.client.ui.AbstractImagePrototype;
70 import com.google.gwt.user.client.ui.Button;
71 import com.google.gwt.user.client.ui.Composite;
72 import com.google.gwt.user.client.ui.HorizontalPanel;
73 import com.google.gwt.user.client.ui.VerticalPanel;
74 import com.google.gwt.view.client.ListDataProvider;
75 import com.google.gwt.view.client.MultiSelectionModel;
76 import com.google.gwt.view.client.ProvidesKey;
77 import com.google.gwt.view.client.SelectionChangeEvent;
78 import com.google.gwt.view.client.SelectionChangeEvent.Handler;
81 * A composite that displays the list of files in a particular folder.
83 public class FileList extends Composite {
85 ListDataProvider<File> provider = new ListDataProvider<File>();
88 * The styles applied to the table.
90 interface TableStyle extends CellTable.Style {
93 interface TableResources extends CellTable.Resources {
94 @Source({CellTable.Style.DEFAULT_CSS, "GssCellTable.css"})
95 TableStyle cellTableStyle();
98 static interface Templates extends SafeHtmlTemplates {
99 Templates INSTANCE = GWT.create(Templates.class);
101 @Template("<div id='dragHelper' style='border:1px solid black; background-color:#ffffff; color:black; width:150px;z-index:100'></div>")
102 SafeHtml outerHelper();
104 @Template("<span id='{0}'>{0}</span>")
105 public SafeHtml filenameSpan(String filename);
107 @Template("<a href='{0}' title='{1}' rel='lytebox[mnf]' onclick='myLytebox.start(this, false, false); return false;'>(view)</a>")
108 public SafeHtml viewLink(String link, String title);
110 @Template("<table><tr><td rowspan='3'>{0}</td><td style='font-size:95%;' id='{1}'>{1}</td></tr><tr><td>{2}</td></tr></table>")
111 public SafeHtml rendelContactCell(String imageHtml, String name, String fileSize);
113 @Template("<span id='{0}' class='{1}'>{2}</span>")
114 public SafeHtml spanWithIdAndClass(String id, String cssClass, String content);
117 private final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
120 * Specifies that the images available for this composite will be the ones
121 * available in FileContextMenu.
123 public interface Images extends ClientBundle,FileContextMenu.Images, FolderTreeView.Images {
125 @Source("gr/grnet/pithos/resources/blank.gif")
126 ImageResource blank();
128 @Source("gr/grnet/pithos/resources/asc.png")
131 @Source("gr/grnet/pithos/resources/desc.png")
132 ImageResource desc();
134 @Source("gr/grnet/pithos/resources/mimetypes/document_shared.png")
135 ImageResource documentShared();
137 @Source("gr/grnet/pithos/resources/mimetypes/kcmfontinst.png")
138 ImageResource wordprocessor();
140 @Source("gr/grnet/pithos/resources/mimetypes/log.png")
141 ImageResource spreadsheet();
143 @Source("gr/grnet/pithos/resources/mimetypes/kpresenter_kpr.png")
144 ImageResource presentation();
146 @Source("gr/grnet/pithos/resources/mimetypes/acroread.png")
149 @Source("gr/grnet/pithos/resources/mimetypes/image.png")
150 ImageResource image();
152 @Source("gr/grnet/pithos/resources/mimetypes/video2.png")
153 ImageResource video();
155 @Source("gr/grnet/pithos/resources/mimetypes/knotify.png")
156 ImageResource audio();
158 @Source("gr/grnet/pithos/resources/mimetypes/html.png")
159 ImageResource html();
161 @Source("gr/grnet/pithos/resources/mimetypes/txt.png")
164 @Source("gr/grnet/pithos/resources/mimetypes/ark2.png")
167 @Source("gr/grnet/pithos/resources/mimetypes/kcmfontinst_shared.png")
168 ImageResource wordprocessorShared();
170 @Source("gr/grnet/pithos/resources/mimetypes/log_shared.png")
171 ImageResource spreadsheetShared();
173 @Source("gr/grnet/pithos/resources/mimetypes/kpresenter_kpr_shared.png")
174 ImageResource presentationShared();
176 @Source("gr/grnet/pithos/resources/mimetypes/acroread_shared.png")
177 ImageResource pdfShared();
179 @Source("gr/grnet/pithos/resources/mimetypes/image_shared.png")
180 ImageResource imageShared();
182 @Source("gr/grnet/pithos/resources/mimetypes/video2_shared.png")
183 ImageResource videoShared();
185 @Source("gr/grnet/pithos/resources/mimetypes/knotify_shared.png")
186 ImageResource audioShared();
188 @Source("gr/grnet/pithos/resources/mimetypes/html_shared.png")
189 ImageResource htmlShared();
191 @Source("gr/grnet/pithos/resources/mimetypes/txt_shared.png")
192 ImageResource txtShared();
194 @Source("gr/grnet/pithos/resources/mimetypes/ark2_shared.png")
195 ImageResource zipShared();
200 * The number of files in this folder.
207 long folderTotalSize;
210 * A cache of the files in the list.
212 private List<File> files;
215 * The widget's image bundle.
217 private final Images images;
219 private CellTable<File> celltable;
221 private final MultiSelectionModel<File> selectionModel;
223 private final List<SortableHeader> allHeaders = new ArrayList<SortableHeader>();
225 SortableHeader nameHeader;
227 FolderTreeView treeView;
232 * Construct the file list widget. This entails setting up the widget
233 * layout, fetching the number of files in the current folder from the
234 * server and filling the local file cache of displayed files with data from
235 * the server, as well.
239 public FileList(final Pithos _app, Images _images, FolderTreeView _treeView) {
242 this.treeView = _treeView;
244 CellTable.Resources resources = GWT.create(TableResources.class);
246 ProvidesKey<File> keyProvider = new ProvidesKey<File>(){
249 public Object getKey(File item) {
250 return item.getUri();
254 celltable = new CellTable<File>(10, resources, keyProvider);
255 celltable.setWidth("100%");
256 celltable.setStyleName("pithos-List");
258 Column<File, ImageResource> status = new Column<File, ImageResource>(new ImageResourceCell() {
260 public boolean handlesSelection() {
266 public ImageResource getValue(File entity) {
267 return getFileIcon(entity);
270 celltable.addColumn(status,"");
272 final Column<File,SafeHtml> nameColumn = new Column<File,SafeHtml>(new SafeHtmlCell()) {
275 public SafeHtml getValue(File object) {
276 SafeHtmlBuilder sb = new SafeHtmlBuilder();
277 sb.append(Templates.INSTANCE.filenameSpan(object.getName()));
278 if (object.getContentType().endsWith("png") || object.getContentType().endsWith("gif") || object.getContentType().endsWith("jpeg")) {
279 sb.appendHtmlConstant(" ")
280 .append(Templates.INSTANCE.viewLink(object.getUri(), object.getOwner() + " : " + object.getPath() + object.getName()));
283 return sb.toSafeHtml();
287 celltable.addColumn(nameColumn, nameHeader = new SortableHeader("Name"));
288 allHeaders.add(nameHeader);
289 nameHeader.setUpdater(new FileValueUpdater(nameHeader, "name"));
291 celltable.redrawHeaders();
293 Column<File,String> aColumn = new Column<File,String>(new TextCell()) {
295 public String getValue(File object) {
296 // TODO Auto-generated method stub
297 return object.getSizeAsString();
300 SortableHeader aheader = new SortableHeader("Size");
301 celltable.addColumn(aColumn, aheader);
302 allHeaders.add(aheader);
303 aheader.setUpdater(new FileValueUpdater(aheader, "size"));
305 aColumn = new Column<File,String>(new TextCell()) {
307 public String getValue(File object) {
308 return formatter.format(object.getLastModified());
311 aheader = new SortableHeader("Last Modified");
312 celltable.addColumn(aColumn, aheader);
313 allHeaders.add(aheader);
314 aheader.setUpdater(new FileValueUpdater(aheader, "date"));
316 provider.addDataDisplay(celltable);
318 VerticalPanel vp = new VerticalPanel();
323 vp.setCellWidth(celltable, "100%");
324 vp.addHandler(new ContextMenuHandler() {
326 public void onContextMenu(ContextMenuEvent event) {
327 Folder selectedFolder = treeView.getSelection();
328 if (!selectedFolder.isTrash()) {
329 FileContextMenu contextMenu = new FileContextMenu(app, images, selectedFolder, getSelectedFiles(), false);
330 int x = event.getNativeEvent().getClientX();
331 int y = event.getNativeEvent().getClientY();
332 contextMenu.setPopupPosition(x, y);
336 }, ContextMenuEvent.getType());
339 selectionModel = new MultiSelectionModel<File>(keyProvider);
341 celltable.setSelectionModel(selectionModel, GSSSelectionEventManager.<File> createDefaultManager());
342 // celltable.setPageSize(Pithos.VISIBLE_FILE_COUNT);
344 sinkEvents(Event.ONCONTEXTMENU);
345 // sinkEvents(Event.ONMOUSEUP);
346 // sinkEvents(Event.ONMOUSEDOWN);
347 // sinkEvents(Event.ONCLICK);
348 // sinkEvents(Event.ONKEYDOWN);
349 // sinkEvents(Event.ONDBLCLICK);
350 Pithos.preventIESelection();
353 public List<File> getSelectedFiles() {
354 return new ArrayList<File>(selectionModel.getSelectedSet());
358 // public void onBrowserEvent(Event event) {
360 // if (files == null || files.size() == 0) {
361 // if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
362 // contextMenu = new FileContextMenu(images, false, true);
363 // contextMenu.show();
364 // event.preventDefault();
365 // event.cancelBubble(true);
369 // if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() != 0) {
370 // GWT.log("*****GOING TO SHOW CONTEXT MENU ****", null);
371 // contextMenu = new FileContextMenu(images, false, false);
372 // contextMenu = contextMenu.onEvent(event);
373 // event.cancelBubble(true);
374 // event.preventDefault();
375 // } else if (DOM.eventGetType(event) == Event.ONCONTEXTMENU && getSelectedFiles().size() == 0) {
376 // contextMenu = new FileContextMenu(images, false, true);
377 // contextMenu = contextMenu.onEmptyEvent(event);
378 // event.cancelBubble(true);
379 // event.preventDefault();
380 // } else if (DOM.eventGetType(event) == Event.ONDBLCLICK)
381 // if (getSelectedFiles().size() == 1) {
383 // File file = getSelectedFiles().get(0);
384 // Window.open(file.getUri(), "_blank", "");
385 // event.preventDefault();
388 // super.onBrowserEvent(event);
392 * Update the display of the file list.
394 void update(boolean sort) {
399 * Return the proper icon based on the MIME type of the file.
404 private ImageResource getFileIcon(File file) {
405 String mimetype = file.getContentType();
406 boolean shared = file.isShared();
407 if (mimetype == null)
408 return shared ? images.documentShared() : images.document();
409 mimetype = mimetype.toLowerCase();
410 if (mimetype.startsWith("application/pdf"))
411 return shared ? images.pdfShared() : images.pdf();
412 else if (mimetype.endsWith("excel"))
413 return shared ? images.spreadsheetShared() : images.spreadsheet();
414 else if (mimetype.endsWith("msword"))
415 return shared ? images.wordprocessorShared() : images.wordprocessor();
416 else if (mimetype.endsWith("powerpoint"))
417 return shared ? images.presentationShared() : images.presentation();
418 else if (mimetype.startsWith("application/zip") ||
419 mimetype.startsWith("application/gzip") ||
420 mimetype.startsWith("application/x-gzip") ||
421 mimetype.startsWith("application/x-tar") ||
422 mimetype.startsWith("application/x-gtar"))
423 return shared ? images.zipShared() : images.zip();
424 else if (mimetype.startsWith("text/html"))
425 return shared ? images.htmlShared() : images.html();
426 else if (mimetype.startsWith("text/plain"))
427 return shared ? images.txtShared() : images.txt();
428 else if (mimetype.startsWith("image/"))
429 return shared ? images.imageShared() : images.image();
430 else if (mimetype.startsWith("video/"))
431 return shared ? images.videoShared() : images.video();
432 else if (mimetype.startsWith("audio/"))
433 return shared ? images.audioShared() : images.audio();
434 return shared ? images.documentShared() : images.document();
438 * Fill the file cache with data.
440 public void setFiles(final List<File> _files) {
441 files = new ArrayList<File>();
442 for (File fres : _files)
443 if (!fres.isInTrash())
445 Collections.sort(files, new Comparator<File>() {
448 public int compare(File arg0, File arg1) {
449 return arg0.getName().compareTo(arg1.getName());
453 folderFileCount = files.size();
455 nameHeader.setSorted(true);
456 nameHeader.toggleReverseSort();
457 for (SortableHeader otherHeader : allHeaders) {
458 if (otherHeader != nameHeader) {
459 otherHeader.setSorted(false);
460 otherHeader.setReverseSort(true);
464 provider.setList(files);
465 selectionModel.clear();
469 * Does the list contains the requested filename
474 public boolean contains(String fileName) {
475 for (int i = 0; i < files.size(); i++)
476 if (files.get(i).getName().equals(fileName))
481 public void clearSelectedRows() {
482 Iterator<File> it = selectionModel.getSelectedSet().iterator();
484 selectionModel.setSelected(it.next(),false);
491 public void selectAllRows() {
492 Iterator<File> it = provider.getList().iterator();
494 selectionModel.setSelected(it.next(),true);
498 private void sortFiles(final String sortingProperty, final boolean sortingType){
499 Collections.sort(files, new Comparator<File>() {
502 public int compare(File arg0, File arg1) {
503 AbstractImagePrototype descPrototype = AbstractImagePrototype.create(images.desc());
504 AbstractImagePrototype ascPrototype = AbstractImagePrototype.create(images.asc());
506 if (sortingProperty.equals("version")) {
507 return arg0.getVersion() - arg1.getVersion();
508 } else if (sortingProperty.equals("owner")) {
509 return arg0.getOwner().compareTo(arg1.getOwner());
510 } else if (sortingProperty.equals("date")) {
511 return arg0.getLastModified().compareTo(arg1.getLastModified());
512 } else if (sortingProperty.equals("size")) {
513 return (int) (arg0.getBytes() - arg1.getBytes());
514 } else if (sortingProperty.equals("name")) {
515 return arg0.getName().compareTo(arg1.getName());
516 } else if (sortingProperty.equals("path")) {
517 return arg0.getUri().compareTo(arg1.getUri());
519 return arg0.getName().compareTo(arg1.getName());
522 else if (sortingProperty.equals("version")) {
524 return arg1.getVersion() - arg0.getVersion();
525 } else if (sortingProperty.equals("owner")) {
527 return arg1.getOwner().compareTo(arg0.getOwner());
528 } else if (sortingProperty.equals("date")) {
530 return arg1.getLastModified().compareTo(arg0.getLastModified());
531 } else if (sortingProperty.equals("size")) {
532 return (int) (arg1.getBytes() - arg0.getBytes());
533 } else if (sortingProperty.equals("name")) {
535 return arg1.getName().compareTo(arg0.getName());
536 } else if (sortingProperty.equals("path")) {
538 return arg1.getUri().compareTo(arg0.getUri());
541 return arg1.getName().compareTo(arg0.getName());
548 final class FileValueUpdater implements ValueUpdater<String>{
549 private String property;
550 private SortableHeader header;
554 public FileValueUpdater(SortableHeader header,String property) {
555 this.property=property;
559 public void update(String value) {
560 header.setSorted(true);
561 header.toggleReverseSort();
563 for (SortableHeader otherHeader : allHeaders) {
564 if (otherHeader != header) {
565 otherHeader.setSorted(false);
566 otherHeader.setReverseSort(true);
569 celltable.redrawHeaders();
570 sortFiles(property, header.getReverseSort());
571 FileList.this.update(true);
577 * Shows the files in the cellTable
579 private void showCellTable(){
580 provider.setList(files);
584 //celltable.redraw();
585 celltable.redrawHeaders();