teichmann@5835: package org.dive4elements.river.client.client.ui; ingo@4: sascha@3473: import com.google.gwt.core.client.GWT; ingo@226: import com.google.gwt.i18n.client.DateTimeFormat; ingo@585: import com.google.gwt.user.client.Timer; ingo@97: import com.google.gwt.user.client.rpc.AsyncCallback; christian@4184: ingo@226: import com.smartgwt.client.types.Alignment; christian@3709: import com.smartgwt.client.types.Autofit; ingo@597: import com.smartgwt.client.types.ListGridEditEvent; ingo@226: import com.smartgwt.client.types.ListGridFieldType; christian@3709: import com.smartgwt.client.types.Overflow; ingo@606: import com.smartgwt.client.types.SelectionStyle; ingo@606: import com.smartgwt.client.types.SortArrow; ingo@226: import com.smartgwt.client.types.SortDirection; sascha@3473: import com.smartgwt.client.types.VerticalAlignment; ingo@606: import com.smartgwt.client.util.BooleanCallback; ingo@220: import com.smartgwt.client.util.SC; ingo@4: import com.smartgwt.client.widgets.Canvas; rrenkert@5144: import com.smartgwt.client.widgets.IconButton; ingo@4: import com.smartgwt.client.widgets.Label; rrenkert@5144: import com.smartgwt.client.widgets.events.ClickEvent; bjoern@4605: import com.smartgwt.client.widgets.events.VisibilityChangedEvent; bjoern@4605: import com.smartgwt.client.widgets.events.VisibilityChangedHandler; ingo@226: import com.smartgwt.client.widgets.grid.CellFormatter; ingo@606: import com.smartgwt.client.widgets.grid.HoverCustomizer; ingo@4: import com.smartgwt.client.widgets.grid.ListGrid; ingo@4: import com.smartgwt.client.widgets.grid.ListGridField; ingo@97: import com.smartgwt.client.widgets.grid.ListGridRecord; ingo@597: import com.smartgwt.client.widgets.grid.events.CellClickEvent; ingo@597: import com.smartgwt.client.widgets.grid.events.CellClickHandler; ingo@253: import com.smartgwt.client.widgets.grid.events.CellDoubleClickEvent; ingo@253: import com.smartgwt.client.widgets.grid.events.CellDoubleClickHandler; ingo@597: import com.smartgwt.client.widgets.grid.events.EditCompleteEvent; ingo@597: import com.smartgwt.client.widgets.grid.events.EditCompleteHandler; sascha@3473: import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickEvent; sascha@3473: import com.smartgwt.client.widgets.grid.events.HeaderDoubleClickHandler; ingo@220: import com.smartgwt.client.widgets.grid.events.RowContextClickEvent; ingo@220: import com.smartgwt.client.widgets.grid.events.RowContextClickHandler; bjoern@4559: import com.smartgwt.client.widgets.layout.HLayout; ingo@4: import com.smartgwt.client.widgets.layout.VLayout; ingo@220: import com.smartgwt.client.widgets.menu.Menu; ingo@220: import com.smartgwt.client.widgets.menu.MenuItem; sascha@778: import com.smartgwt.client.widgets.menu.MenuItemSeparator; sascha@3473: import com.smartgwt.client.widgets.menu.events.ClickHandler; sascha@3473: import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent; ingo@4: teichmann@5835: import org.dive4elements.river.client.client.Config; teichmann@5835: import org.dive4elements.river.client.client.FLYS; teichmann@5835: import org.dive4elements.river.client.client.FLYSConstants; teichmann@5835: import org.dive4elements.river.client.client.event.CollectionChangeEvent; teichmann@5835: import org.dive4elements.river.client.client.event.CollectionChangeHandler; teichmann@5835: import org.dive4elements.river.client.client.event.FilterHandler; teichmann@5835: import org.dive4elements.river.client.client.event.RangeFilterEvent; teichmann@5835: import org.dive4elements.river.client.client.event.StringFilterEvent; teichmann@5835: import org.dive4elements.river.client.client.services.AddArtifactService; teichmann@5835: import org.dive4elements.river.client.client.services.AddArtifactServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.ArtifactService; teichmann@5835: import org.dive4elements.river.client.client.services.ArtifactServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.CreateCollectionService; teichmann@5835: import org.dive4elements.river.client.client.services.CreateCollectionServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.DeleteCollectionService; teichmann@5835: import org.dive4elements.river.client.client.services.DeleteCollectionServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.DescribeCollectionService; teichmann@5835: import org.dive4elements.river.client.client.services.DescribeCollectionServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.GetArtifactService; teichmann@5835: import org.dive4elements.river.client.client.services.GetArtifactServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.SetCollectionNameService; teichmann@5835: import org.dive4elements.river.client.client.services.SetCollectionNameServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.SetCollectionTTLService; teichmann@5835: import org.dive4elements.river.client.client.services.SetCollectionTTLServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.UserCollectionsService; teichmann@5835: import org.dive4elements.river.client.client.services.UserCollectionsServiceAsync; teichmann@5835: import org.dive4elements.river.client.shared.model.Artifact; teichmann@5835: import org.dive4elements.river.client.shared.model.Collection; teichmann@5835: import org.dive4elements.river.client.shared.model.CollectionItem; teichmann@5835: import org.dive4elements.river.client.shared.model.CollectionRecord; teichmann@5835: import org.dive4elements.river.client.shared.model.Recommendation; teichmann@5835: import org.dive4elements.river.client.shared.model.User; sascha@3473: sascha@3473: import java.util.ArrayList; sascha@3473: import java.util.Date; sascha@3473: import java.util.List; sascha@3473: import java.util.Map; sascha@3473: import java.util.MissingResourceException; sascha@3473: ingo@4: ingo@4: /** ingo@4: * The project list shows a list of projects of a specific user. ingo@4: * ingo@4: * @author Ingo Weinzierl ingo@4: */ ingo@97: public class ProjectList ingo@97: extends VLayout bjoern@4605: implements CollectionChangeHandler, EditCompleteHandler, FilterHandler, bjoern@4605: VisibilityChangedHandler ingo@97: { ingo@585: /** Interval to refresh the user's projects.*/ ingo@585: public static final int UPDATE_INTERVAL = 30000; ingo@585: ingo@585: /** Min Interval to refresh the user's projects.*/ ingo@585: public static final int MIN_UPDATE_INTERVAL = 5000; ingo@585: ingo@606: /** The initial width of this panel.*/ ingo@606: public static final int MIN_WIDTH = 300; ingo@606: ingo@613: /** The max length for new project names.*/ ingo@613: public static final int MAX_NAME_LENGTH = 50; ingo@613: ingo@606: public static final String COLUMN_DATE_WIDTH = "100px"; ingo@606: ingo@606: public static final String COLUMN_TITLE_WIDTH = "*"; ingo@606: ingo@606: public static final String COLUMN_FAVORITE_WIDTH = "75px"; ingo@606: ingo@4: /** The interface that provides i18n messages. */ christian@3501: private final FLYSConstants messages = GWT.create(FLYSConstants.class); ingo@4: ingo@97: /** The UserService used to retrieve information about the current user. */ ingo@97: protected UserCollectionsServiceAsync userCollectionsService = ingo@97: GWT.create(UserCollectionsService.class); ingo@97: ingo@598: /** The service used to set the name of a project.*/ ingo@598: protected SetCollectionNameServiceAsync nameService = ingo@598: GWT.create(SetCollectionNameService.class); ingo@598: ingo@598: /** The service used to set the name of a project.*/ ingo@598: protected SetCollectionTTLServiceAsync ttlService = ingo@598: GWT.create(SetCollectionTTLService.class); ingo@598: ingo@598: /** The service used to set the name of a project.*/ ingo@598: protected DeleteCollectionServiceAsync deleteService = ingo@598: GWT.create(DeleteCollectionService.class); ingo@598: raimund@887: /** The DescribeCollectionService used to update the existing collection. */ raimund@887: protected DescribeCollectionServiceAsync describeCollectionService = raimund@887: GWT.create(DescribeCollectionService.class); raimund@887: raimund@887: /** The ArtifactService used to communicate with the Artifact server. */ raimund@887: protected ArtifactServiceAsync createArtifactService = raimund@887: GWT.create(ArtifactService.class); raimund@887: raimund@887: /** The ArtifactService used to communicate with the Artifact server. */ raimund@887: protected CreateCollectionServiceAsync createCollectionService = raimund@887: GWT.create(CreateCollectionService.class); raimund@887: raimund@887: /** The AddArtifactService used to add an artifact to a collection. */ raimund@887: protected AddArtifactServiceAsync addArtifactService = raimund@887: GWT.create(AddArtifactService.class); raimund@887: felix@3380: /** The GetArtifactService used to open an existing collection. */ felix@3380: protected GetArtifactServiceAsync getArtifactService = felix@3380: GWT.create(GetArtifactService.class); felix@3380: ingo@225: /** A pointer to the FLYS instance.*/ ingo@225: protected FLYS flys; ingo@225: ingo@4: /** The user whose projects should be displayed.*/ ingo@4: protected User user; ingo@4: ingo@4: /** The grid that contains the project rows.*/ ingo@4: protected ListGrid grid; ingo@4: raimund@885: /** All user collections.*/ raimund@885: protected List collections; raimund@885: raimund@887: /** The collection to clone*/ raimund@887: protected Collection cloneCollection; raimund@887: felix@3380: /** The message class that provides i18n strings.*/ felix@3380: protected FLYSConstants MSG = GWT.create(FLYSConstants.class); felix@3380: bjoern@4691: private String filter; bjoern@4691: felix@3380: ingo@4: /** ingo@4: * The default constructor that creates a new ProjectList for a specific ingo@4: * user. ingo@4: * ingo@4: * @param user The user. ingo@4: */ ingo@225: public ProjectList(FLYS flys, User user) { felix@3531: super(); ingo@225: this.flys = flys; ingo@4: this.user = user; ingo@4: christian@3501: collections = new ArrayList(); ingo@226: grid = new ListGrid(); ingo@4: initGrid(); ingo@97: init(); ingo@585: initTimer(); ingo@4: ingo@597: grid.addEditCompleteHandler(this); ingo@597: bjoern@4605: addVisibilityChangedHandler(this); bjoern@4605: ingo@97: updateUserCollections(); ingo@4: } ingo@4: ingo@4: ingo@4: protected void initGrid() { ingo@606: grid.setWidth100(); christian@3709: grid.setAutoFitData(Autofit.VERTICAL); ingo@606: grid.setAutoFitMaxWidth(500); ingo@4: grid.setEmptyMessage(messages.no_projects()); ingo@4: grid.setLoadingDataMessage(messages.load_projects()); ingo@606: grid.setCanEdit(false); ingo@606: grid.setEditEvent(ListGridEditEvent.NONE); ingo@606: grid.setShowHeaderContextMenu(false); ingo@606: grid.setShowSortArrow(SortArrow.NONE); ingo@226: grid.setSortDirection(SortDirection.DESCENDING); ingo@226: grid.setSortField(0); ingo@606: grid.setSelectionType(SelectionStyle.SINGLE); raimund@877: grid.setCanReorderFields(false); ingo@2446: grid.setLeaveScrollbarGap(false); christian@3709: grid.setBorder("0px"); ingo@4: ingo@226: ListGridField date = buildDateField(); ingo@226: ListGridField name = buildNameField(); ingo@587: ListGridField fav = buildFavoriteField(); ingo@4: ingo@587: grid.setFields(date, name, fav); ingo@220: raimund@1391: grid.addHeaderDoubleClickHandler(new HeaderDoubleClickHandler() { christian@3501: @Override raimund@1391: public void onHeaderDoubleClick(HeaderDoubleClickEvent event) { felix@3380: // Cancel the event. raimund@1391: return; raimund@1391: } raimund@1391: }); raimund@1391: felix@3380: // Add a handler to set / unset the favorite state of a project. ingo@597: grid.addCellClickHandler(new CellClickHandler() { christian@3501: @Override ingo@597: public void onCellClick(CellClickEvent event) { ingo@597: if (event.getColNum() != 2) { ingo@597: return; ingo@597: } ingo@597: ingo@597: CollectionRecord r = (CollectionRecord) event.getRecord(); ingo@597: Collection c = r.getCollection(); ingo@597: ingo@597: c.setTTL(c.getTTL() == 0 ? -1 : 0); ingo@597: updateCollectionTTL(c); ingo@597: } ingo@597: }); ingo@597: felix@3380: // Add a handler to open a project. ingo@253: grid.addCellDoubleClickHandler(new CellDoubleClickHandler() { christian@3501: @Override ingo@253: public void onCellDoubleClick(CellDoubleClickEvent e) { ingo@253: CollectionRecord record = (CollectionRecord) e.getRecord(); ingo@253: String uuid = record != null ingo@253: ? record.getCollection().identifier() ingo@253: : ""; ingo@253: getFlys().openProject(uuid); ingo@253: } ingo@253: }); ingo@253: felix@3380: // Add a handler to open a context menu. ingo@220: grid.addRowContextClickHandler(new RowContextClickHandler() { christian@3501: @Override ingo@220: public void onRowContextClick(RowContextClickEvent event) { ingo@220: CollectionRecord record = (CollectionRecord) event.getRecord(); ingo@220: ingo@220: Menu menu = createContextMenu(record); ingo@220: grid.setContextMenu(menu); ingo@220: menu.showContextMenu(); ingo@220: ingo@220: event.cancel(); ingo@220: } ingo@220: }); ingo@220: } ingo@220: ingo@220: ingo@585: /** ingo@585: * Initializes a repeating timer that updates the user's collections. The ingo@585: * interval is specified by the constant UPDATE_INTERVAL. ingo@585: */ ingo@585: protected void initTimer() { ingo@585: Config config = Config.getInstance(); ingo@585: int interval = config.getProjectListUpdateInterval(); ingo@585: ingo@585: interval = interval > MIN_UPDATE_INTERVAL ? interval : UPDATE_INTERVAL; ingo@585: ingo@585: GWT.log("Update project list every " + interval + " milliseconds."); ingo@585: ingo@585: Timer t = new Timer() { ingo@585: @Override ingo@585: public void run() { ingo@585: updateUserCollections(); ingo@585: } ingo@585: }; ingo@585: ingo@585: t.scheduleRepeating(interval); ingo@585: } ingo@585: ingo@585: ingo@225: public FLYS getFlys() { ingo@225: return flys; ingo@225: } ingo@225: ingo@225: ingo@220: /** ingo@220: * Creates a new context menu that interacts with a CollectionRecord. ingo@220: * ingo@220: * @param record The selected record. ingo@220: * ingo@220: * @return the context menu with operations that interact with ingo@220: * record. ingo@220: */ ingo@220: protected Menu createContextMenu(final CollectionRecord record) { ingo@220: Menu menu = new Menu(); ingo@220: ingo@220: MenuItem open = new MenuItem(messages.open_project()); ingo@220: open.addClickHandler(new ClickHandler() { christian@3501: @Override ingo@220: public void onClick(MenuItemClickEvent evt) { ingo@225: getFlys().openProject(record.getCollection().identifier()); ingo@220: } ingo@220: }); ingo@220: ingo@220: MenuItem del = new MenuItem(messages.delete_project()); ingo@220: del.addClickHandler(new ClickHandler() { christian@3501: @Override ingo@220: public void onClick(MenuItemClickEvent evt) { ingo@606: SC.ask(messages.really_delete(), new BooleanCallback() { christian@3501: @Override ingo@606: public void execute(Boolean value) { ingo@606: if (value) { ingo@606: deleteCollection(record.getCollection()); ingo@606: } ingo@606: } ingo@606: }); ingo@220: } ingo@220: }); ingo@220: ingo@597: MenuItem rename = new MenuItem(messages.rename_project()); ingo@597: rename.addClickHandler(new ClickHandler() { christian@3501: @Override ingo@597: public void onClick(MenuItemClickEvent evt) { ingo@597: int row = grid.getRecordIndex(record); ingo@597: grid.startEditing(row, 1, false); ingo@597: } ingo@597: }); ingo@597: raimund@887: MenuItem clone = new MenuItem(messages.clone_project()); raimund@887: clone.addClickHandler(new ClickHandler() { christian@3501: @Override raimund@887: public void onClick(MenuItemClickEvent evt) { raimund@887: cloneProject(record.getCollection()); raimund@887: } raimund@887: }); raimund@887: ingo@220: menu.addItem(open); sascha@778: menu.addItem(rename); raimund@887: menu.addItem(clone); sascha@778: menu.addItem(new MenuItemSeparator()); ingo@220: menu.addItem(del); ingo@220: ingo@220: return menu; ingo@4: } ingo@4: ingo@4: ingo@4: /** ingo@4: * The init() method handles the layout stuff for this widget. ingo@4: */ ingo@4: protected void init() { ingo@606: setWidth(MIN_WIDTH); ingo@606: setMinWidth(MIN_WIDTH); ingo@4: setHeight100(); ingo@4: setShowResizeBar(true); ingo@4: setShowEdges(false); ingo@4: setLayoutMargin(0); raimund@79: setLayoutAlign(VerticalAlignment.TOP); christian@3709: setOverflow(Overflow.AUTO); ingo@4: ingo@4: Label title = new Label(messages.projects()); ingo@4: title.setHeight("20"); ingo@4: title.setMargin(5); ingo@4: title.setWidth100(); bjoern@4559: title.setStyleName("projectHeader"); ingo@4: bjoern@4559: HLayout buttonWrapper = new HLayout(); bjoern@4559: rrenkert@5144: IconButton addButton = new IconButton(""); rrenkert@5144: addButton.setIcon(messages.projectListAdd()); rrenkert@5144: addButton.setTooltip(messages.new_project()); bjoern@4559: addButton.setWidth("30px"); bjoern@4559: rrenkert@5144: IconButton closeButton = new IconButton(""); rrenkert@5144: closeButton.setIcon(messages.projectListMin()); rrenkert@5144: closeButton.setTooltip(messages.projectlist_close()); bjoern@4559: closeButton.setWidth("30px"); bjoern@4559: bjoern@4559: buttonWrapper.addMember(addButton); bjoern@4559: buttonWrapper.addMember(closeButton); bjoern@4559: buttonWrapper.setAlign(Alignment.RIGHT); bjoern@4559: buttonWrapper.setAutoWidth(); bjoern@4559: bjoern@4559: HLayout titleWrapper = new HLayout(); bjoern@4559: titleWrapper.setStyleName("bgBlueMid"); ingo@4: titleWrapper.setWidth100(); raimund@79: titleWrapper.setHeight("20px"); bjoern@4559: titleWrapper.addMember(title); bjoern@4559: titleWrapper.addMember(buttonWrapper); ingo@4: ingo@4: Canvas gridWrapper = new Canvas(); ingo@4: gridWrapper.setPadding(0); ingo@4: titleWrapper.setWidth100(); ingo@4: gridWrapper.addChild(grid); ingo@4: bjoern@4692: TableFilter filterpanel = new TableFilter(); bjoern@4692: filterpanel.setHeight("30px"); bjoern@4692: filterpanel.addFilterHandler(this); bjoern@4692: filterpanel.setBorder("1px solid gray"); raimund@885: ingo@4: addMember(titleWrapper); ingo@4: addMember(gridWrapper); bjoern@4692: addMember(filterpanel); bjoern@4559: bjoern@4559: addButton.addClickHandler( rrenkert@5144: new com.smartgwt.client.widgets.events.ClickHandler() { bjoern@4559: bjoern@4559: @Override bjoern@4559: public void onClick(ClickEvent ev) { bjoern@4559: flys.newProject(); bjoern@4559: } bjoern@4559: }); bjoern@4559: bjoern@4559: closeButton.addClickHandler( rrenkert@5144: new com.smartgwt.client.widgets.events.ClickHandler() { bjoern@4559: bjoern@4559: @Override bjoern@4559: public void onClick(ClickEvent ev) { bjoern@4559: hide(); bjoern@4559: } bjoern@4559: }); raimund@885: } raimund@885: raimund@885: christian@3501: @Override raimund@885: public void onFilterCriteriaChanged(StringFilterEvent event) { raimund@885: String search = event.getFilter(); bjoern@4691: // Filter the records. bjoern@4691: setFilter(search); bjoern@4691: updateGrid(); ingo@4: } ingo@97: ingo@97: christian@3501: @Override raimund@1534: public void onFilterCriteriaChanged(RangeFilterEvent event) { raimund@1534: //Empty. No Ranges to filter. raimund@1534: } raimund@1534: raimund@1534: felix@3531: /** On collection change, update list (probably name change or similar). */ christian@3501: @Override ingo@97: public void onCollectionChange(CollectionChangeEvent event) { ingo@585: if (event.getOldValue() == null) { ingo@585: updateUserCollections(); ingo@585: } ingo@97: } ingo@97: ingo@97: christian@3501: @Override ingo@597: public void onEditComplete(EditCompleteEvent event) { ingo@597: if (event.getColNum() != 1) { ingo@597: return; ingo@597: } ingo@597: ingo@597: int row = event.getRowNum(); ingo@597: ingo@597: CollectionRecord r = (CollectionRecord) grid.getRecord(row); ingo@597: Collection c = r.getCollection(); ingo@597: christian@3501: Map newValues = event.getNewValues(); ingo@597: String name = (String) newValues.get("name"); ingo@597: ingo@613: int maxLength = getMaxNameLength(); ingo@613: int length = name != null ? name.length() : 0; ingo@613: ingo@613: if (length <= 0 || length > maxLength) { ingo@613: String msg = messages.project_name_too_long(); ingo@613: msg = msg.replace("$LEN", String.valueOf(maxLength)); ingo@613: SC.warn(msg); ingo@613: ingo@613: ListGridRecord[] rs = grid.getRecords(); ingo@613: rs[row] = (ListGridRecord) event.getOldRecord(); ingo@613: grid.setRecords(rs); ingo@613: ingo@613: return; ingo@613: } ingo@613: bjoern@4693: updateCollectionName(c, name); ingo@597: } ingo@597: ingo@597: ingo@597: /** ingo@597: * Set the name of the collection c to a new value. If the update ingo@597: * process succeeded, the project list is refreshed. ingo@597: * ingo@597: * @param c The Collection with a new name. bjoern@4693: * @param name Name to set on the collection ingo@597: */ bjoern@4693: private void updateCollectionName(final Collection c, String name) { ingo@597: if (c == null) { ingo@597: return; ingo@597: } ingo@597: bjoern@4693: c.setName(name); bjoern@4693: ingo@597: GWT.log("Update Collection name: " + c.identifier()); ingo@597: GWT.log("=> New name = " + c.getName()); ingo@597: raimund@1425: nameService.setName(c, new AsyncCallback(){ christian@3501: @Override ingo@598: public void onFailure(Throwable caught) { ingo@598: String msg = caught.getMessage(); ingo@598: ingo@598: try { ingo@598: SC.warn(messages.getString(msg)); ingo@598: } ingo@598: catch (MissingResourceException mre) { ingo@598: SC.warn(msg); ingo@598: } ingo@598: } ingo@598: christian@3501: @Override ingo@598: public void onSuccess(Void v) { ingo@598: updateUserCollections(); raimund@896: if(flys.getWorkspace().hasView(c.identifier())) { raimund@896: flys.getWorkspace().updateTitle(c.identifier(), c.getName()); raimund@896: } ingo@598: } ingo@598: }); ingo@597: } ingo@597: ingo@597: ingo@597: /** ingo@597: * Set the ttl of the collection c to a new value. If the update ingo@597: * process succeeded, the project list is refreshed. ingo@597: * ingo@597: * @param c The Collection with a new ttl. ingo@597: */ ingo@597: protected void updateCollectionTTL(Collection c) { ingo@597: if (c == null) { ingo@597: return; ingo@597: } ingo@597: ingo@597: GWT.log("Update Collection TTL: " + c.identifier()); ingo@597: GWT.log("=> New ttl = " + c.getTTL()); ingo@597: raimund@1425: ttlService.setTTL(c, new AsyncCallback() { christian@3501: @Override ingo@598: public void onFailure(Throwable caught) { ingo@598: String msg = caught.getMessage(); ingo@598: ingo@598: try { ingo@598: SC.warn(messages.getString(msg)); ingo@598: } ingo@598: catch (MissingResourceException mre) { ingo@598: SC.warn(msg); ingo@598: } ingo@598: } ingo@598: christian@3501: @Override ingo@598: public void onSuccess(Void v) { ingo@598: updateUserCollections(); ingo@598: } ingo@598: }); ingo@598: } ingo@598: ingo@598: ingo@598: /** ingo@598: * Delete the collection c. ingo@598: * ingo@598: * @param c The Collection that should be deleted. ingo@598: */ christian@3501: public void deleteCollection(final Collection c) { ingo@598: if (c == null) { ingo@598: return; ingo@598: } ingo@598: ingo@598: GWT.log("Delete Collection: " + c.identifier()); ingo@598: raimund@1425: deleteService.delete(c, new AsyncCallback(){ christian@3501: @Override ingo@598: public void onFailure(Throwable caught) { ingo@598: String msg = caught.getMessage(); ingo@598: ingo@598: try { ingo@598: SC.warn(messages.getString(msg)); ingo@598: } ingo@598: catch (MissingResourceException mre) { ingo@598: SC.warn(msg); ingo@598: } ingo@598: } ingo@598: christian@3501: @Override ingo@598: public void onSuccess(Void v) { ingo@600: flys.getWorkspace().destroyProject(c.identifier()); ingo@598: updateUserCollections(); ingo@598: } ingo@598: }); ingo@597: } ingo@597: ingo@597: bjoern@4140: public void updateUserCollections() { ingo@585: GWT.log("==> ProjectList updates user collections!"); ingo@585: ingo@97: Config config = Config.getInstance(); ingo@229: String locale = config.getLocale(); ingo@97: ingo@1493: userCollectionsService.getUserCollections(locale, user.identifier(), ingo@97: new AsyncCallback() { christian@3501: @Override ingo@97: public void onFailure(Throwable caught) { ingo@598: String msg = caught.getMessage(); ingo@598: ingo@598: try { ingo@598: SC.warn(messages.getString(msg)); ingo@598: } ingo@598: catch (MissingResourceException mre) { ingo@598: SC.warn(msg); ingo@598: } ingo@97: } ingo@97: christian@3501: @Override ingo@97: public void onSuccess(Collection[] collections) { ingo@97: int num = collections != null ? collections.length : 0; ingo@97: ingo@97: GWT.log("Received " + num + " user collections."); ingo@97: raimund@885: updateGridDataSource(collections); ingo@97: } ingo@97: } ingo@97: ); ingo@97: } ingo@97: felix@3380: raimund@885: /** raimund@885: * Delete all entries in the ListGrid. raimund@885: */ bjoern@4694: private void clearGrid() { ingo@97: ListGridRecord[] records = grid.getRecords(); ingo@97: ingo@97: for (ListGridRecord record: records) { ingo@97: grid.removeData(record); ingo@97: } ingo@97: } ingo@97: ingo@97: raimund@885: /** raimund@885: * Update the collections data source. raimund@885: * raimund@885: * First removes all collections to avoid duplicates, then add new entries. raimund@885: * raimund@885: * @param c Collections to set to the data source. raimund@885: */ bjoern@4694: private void updateGridDataSource(Collection[] c) { raimund@885: collections.clear(); raimund@889: if(c == null) { raimund@889: clearGrid(); raimund@889: return; raimund@889: } raimund@885: for (Collection coll : c) { raimund@885: this.collections.add(coll); raimund@885: } bjoern@4691: updateGrid(); raimund@885: } raimund@885: raimund@885: raimund@885: /** raimund@885: * Updates the ListGrid. raimund@885: */ bjoern@4694: private void updateGrid() { ingo@97: clearGrid(); ingo@97: bjoern@4695: if (collections == null || collections.isEmpty()) { ingo@599: return; ingo@599: } ingo@599: bjoern@4691: for (Collection col: collections) { raimund@885: String name; raimund@885: bjoern@4691: name = col.getDisplayName().toLowerCase(); raimund@885: raimund@885: // Add a collection to the filtered list if the search string raimund@885: // matches. bjoern@4691: if (filter == null || filter.isEmpty() || bjoern@4691: name.contains(filter.toLowerCase())) { bjoern@4691: grid.addData(new CollectionRecord(col)); raimund@885: } raimund@885: } raimund@885: } raimund@885: ingo@613: public int getMaxNameLength() { ingo@613: return MAX_NAME_LENGTH; ingo@613: } ingo@613: ingo@613: ingo@226: /** ingo@226: * Builds the field in the grid that displays the creation time of a ingo@226: * project. ingo@226: * ingo@226: * @return the grid field. ingo@226: */ ingo@226: protected ListGridField buildDateField() { ingo@606: ListGridField date = new ListGridField( ingo@606: "creationTime", messages.projectlist_creationTime()); ingo@606: ingo@226: date.setType(ListGridFieldType.DATE); ingo@597: date.setCanEdit(false); ingo@226: ingo@226: date.setCellFormatter(new CellFormatter() { christian@3501: @Override ingo@226: public String format(Object value, ListGridRecord rec, int r, int c) { ingo@226: if (value == null) { ingo@226: return null; ingo@226: } ingo@226: ingo@226: DateTimeFormat dtf = DateTimeFormat.getFormat( ingo@226: messages.datetime_format()); ingo@226: ingo@226: return dtf.format((Date)value); ingo@226: } ingo@226: }); ingo@226: ingo@606: date.setWidth(COLUMN_DATE_WIDTH); ingo@606: date.setAlign(Alignment.CENTER); ingo@226: ingo@226: return date; ingo@226: } ingo@226: ingo@226: ingo@226: /** ingo@226: * Builds the field in the grid that displays the name of a project. ingo@226: * ingo@226: * @return the grid field. ingo@226: */ ingo@226: protected ListGridField buildNameField() { ingo@606: ListGridField name = new ListGridField( ingo@606: "name", messages.projectlist_title()); ingo@606: ingo@226: name.setType(ListGridFieldType.TEXT); ingo@606: name.setShowHover(true); ingo@606: name.setHoverCustomizer(new HoverCustomizer() { christian@3501: @Override ingo@606: public String hoverHTML( ingo@606: Object value, ingo@606: ListGridRecord record, ingo@606: int row, ingo@606: int col) ingo@606: { ingo@606: CollectionRecord r = (CollectionRecord) record; ingo@606: Collection c = r.getCollection(); ingo@606: ingo@607: String name = r.getName(); ingo@606: ingo@606: return name != null && name.length() > 0 ingo@606: ? name ingo@606: : c.identifier(); ingo@606: } ingo@606: }); ingo@226: ingo@606: name.setWidth(COLUMN_TITLE_WIDTH); ingo@226: name.setAlign(Alignment.LEFT); ingo@226: ingo@226: return name; ingo@226: } ingo@587: ingo@587: ingo@587: protected ListGridField buildFavoriteField() { ingo@606: ListGridField fav = new ListGridField( ingo@606: "ttl", messages.projectlist_favorite()); ingo@606: ingo@587: fav.setType(ListGridFieldType.IMAGE); ingo@587: String base = GWT.getHostPageBaseURL(); ingo@587: fav.setImageURLPrefix(base + "images/"); ingo@587: fav.setImageURLSuffix(".png"); ingo@606: fav.setWidth(COLUMN_FAVORITE_WIDTH); ingo@606: fav.setAlign(Alignment.CENTER); ingo@597: fav.setCanEdit(false); ingo@587: ingo@587: return fav; ingo@587: } raimund@887: raimund@887: raimund@887: protected void cloneProject(Collection c) { raimund@887: Config config = Config.getInstance(); raimund@887: String locale = config.getLocale(); raimund@887: raimund@887: cloneCollection = c; raimund@887: raimund@1425: describeCollectionService.describe(c.identifier(), locale, raimund@887: new AsyncCallback() { christian@3501: @Override raimund@887: public void onFailure(Throwable caught) { raimund@887: GWT.log("Could not DESCRIBE collection."); raimund@887: SC.warn(messages.getString(caught.getMessage())); raimund@887: } raimund@887: raimund@887: christian@3501: @Override raimund@887: public void onSuccess(Collection newCollection) { raimund@887: GWT.log("Successfully DESCRIBED collection."); raimund@887: String uuid = getMasterArtifact(newCollection); felix@3380: cloneArtifact(uuid, newCollection); raimund@887: } raimund@887: } raimund@887: ); raimund@887: } raimund@887: raimund@887: felix@3380: /** Get master artifacts UUID of a collection. */ raimund@887: protected String getMasterArtifact(Collection newCollection) { raimund@887: String uuid = newCollection.getItem(0).identifier(); raimund@887: // The master artifact uuid. raimund@887: return uuid; raimund@887: } raimund@887: raimund@887: felix@3380: /** Clone artifact/create collection, using the refArtifacts factory. */ felix@3380: protected void cloneArtifact(String uuid, Artifact refArtifact, felix@3380: final String locale) { raimund@887: Recommendation recommendation = new Recommendation( felix@3380: refArtifact.getName(), raimund@887: null, raimund@887: uuid, raimund@887: null); raimund@887: raimund@887: String factory = recommendation.getFactory(); raimund@887: createArtifactService.create( raimund@1425: locale, factory, recommendation, raimund@887: new AsyncCallback() { christian@3501: @Override raimund@887: public void onFailure(Throwable caught) { raimund@887: GWT.log("Error loading recommendations: " + raimund@887: caught.getMessage()); raimund@887: } raimund@887: christian@3501: @Override raimund@887: public void onSuccess(Artifact artifact) { raimund@887: GWT.log("Created new artifact: " + artifact.getUuid()); bjoern@4696: createClonedCollection(artifact); raimund@887: } raimund@887: } raimund@887: ); raimund@887: } raimund@887: raimund@887: felix@3380: /** felix@3380: * Clone a project (collection). felix@3380: */ bjoern@4694: private void cloneArtifact(final String uuid, Collection newCollection) { felix@3380: Config config = Config.getInstance(); felix@3380: final String locale = config.getLocale(); felix@3380: felix@3380: // Find out which factory to use for cloning. felix@3380: CollectionItem master = newCollection.getItem(0); felix@3380: getArtifactService.getArtifact( felix@3380: locale, felix@3380: master.identifier(), felix@3380: master.hash(), felix@3380: new AsyncCallback() { christian@3501: @Override felix@3380: public void onFailure(Throwable caught) { felix@3380: SC.warn(MSG.getString(caught.getMessage())); felix@3380: } felix@3380: christian@3501: @Override felix@3380: public void onSuccess(Artifact artifact) { felix@3380: cloneArtifact(uuid, artifact, locale); felix@3380: } felix@3380: }); felix@3380: } felix@3380: felix@3380: bjoern@4696: /** bjoern@4696: * Creates a {@link Collection} with the passed {@link Artifact} bjoern@4696: * @param artifact {@link Artifact} to add to the new {@link Collection} bjoern@4696: */ bjoern@4696: private void createClonedCollection(final Artifact artifact) { raimund@887: Config config = Config.getInstance(); raimund@887: final String locale = config.getLocale(); raimund@887: final String ownerid = user.identifier(); raimund@887: raimund@887: createCollectionService.create( raimund@1425: locale, raimund@1425: ownerid, raimund@887: new AsyncCallback() { christian@3501: @Override raimund@887: public void onFailure(Throwable caught) { raimund@887: GWT.log("Could not create the new collection."); raimund@887: SC.warn(messages.getString(caught.getMessage())); raimund@887: } raimund@887: christian@3501: @Override raimund@887: public void onSuccess(Collection collection) { raimund@887: GWT.log("Successfully created a new collection."); bjoern@4696: addArtifactToClonedCollection(artifact, collection); raimund@887: } raimund@887: } raimund@887: ); raimund@887: } raimund@887: raimund@887: bjoern@4696: private void addArtifactToClonedCollection(Artifact a, Collection c) { ingo@1493: Config config = Config.getInstance(); ingo@1493: final String locale = config.getLocale(); raimund@887: raimund@887: addArtifactService.add( raimund@1425: c, a, locale, raimund@887: new AsyncCallback() { christian@3501: @Override raimund@887: public void onFailure(Throwable caught) { raimund@887: GWT.log("An error occured while adding artifact."); raimund@887: SC.warn(messages.getString(caught.getMessage())); raimund@887: } raimund@887: christian@3501: @Override raimund@887: public void onSuccess(Collection newColl) { raimund@887: String name = cloneCollection.getName(); raimund@887: if(name == null || name.equals("")) { raimund@887: name = cloneCollection.identifier(); raimund@887: } raimund@887: bjoern@4696: String colname = messages.copy_of() + ": " + name; raimund@887: bjoern@4694: updateCollectionName(newColl, colname); raimund@887: if(cloneCollection.getTTL() == 0) { raimund@887: newColl.setTTL(0); raimund@887: updateCollectionTTL(newColl); raimund@887: } raimund@887: } raimund@887: } raimund@887: ); raimund@887: } bjoern@4605: bjoern@4605: bjoern@4605: @Override bjoern@4605: public void onVisibilityChanged(VisibilityChangedEvent event) { bjoern@4605: if (event.getIsVisible()) { bjoern@4605: this.flys.hideHeaderProjectButton(); bjoern@4605: } bjoern@4605: else { bjoern@4605: this.flys.shoHeaderProjectButton(); bjoern@4605: } bjoern@4605: } bjoern@4691: bjoern@4691: private void setFilter(String filter) { bjoern@4691: this.filter = filter; bjoern@4691: } ingo@4: } ingo@4: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :