Java tutorial
/* * ============================================================= * Copyright (C) 2007-2011 Edgenius (http://www.edgenius.com) * ============================================================= * License Information: http://www.edgenius.com/licensing/edgenius/2.0/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2.0 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * http://www.gnu.org/licenses/gpl.txt * * **************************************************************** */ package com.edgenius.wiki.gwt.client.page.widgets; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import com.allen_sauer.gwt.log.client.Log; import com.edgenius.wiki.gwt.client.AbstractEntryPoint; import com.edgenius.wiki.gwt.client.ControllerFactory; import com.edgenius.wiki.gwt.client.Css; import com.edgenius.wiki.gwt.client.GwtClientUtils; import com.edgenius.wiki.gwt.client.KeyCaptureListener; import com.edgenius.wiki.gwt.client.i18n.Msg; import com.edgenius.wiki.gwt.client.model.AttachmentModel; import com.edgenius.wiki.gwt.client.model.PageModel; import com.edgenius.wiki.gwt.client.page.PageMain; import com.edgenius.wiki.gwt.client.server.PageControllerAsync; import com.edgenius.wiki.gwt.client.server.constant.PageType; import com.edgenius.wiki.gwt.client.server.utils.ErrorCode; import com.edgenius.wiki.gwt.client.server.utils.GwtUtils; import com.edgenius.wiki.gwt.client.widgets.ClickLink; import com.edgenius.wiki.gwt.client.widgets.IconBundle; import com.edgenius.wiki.gwt.client.widgets.MessageWidget; import com.edgenius.wiki.gwt.client.widgets.UploadDialog; import com.edgenius.wiki.gwt.client.widgets.Writable; import com.edgenius.wiki.gwt.client.widgets.WritableListener; import com.edgenius.wiki.gwt.client.widgets.ZebraTable; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONException; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONValue; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; /** * @author Dapeng.Ni */ public class AttachmentPanel extends SimplePanel implements ClickHandler { public static final String MODULE_ACTION_URI = "pages/upload"; // 5seconds private final String panelID = HTMLPanel.createUniqueId(); private MessageWidget message = new MessageWidget(); private UploadedPanel uploadedPanel = new UploadedPanel(); private ClickLink addMoreAttBtn = new ClickLink(Msg.consts.add_attachments()); private HTML noPermLabel = new HTML("<b>" + Msg.consts.no_perm_upload() + "</b>"); private PageMain main; private boolean readonly; private Vector<AttachmentListener> attachmentListeners = new Vector<AttachmentListener>(); private PageType draftStatus; //******************************************************************** // Methods //******************************************************************** public AttachmentPanel(PageMain main, boolean readonly) { this.readonly = readonly; this.main = main; VerticalPanel panel = new VerticalPanel(); addMoreAttBtn.addClickHandler(this); FlowPanel btnPanel = new FlowPanel(); btnPanel.add(noPermLabel); btnPanel.add(addMoreAttBtn); panel.add(btnPanel); panel.add(message); panel.add(uploadedPanel); setReadonly(readonly); //style this.setStyleName(Css.ATTACHMNET_PANEL); btnPanel.setStyleName(Css.FUNCTION); panel.setSize("100%", "100%"); panel.setCellHorizontalAlignment(uploadedPanel, HasHorizontalAlignment.ALIGN_CENTER); this.add(panel); DOM.setElementAttribute(this.getElement(), "id", panelID); } public PageMain getPageMain() { return this.main; } public String getPanelID() { return panelID; } public void setReadonly(boolean readonly) { addMoreAttBtn.setVisible(!readonly); noPermLabel.setVisible(readonly); uploadedPanel.setReadonly(readonly); this.readonly = readonly; } // // public void uploadWithCaptcha(String captchaResponse, final boolean toView, final int draftStatus, final CaptchaDialog captcha){ // CaptchaCodeModel model = null; // if(captchaResponse != null){ // model = new CaptchaCodeModel(); // model.captchaCode = captchaResponse; // model.reqireCaptcha = true; // } // SecurityControllerAsync action = ControllerFactory.getSecurityController(); // action.captchaValid(model, new AsyncCallback<Integer>(){ // // public void onFailure(Throwable error) { // if(captcha != null){ // captcha.enableSubmit(); // } // if(error instanceof CaptchaVerifiedException && captcha != null){ // captcha.refreshCaptch(); // }else{ // GwtClientUtils.processError(error); // } // } // // public void onSuccess(Integer result) { // if(captcha != null){ // captcha.hidebox(); // } // if(result == null || result == -1) // return; // // //TODO: submit //// uploadFormPanel.setToView(toView); //// uploadFormPanel.setDraftStatus(draftStatus); //// uploadFormPanel.submitForm(); // } // // }); // } public void reset() { for (AttachmentListener listener : attachmentListeners) { listener.resetAttachmentPanel(); } } /** * Merge given JSON string with current attachment list on UploadedPanel. * @param results */ public void mergeAttachments(String results) { this.mergeAttachments(results, PageType.NONE_DRAFT); } public void mergeAttachments(String results, PageType draftStatus) { this.draftStatus = draftStatus; if (results == null || results.trim().length() == 0) { return; } List<AttachmentModel> modelList = parseAttachmentJSON(results); if (modelList.size() > 0) { List<AttachmentModel> uploaded = new ArrayList<AttachmentModel>(); for (Iterator<AttachmentModel> iter = modelList.iterator(); iter.hasNext();) { AttachmentModel att = iter.next(); //only non-bulk-uploaded could display on uploaded panel... if (!att.bulkZip) { uploaded.add(att); QuickHelpDictionary.addAttachment(att.filename); } } //fire event to add item in uploadedPanel for (AttachmentListener listener : attachmentListeners) { listener.addOrUpdateItem(uploaded); } } } public void addAttachmentListener(AttachmentListener listener) { attachmentListeners.add(listener); } /** * @param mceImageDialog */ public void removeAttachmentListener(AttachmentListener listener) { attachmentListeners.remove(listener); } public void addOrUpdateItem(List<AttachmentModel> modelList) { if (modelList == null || modelList.size() == 0) { return; } //check if there any errors, if has, popup message in main panel. for (Iterator<AttachmentModel> iter = modelList.iterator(); iter.hasNext();) { AttachmentModel att = iter.next(); if (ErrorCode.hasError(att)) { main.errorOnVisiblePanel(ErrorCode.getMessageText(att.errorCode, att.errorMsg)); iter.remove(); } } uploadedPanel.addUploadItem(modelList); main.setAttachmentCount(uploadedPanel.getUploadedCount()); } public void removeItem(String nodeUuid) { uploadedPanel.removeItem(nodeUuid); main.setAttachmentCount(uploadedPanel.getUploadedCount()); } public void resetAttachmentPanel() { uploadedPanel.clear(); message.cleanMessage(); main.setAttachmentCount(uploadedPanel.getUploadedCount()); QuickHelpDictionary.clearAttachmentList(); } public void onClick(ClickEvent event) { Object sender = event.getSource(); if (sender == addMoreAttBtn) { if (draftStatus == PageType.NONE_DRAFT && main.getVisiblePanelIndex() == PageMain.EDIT_PANEL) { //anyway, save initial status: maybe user will choose save or save-draft, then status will modified in server side. draftStatus = PageType.AUTO_DRAFT; } UploadDialog dialog = new UploadDialog(this, PageMain.getSpaceUname(), PageMain.getPageUuid(), draftStatus); dialog.showbox(); } } /** * This only return list without history */ public ArrayList<String> getUploadedItemsUuid() { return uploadedPanel.getUploadedItemsUuid(); } /** * This only return list without history */ public List<AttachmentModel> getUploadedItems() { return uploadedPanel.getUploadedItems(); } public boolean isReadonly() { return readonly; } public void refresh(String spaceUname, String pageUuid, final PageType draftStatus) { PageControllerAsync action = ControllerFactory.getPageController(); action.getAttachments(spaceUname, pageUuid, draftStatus, new AsyncCallback<String>() { @Override public void onSuccess(String json) { if (json != null) { AttachmentPanel.this.reset(); AttachmentPanel.this.mergeAttachments(json, draftStatus); } } @Override public void onFailure(Throwable arg0) { //nothing } }); } //******************************************************************** // Private methods //******************************************************************** private List<AttachmentModel> parseAttachmentJSON(String results) { List<AttachmentModel> modelList = new ArrayList<AttachmentModel>(); try { JSONValue jsonValue = JSONParser.parseStrict(results); JSONArray attachmentArray; if ((attachmentArray = jsonValue.isArray()) != null) { //AttachmentList int size = attachmentArray.size(); for (int idx = 0; idx < size; ++idx) { //attachment JSONObject attachObj = attachmentArray.get(idx).isObject(); AttachmentModel model = retrieve(attachObj); modelList.add(model); } } } catch (JSONException e) { Window.alert(Msg.consts.error_request()); } return modelList; } private AttachmentModel retrieve(JSONObject attachObj) { AttachmentModel model = new AttachmentModel(); //retrieve Attachment->Filename, Comment and Shared fields. //Attachment fields Set<String> attKeys = attachObj.keySet(); for (Iterator<String> attIter = attKeys.iterator(); attIter.hasNext();) { String attKey = attIter.next(); //these values come from com.edgenius.core.repository.FileNode.java if (attKey.equalsIgnoreCase("filename")) { model.filename = attachObj.get(attKey).isString().stringValue(); } else if (attKey.equalsIgnoreCase("comment")) { model.desc = attachObj.get(attKey).isString().stringValue(); } else if (attKey.equalsIgnoreCase("date")) { model.date = (long) attachObj.get(attKey).isNumber().doubleValue(); } else if (attKey.equalsIgnoreCase("size")) { model.size = (long) attachObj.get(attKey).isNumber().doubleValue(); } else if (attKey.equalsIgnoreCase("status")) { //This field is from FileNode.status, so Name is not "draftStart". model.draftStatus = (int) attachObj.get(attKey).isNumber().doubleValue(); } else if (attKey.equalsIgnoreCase("userFullname")) { model.creator = attachObj.get(attKey).isString().stringValue(); } else if (attKey.equalsIgnoreCase("index")) { model.index = attachObj.get(attKey).isString().stringValue(); } else if (attKey.equalsIgnoreCase("nodeUuid")) { model.nodeUuid = attachObj.get(attKey).isString().stringValue(); } else if (attKey.equalsIgnoreCase("version")) { model.version = attachObj.get(attKey).isString().stringValue(); } else if (attKey.equalsIgnoreCase("bulkZip")) { model.bulkZip = attachObj.get(attKey).isBoolean().booleanValue(); } else if (attKey.equalsIgnoreCase("errorCode")) { model.errorCode = attachObj.get(attKey).isString().stringValue(); } } return model; } private void removeAttachment(String nodeUuid, String version) { PageControllerAsync action = ControllerFactory.getPageController(); action.removeAttachment(PageMain.getSpaceUname(), PageMain.getPageUuid(), nodeUuid, version, new AsyncCallback<PageModel>() { //nothing to do here public void onFailure(Throwable error) { GwtClientUtils.processError(error); } public void onSuccess(PageModel model) { if (!GwtClientUtils.preSuccessCheck(model, message)) { return; } } }); } //******************************************************************** // Private class : Uploaded Panel //******************************************************************** private class UploadedPanel extends SimplePanel { //(itemID,open/close image),name,author,size,date,desc,edit/remove: private static final int MAIN_ITEM_LEN = 7; private static final int HISTORY_IMG_COL = 0; private ZebraTable table = new ZebraTable(); //row 0 is header private static final int startRow = 1; private Label msg = new Label(Msg.consts.no_attachment()); private VerticalPanel panel = new VerticalPanel(); private boolean readonly; public UploadedPanel() { clear(); msg.setStyleName(Css.BLANK_MSG); this.setWidget(panel); } public void setReadonly(boolean readonly) { this.readonly = readonly; int count = table.getRowCount(); for (int row = startRow; row < count; row++) { ItemID id = (ItemID) table.getWidget(row, 0); if (!id.isHistory()) { //skip first one(itemID,img) and last (remove btn) for (int col = 1; col < MAIN_ITEM_LEN - 1; col++) { Writable label = (Writable) table.getWidget(row, col); //make some editing label switch to text. label.cancelEditing(); } FuncPanel funcPanel = (FuncPanel) table.getWidget(row, MAIN_ITEM_LEN - 1); funcPanel.setVisible(!readonly); } } if (startRow <= count) //show/hide header part "Function" table.getWidget(0, MAIN_ITEM_LEN - 1).setVisible(!readonly); } /** * Override to only clean table */ public void clear() { //DO NOT user table.clear simply, which does not clear all cell in table, see HtmlTable Jdoc. panel.clear(); msg.setVisible(true); table.removeAllRows(); panel.add(table); panel.add(msg); table.setWidth("97%"); panel.setSize("99%", "100%"); } public void removeItem(String nodeUuid) { int count = table.getRowCount(); int removeRow = -1; for (int row = startRow; row < count; row++) { ItemID id = (ItemID) table.getWidget(row, 0); if (id.getUuid().equals(nodeUuid)) { removeRow = row; break; } } if (removeRow != -1) { //try to remove history first. if (removeRow + 1 < count) { ItemID hisID = (ItemID) table.getWidget(removeRow + 1, 0); if (hisID.getUuid().equals(nodeUuid)) { table.removeRow(removeRow + 1); } } //remove main item row table.removeRow(removeRow); } if (table.getRowCount() == startRow) { clear(); } } /* * Return how many items in uploaded panel, it won't count history items */ public int getUploadedCount() { int rowSize = table.getRowCount(); int count = 0; for (int idx = startRow; idx < rowSize; idx++) { ItemID itemId = (ItemID) table.getWidget(idx, 0); if (itemId.isHistory()) continue; count++; } Log.info("Get getUploadedCount " + count); return count; } public ArrayList<String> getUploadedItemsUuid() { int rowSize = table.getRowCount(); ArrayList<String> uuidList = new ArrayList<String>(); for (int idx = startRow; idx < rowSize; idx++) { ItemID itemId = (ItemID) table.getWidget(idx, 0); if (itemId.isHistory()) continue; uuidList.add(itemId.getUuid()); } return uuidList; } public List<AttachmentModel> getUploadedItems() { int rowSize = table.getRowCount(); List<AttachmentModel> list = new ArrayList<AttachmentModel>(); for (int idx = startRow; idx < rowSize; idx++) { ItemID itemId = (ItemID) table.getWidget(idx, 0); if (itemId.isHistory()) continue; list.add(itemId.getModel()); } return list; } /* * This method will merge current item with input items in list. If input item is could be a new item, a item * which is newer than exist one(nodeUuid is same), then the old one will push into history list. * * Structure: * Main Item Row -> ItemID(uuid,ver,false), displayed fields in column * HistoryItem Row -> ItemID(uuid,"",true), HistoryTable -> ItemID(uuid,ver,true), displayed field in column * */ public void addUploadItem(List<AttachmentModel> modelList) { int size = modelList.size(); //remove "No attachment message" if (size >= 0 && msg.isVisible()) { msg.setVisible(false); buildTableHeader(); } for (int s = 0; s < size; s++) { final AttachmentModel model = modelList.get(s); //check if same attachment already exist: if so, will update. int count = table.getRowCount(); boolean exist = false; for (int idx = startRow; idx < count; idx++) { ItemID itemId = (ItemID) table.getWidget(idx, 0); if (itemId.isHistory()) continue; //find same item exist, then need compare incoming item with all item(root and history) to decide //arrange items by versions if (itemId.getUuid().equals(model.nodeUuid)) { float ver = itemId.getVersion(); float newVer = getFloatVersion(model.version); if (newVer > ver) { //make this item become main item and convert old item to first history item convertToHistory(idx, model); } else if (newVer == ver) { //update main item ItemID item = (ItemID) table.getWidget(idx, HISTORY_IMG_COL); setItem(idx, model, item.isOpen()); } else { //compare income with history item, update or insert new one refreshHistory(idx, model); } //update this item and return exist = true; break; } } if (exist) continue; //could don't found exist item, then create new row //TODO: this does not sort by file name //Don't use above count field. table.getRowCount(): row is possible increase if multiple files upload. setItem(table.getRowCount(), model, false); } } private void buildTableHeader() { //skip ItemID, and History Image cells int col = HISTORY_IMG_COL + 1; table.getCellFormatter().setWordWrap(0, col, false); table.setWidget(0, col++, new HTML(Msg.consts.file_name())); table.getCellFormatter().setWordWrap(0, col, false); table.setWidget(0, col++, new HTML(Msg.consts.author())); table.getCellFormatter().setWordWrap(0, col, false); table.setWidget(0, col++, new HTML(Msg.consts.size())); table.getCellFormatter().setWordWrap(0, col, false); table.setWidget(0, col++, new HTML(Msg.consts.date())); table.getCellFormatter().setWordWrap(0, col, false); table.setWidget(0, col++, new HTML(Msg.consts.description())); HTML f = new HTML(Msg.consts.actions()); table.setWidget(0, col++, f); f.setVisible(!readonly); col = HISTORY_IMG_COL + 1; for (int idx = 0; idx < col; idx++) table.getColumnFormatter().setWidth(idx, "1%"); table.getColumnFormatter().setStyleName(col++, Css.COL1); //name table.getColumnFormatter().setStyleName(col++, Css.COL2); //author table.getColumnFormatter().setStyleName(col++, Css.COL3); //size table.getColumnFormatter().setStyleName(col++, Css.COL4); //date col++; //desc SKIP! table.getColumnFormatter().setStyleName(col++, Css.COL6); //funct } /* * mainRow is main item row, history will be in next row. */ private void refreshHistory(int mainRow, AttachmentModel model) { //firstly, try to get history item panel, if no, then create new one FlexTable historyTable = null; int hisRow = mainRow + 1; if (hisRow < table.getRowCount()) { //main row is not last row, so need check if next row is its history row ItemID id = (ItemID) table.getWidget(mainRow + 1, 0); if (id.getUuid().equals(model.nodeUuid)) { //find exist history table historyTable = (FlexTable) table.getWidget(mainRow + 1, HISTORY_IMG_COL + 1); } } //no history exist, create new one if (historyTable == null) { if (hisRow < table.getRowCount()) { //create a new row to hold new HistoryTable if main item is not last item. table.insertRow(hisRow); } historyTable = new FlexTable(); historyTable.setStyleName(Css.HISTORY_TABLE); //table first column always is ItemID table.setWidget(hisRow, 0, new ItemID(model, true)); table.setWidget(hisRow, HISTORY_IMG_COL + 1, historyTable); table.getFlexCellFormatter().setColSpan(hisRow, HISTORY_IMG_COL + 1, MAIN_ITEM_LEN - 1); int total = table.getCellCount(hisRow); //if the row of history is new one, it could contain extra columns, remove them. if (total > HISTORY_IMG_COL + 1) table.removeCells(hisRow, HISTORY_IMG_COL + 2, total - 2 - HISTORY_IMG_COL); //last field: remove button, will leave empty } int hisCount = historyTable.getRowCount(); boolean historyDone = false; float newVer = getFloatVersion(model.version); for (int hrow = 0; hrow < hisCount; hrow++) { ItemID itemId = (ItemID) historyTable.getWidget(hrow, 0); float ver = itemId.getVersion(); if (newVer > ver) { //insert incoming before this history item historyTable.insertRow(hrow); setHisotryItem(model, hrow, historyTable); historyDone = true; break; } else if (newVer == ver) { setHisotryItem(model, hrow, historyTable); historyDone = true; break; } } if (!historyDone) { //insert this history to last one setHisotryItem(model, historyTable.getRowCount(), historyTable); } //enable history open/close image to visible ItemID itemId = (ItemID) table.getWidget(mainRow, HISTORY_IMG_COL); itemId.setSwitch(itemId.isOpen() ? ItemID.SWITCH_CLOSE : ItemID.SWITCH_OPEN); //also set history visible or not according to image switch status table.getRowFormatter().setVisible(hisRow, itemId.isOpen()); } /* * Convert given row in table to first history item. If history row does not exist, then create a new one */ private void convertToHistory(int row, AttachmentModel mainModel) { //get current row all value and convert them to AttachmentModel, then create new row in history table int idx = 0; ItemID itemId = (ItemID) table.getWidget(row, idx++); AttachmentModel model = itemId.getModel(); refreshHistory(row, model); setItem(row, mainModel, itemId.isOpen()); } /** * @param model * @param hisRow * @param historyTable */ private void setHisotryItem(AttachmentModel model, int hisRow, FlexTable historyTable) { int hisCol = 0; historyTable.setWidget(hisRow, hisCol++, new ItemID(model, true)); historyTable.setWidget(hisRow, hisCol++, new Label("ver" + model.version)); historyTable.setWidget(hisRow, hisCol++, GwtClientUtils.buildDownloadURLWidget(PageMain.getSpaceUname(), model.filename, model.nodeUuid, model.version)); historyTable.setWidget(hisRow, hisCol++, new Label(model.creator)); historyTable.setWidget(hisRow, hisCol++, new Label(GwtUtils.convertHumanSize(model.size))); historyTable.setWidget(hisRow, hisCol++, new Label(GwtClientUtils.toDisplayDate(model.date))); historyTable.setWidget(hisRow, hisCol++, new Label(model.desc)); } private void setItem(int row, final AttachmentModel model, boolean closeHistory) { int col = 0; ItemID itemID = new ItemID(model, false); table.getCellFormatter().setWidth(row, col, "1%"); table.setWidget(row, col++, itemID); //check if this item has history: if no, mark image invisible if (row + 1 < table.getRowCount()) { ItemID historyItemId = (ItemID) table.getWidget(row + 1, 0); if (historyItemId.isHistory() && historyItemId.getUuid().equals(model.nodeUuid)) { itemID.setSwitch(closeHistory ? ItemID.SWITCH_CLOSE : ItemID.SWITCH_OPEN); } } Writable nameLabel = new Writable(downloadLink(model), model.filename); nameLabel.addFocusHandler(KeyCaptureListener.instance()); nameLabel.addBlurHandler(KeyCaptureListener.instance()); nameLabel.addStyleName(Css.NAME); final Label descText = new Label(model.desc); Writable descLabel = new Writable(descText, model.desc); descLabel.addFocusHandler(KeyCaptureListener.instance()); descLabel.addBlurHandler(KeyCaptureListener.instance()); descLabel.addStyleName(Css.DESC); table.getCellFormatter().setWordWrap(row, col, false); table.setWidget(row, col++, nameLabel); table.getCellFormatter().setWordWrap(row, col, false); table.setWidget(row, col++, new Writable(new Label(model.creator), model.creator, true)); table.getCellFormatter().setWordWrap(row, col, false); table.setWidget(row, col++, new Writable(new Label(GwtUtils.convertHumanSize(model.size)), GwtUtils.convertHumanSize(model.size), true)); table.getCellFormatter().setWordWrap(row, col, false); table.setWidget(row, col++, new Writable(new Label(GwtClientUtils.toDisplayDate(model.date)), GwtClientUtils.toDisplayDate(model.date), true)); //skip desc wrap table.setWidget(row, col++, descLabel); table.getCellFormatter().setWordWrap(row, col, false); FuncPanel func = new FuncPanel(itemID); func.setVisible(!readonly); table.setWidget(row, col++, func); //name and description are editable nameLabel.addListener(new WritableListener() { public void editDone(Writable sender, String text) { model.filename = text; sender.resetWidget(downloadLink(model)); } public void editing(Writable sender) { } public void editCancelled(Writable sender, String originalText) { // TODO Auto-generated method stub } }); descLabel.addListener(new WritableListener() { public void editDone(Writable sender, String text) { //reset desc text in display. descText.setText(text); } public void editing(Writable sender) { } public void editCancelled(Writable sender, String originalText) { } }); } private HTML downloadLink(final AttachmentModel model) { HTML link = GwtClientUtils.buildDownloadURLWidget(PageMain.getSpaceUname(), model.filename, model.nodeUuid, model.version); if (model.draftStatus > 0) { return new HTML( link.getHTML() + "<span class='status-label'> [" + Msg.consts.draft() + "] </span>"); } else { return link; } } private float getFloatVersion(String verstr) { try { return new Float(verstr).floatValue(); } catch (Exception e) { return 0; } } private class ItemID extends SimplePanel { public final static int SWITCH_NONE = 0; public final static int SWITCH_CLOSE = 1; public final static int SWITCH_OPEN = 2; //switch image setting final Image closeImg = new Image(IconBundle.I.get().closeArrow()); final Image openImg = new Image(IconBundle.I.get().openArrow()); private boolean history; private int switchType; private AttachmentModel model; public ItemID(final AttachmentModel model, boolean history) { //clone useful field... rather than keep model object this.model = model.clone(); this.history = history; FlowPanel panel = new FlowPanel(); openImg.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { switchGate(ItemID.this, false); } }); closeImg.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { switchGate(ItemID.this, true); } }); closeImg.setVisible(false); openImg.setVisible(false); panel.add(closeImg); panel.add(openImg); this.setWidget(panel); } private void switchGate(ItemID itemId, boolean open) { //retrieve table to find out the history panel and hide it //DON'T use row, this row maybe adjust when new item added,it is not always correct. int size = table.getRowCount(); for (int idx = startRow; idx < size; idx++) { ItemID historyItemID = (ItemID) table.getWidget(idx, 0); if (historyItemID.isHistory() && historyItemID.getUuid().equals(model.nodeUuid)) { //make this history show/hide table.getRowFormatter().setVisible(idx, open); //switch img itemId.setSwitch(open ? SWITCH_CLOSE : SWITCH_OPEN); break; } } } /** * @return */ public boolean isOpen() { //if switch is close image, it means history is opened return switchType == SWITCH_CLOSE; } public void setSwitch(int type) { switchType = type; if (type == SWITCH_NONE) { //hide all openImg.setVisible(false); closeImg.setVisible(false); } else if (type == SWITCH_CLOSE) { //show open openImg.setVisible(true); closeImg.setVisible(false); } else { //show open openImg.setVisible(false); closeImg.setVisible(true); } } public boolean isHistory() { return history; } public float getVersion() { return getFloatVersion(model.version); } public String getUuid() { return this.model.nodeUuid; } public AttachmentModel getModel() { return model.clone(); } } /** * Each attachment item has a Function Panel which holds possible operation for this attachment. Such as * Edit,Remove, Done(edit), Cancel(Edit). */ private class FuncPanel extends SimplePanel implements ClickHandler, AsyncCallback<String> { private FlowPanel panel = new FlowPanel(); private ClickLink removeBtn = new ClickLink(Msg.consts.remove()); private ClickLink editBtn = new ClickLink(Msg.consts.edit()); private ClickLink doneBtn = new ClickLink(Msg.consts.done()); private ClickLink cancelBtn = new ClickLink(Msg.consts.cancel()); private ItemID itemID; /** * @param itemID */ public FuncPanel(ItemID itemID) { this.itemID = itemID; if (!AbstractEntryPoint.isOffline()) { HTML sep1 = new HTML("|"); doneBtn.setVisible(false); cancelBtn.setVisible(false); panel.add(editBtn); panel.add(cancelBtn); panel.add(sep1); panel.add(doneBtn); editBtn.addClickHandler(this); doneBtn.addClickHandler(this); cancelBtn.addClickHandler(this); DOM.setStyleAttribute(sep1.getElement(), "display", "inline"); } panel.add(removeBtn); removeBtn.addClickHandler(this); this.setWidget(panel); } public void onClick(ClickEvent event) { Object sender = event.getSource(); if (sender == removeBtn) { if (Window.confirm(Msg.consts.confirm_remove_attachment())) { //remove whole node with its history removeAttachment(itemID.getUuid(), null); for (AttachmentListener listener : attachmentListeners) { listener.removeItem(itemID.getUuid()); } } } else if (sender == editBtn) { if (!AbstractEntryPoint.isOffline()) { editBtn.setVisible(false); doneBtn.setVisible(true); cancelBtn.setVisible(true); } removeBtn.setVisible(false); switchEdit(1); } else if (sender == doneBtn) { if (!AbstractEntryPoint.isOffline()) { editBtn.setVisible(true); doneBtn.setVisible(false); cancelBtn.setVisible(false); } removeBtn.setVisible(true); //save attachment metadata to server side. String[] meta = getMetaData(); PageControllerAsync pageController = ControllerFactory.getPageController(); //NodeUuid, Name, Desc pageController.updateAttachmentMeta(PageMain.getSpaceUname(), PageMain.getPageUuid(), meta[0], meta[1], meta[2], this); } else if (sender == cancelBtn) { if (!AbstractEntryPoint.isOffline()) { editBtn.setVisible(true); doneBtn.setVisible(false); cancelBtn.setVisible(false); } removeBtn.setVisible(true); switchEdit(3); } } private String[] getMetaData() { //NodeUuid, Name, Desc String[] meta = null; int rowSize = table.getRowCount(); for (int row = startRow; row < rowSize; row++) { ItemID id = (ItemID) table.getWidget(row, 0); if (!id.isHistory() && id.getUuid().equals(itemID.getUuid())) { int colSize = table.getCellCount(row); meta = new String[3]; meta[0] = itemID.getUuid(); int idx = 0; for (int col = 0; col < colSize; col++) { Widget w = table.getWidget(row, col); //so far, to get Name and desc, is check if they are readonly, first should be name, then desc if (w instanceof Writable && !((Writable) w).isReadonly()) { meta[++idx] = ((Writable) w).getEditingText(); //already get name and desc if (idx == 2) break; } } break; } } return meta; } private void switchEdit(int flag) { //invoke edit model for this row items int rowSize = table.getRowCount(); for (int row = startRow; row < rowSize; row++) { ItemID id = (ItemID) table.getWidget(row, 0); if (!id.isHistory() && id.getUuid().equals(itemID.getUuid())) { int colSize = table.getCellCount(row); for (int col = 0; col < colSize; col++) { Widget w = table.getWidget(row, col); if (w instanceof Writable) { Writable wl = (Writable) w; if (flag == 1) { wl.enableEdit(); } else if (flag == 2) { wl.doneEdit(); } else if (flag == 3) { wl.cancelEditing(); } } } break; } } } public void setVisible(boolean visible) { if (!visible) { //if visible, then must set function bar to edit|remove status. if (!AbstractEntryPoint.isOffline()) { editBtn.setVisible(true); doneBtn.setVisible(false); cancelBtn.setVisible(false); } removeBtn.setVisible(true); } super.setVisible(visible); } /* * Update attachment item metadata failed */ public void onFailure(Throwable error) { GwtClientUtils.processError(error); } /* * Update attachment item metadata success. */ public void onSuccess(String errCode) { if (errCode != null && errCode.trim().length() > 0) { message.error(ErrorCode.getMessage(errCode, null)); } switchEdit(2); } } } }