/** * OpenKM, Open Document Management System (http://www.openkm.com) * Copyright (c) 2006-2011 Paco Avila & Josep Llort * * No bytes were intentionally harmed during the development of this application. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. */ package com.openkm.frontend.client.widget; import java.util.Iterator; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.MouseMoveEvent; import com.google.gwt.event.dom.client.MouseMoveHandler; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.event.dom.client.MouseUpHandler; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.ServiceDefTarget; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TreeItem; import com.google.gwt.user.client.ui.Widget; import com.openkm.frontend.client.Main; import com.openkm.frontend.client.bean.GWTDocument; import com.openkm.frontend.client.bean.GWTFolder; import com.openkm.frontend.client.bean.GWTMail; import com.openkm.frontend.client.bean.GWTPermission; import com.openkm.frontend.client.contants.service.RPCService; import com.openkm.frontend.client.service.OKMDocumentService; import com.openkm.frontend.client.service.OKMDocumentServiceAsync; import com.openkm.frontend.client.service.OKMFolderService; import com.openkm.frontend.client.service.OKMFolderServiceAsync; import com.openkm.frontend.client.service.OKMMailService; import com.openkm.frontend.client.service.OKMMailServiceAsync; /** * @author jllort * */ public class Dragable extends Composite implements OriginPanel { private final OKMFolderServiceAsync folderService = (OKMFolderServiceAsync) GWT.create(OKMFolderService.class); private final OKMDocumentServiceAsync documentService = (OKMDocumentServiceAsync) GWT.create(OKMDocumentService.class); private final OKMMailServiceAsync mailService = (OKMMailServiceAsync) GWT.create(OKMMailService.class); private boolean dragged = false; private boolean dropEnabled = false; // Used to eliminate user drag & drop too much faster ( timer to enable drop ) private HTML floater = new HTML(); private int originPanel = NONE; private Timer timer; private TreeItem selectedTreeItem; private TreeItem lastSelectedTreeItem; private Element selectedElement; private Element lastSelectElement; /** * Dragable */ public Dragable() { dragged = false; floater = new HTML(""); floater.setVisible(false); floater.sinkEvents(Event.MOUSEEVENTS); floater.setVisible(false); floater.setWordWrap(false); floater.setStyleName("okm-Draggable"); floater.addMouseUpHandler(new MouseUpHandler(){ @Override public void onMouseUp(MouseUpEvent event) { if (timer!=null) { timer.cancel(); // Cancel timer timer = null; } DOM.releaseCapture(floater.getElement()); floater.setHTML(""); floater.setVisible(false); // Cancelling the timer if (timer!=null) { timer.cancel(); // Cancelling timer timer = null; } // Only move if dragged has been enabled by timer if (dragged && dropEnabled) { // Action depends on origin dragable switch(originPanel) { case TREE_ROOT : TreeItem clickedTreeItem = Main.get().activeFolderTree.elementClicked(DOM.eventGetTarget((Event)event.getNativeEvent())); if (clickedTreeItem!=null && (((GWTFolder)clickedTreeItem.getUserObject()).getPermissions()& GWTPermission.WRITE) == GWTPermission.WRITE ){ final TreeItem draggedTreeItem = Main.get().activeFolderTree.getActualItem(); boolean isChild = DOM.isOrHasChild(draggedTreeItem.getElement(), clickedTreeItem.getElement()); if (draggedTreeItem != clickedTreeItem && !isChild) { String fldPath = ((GWTFolder) draggedTreeItem.getUserObject()).getPath(); // Folder actual path final String dstPath = ((GWTFolder) clickedTreeItem.getUserObject()).getPath(); // Destination path TreeItem parentItem = draggedTreeItem.getParentItem(); // The parent of actual item selected // Remove the folders and evaluates parent child status draggedTreeItem.remove(); if (parentItem.getChildCount()==0) { ((GWTFolder) parentItem.getUserObject()).setHasChilds(false); // Sets not has folder childs } clickedTreeItem.addItem(draggedTreeItem); // Adds the draggedItem to selected ((GWTFolder) clickedTreeItem.getUserObject()).setHasChilds(true); // Always sets that the actual parent folder now has childs clickedTreeItem.setState(true); // Always opens treeItem parent draggedTreeItem.setSelected(true); // Selects the treeItem // Evaluate icon of changed folders last and actual parent tree Item Main.get().activeFolderTree.evaluesFolderIcon(parentItem); Main.get().activeFolderTree.evaluesFolderIcon(clickedTreeItem); // Move the folder ServiceDefTarget endPoint = (ServiceDefTarget) folderService; endPoint.setServiceEntryPoint(RPCService.FolderService); folderService.move( fldPath, dstPath, new AsyncCallback<Object>() { public void onSuccess(Object result) { // Sets the folder new path itself and childs GWTFolder draggedFolder = (GWTFolder) draggedTreeItem.getUserObject(); String oldPath = draggedFolder.getPath(); String newPath = dstPath + "/" + draggedFolder.getName(); preventFolderInconsitences(draggedTreeItem, oldPath, newPath, dstPath); draggedTreeItem.setState(false); Main.get().activeFolderTree.openAllPathFolder(newPath,null); } public void onFailure(Throwable caught) { draggedTreeItem.setState(false); Main.get().showError("Move", caught); } } ); } } break; case FILE_BROWSER : clickedTreeItem = Main.get().activeFolderTree.elementClicked(DOM.eventGetTarget((Event)event.getNativeEvent())); TreeItem actualTreeItem = Main.get().activeFolderTree.getActualItem(); if (clickedTreeItem!=null && Main.get().mainPanel.desktop.browser.fileBrowser.isSelectedRow() && (((GWTFolder)clickedTreeItem.getUserObject()).getPermissions()& GWTPermission.WRITE) == GWTPermission.WRITE ){ final String dstPath = ((GWTFolder) clickedTreeItem.getUserObject()).getPath(); // Destination path // if selected path = actual path must not move if (!dstPath.equals(((GWTFolder) actualTreeItem.getUserObject()).getPath())) { // Unselects folder destination on tree if (lastSelectElement!= null) { DOM.setElementProperty(lastSelectElement,"className","gwt-TreeItem"); } if (Main.get().mainPanel.desktop.browser.fileBrowser.isFolderSelected()) { final GWTFolder gwtFolder= Main.get().mainPanel.desktop.browser.fileBrowser.getFolder(); // The dragged folder String fldPath = gwtFolder.getPath(); // Folder actual path // Destination path must not containt actual folder path, because folder can't be moved to his subfolders if (!dstPath.startsWith(fldPath)){ // Gets the moved tree Item final TreeItem movedTreeItem = Main.get().activeFolderTree.getChildFolder(fldPath); // Remove the folders and evaluates parent child status movedTreeItem.remove(); if (actualTreeItem.getChildCount()==0) { ((GWTFolder) actualTreeItem.getUserObject()).setHasChilds(false); // Sets not has folder childs } clickedTreeItem.addItem(movedTreeItem); // Adds the draggedItem to selected ((GWTFolder) clickedTreeItem.getUserObject()).setHasChilds(true); // Always sets that the actual parent folder now has childs clickedTreeItem.setState(true); // Always opens treeItem parent Main.get().activeFolderTree.removeDeleted(fldPath); // Evaluate icon of changed folders last and actual parent tree Item Main.get().activeFolderTree.evaluesFolderIcon(clickedTreeItem); // Move the folder ServiceDefTarget endPoint = (ServiceDefTarget) folderService; endPoint.setServiceEntryPoint(RPCService.FolderService); folderService.move( fldPath, dstPath, new AsyncCallback<Object>() { public void onSuccess(Object result) { // Sets the folder new path ( parent and itself ) recursive for itself and childs movedTreeItem.setUserObject(gwtFolder); String oldPath = gwtFolder.getPath(); String newPath = dstPath + "/" + gwtFolder.getName(); preventFolderInconsitences(movedTreeItem, oldPath, newPath, dstPath); movedTreeItem.setState(false); // Refresh file browser Main.get().mainPanel.desktop.browser.fileBrowser.deleteMovedOrMoved(); } public void onFailure(Throwable caught) { movedTreeItem.setState(false); Main.get().showError("Move", caught); } } ); } } else if (Main.get().mainPanel.desktop.browser.fileBrowser.isDocumentSelected()){ GWTDocument gwtDocument = Main.get().mainPanel.desktop.browser.fileBrowser.getDocument(); // The dragged document // Move the document ServiceDefTarget endPoint = (ServiceDefTarget) documentService; endPoint.setServiceEntryPoint(RPCService.DocumentService); documentService.move( gwtDocument.getPath(),dstPath, callbackMove); // refresh file browser Main.get().mainPanel.desktop.browser.fileBrowser.deleteMovedOrMoved(); } else if (Main.get().mainPanel.desktop.browser.fileBrowser.isMailSelected()){ GWTMail gwtMail = Main.get().mainPanel.desktop.browser.fileBrowser.getMail(); // The dragged document // Move the document ServiceDefTarget endPoint = (ServiceDefTarget) mailService; endPoint.setServiceEntryPoint(RPCService.MailService); mailService.move( gwtMail.getPath(),dstPath, callbackMove); // refresh file browser Main.get().mainPanel.desktop.browser.fileBrowser.deleteMovedOrMoved(); } } } break; } } dragged=false; // Sets always dragged to false dropEnabled = false; // Sets always dragged to false // Always we destroy possible timers to automatic up / down scroll Main.get().mainPanel.desktop.navigator.scrollTaxonomyPanel.destroyTimer(); } }); floater.addMouseMoveHandler(new MouseMoveHandler(){ @Override public void onMouseMove(MouseMoveEvent event) { if (dragged && event!=null) { floater.setVisible(true); // Sets the floater visible // Cancels the timer if dropEnabled is true if (dropEnabled && timer!=null) { timer.cancel(); // Cancelling timer timer = null; } int posX = event.getClientX(); int posY = event.getClientY(); RootPanel.get().setWidgetPosition(Main.get().dragable, posX + 1, posY); // Sets selected tree style to indicate posible selected destination selectedTreeItem = Main.get().activeFolderTree.elementClicked(DOM.eventGetTarget((Event)event.getNativeEvent())); TreeItem actualItem = Main.get().activeFolderTree.getActualItem(); // Removes always style of last selected treeItem if (lastSelectedTreeItem!=null && !actualItem.equals(lastSelectedTreeItem) && lastSelectElement!=null){ DOM.setElementProperty(lastSelectElement,"className","gwt-TreeItem"); lastSelectedTreeItem = null; } // Sets the style of actual tree item if (selectedTreeItem!=null) { selectedElement = getSelectedElement(selectedTreeItem.getElement()); if (selectedElement==null) { Window.alert("Problem: '" + selectedTreeItem.getElement().getInnerHTML() + "'"); } DOM.setElementProperty(selectedElement,"className","gwt-TreeItem gwt-TreeItem-selected"); if (lastSelectedTreeItem!=null && !selectedTreeItem.equals(lastSelectedTreeItem) && !actualItem.equals(lastSelectedTreeItem) && lastSelectElement!=null) { DOM.setElementProperty(lastSelectElement,"className","gwt-TreeItem"); } lastSelectedTreeItem = selectedTreeItem; lastSelectElement = selectedElement; } // Action depends dragables destinations widgets Main.get().mainPanel.desktop.navigator.scrollTaxonomyPanel.ScrollOnDragDrop(posX + 1, posY); } } }); initWidget(floater); } /** * Sets the HTML value to floater * @param html */ public void show(String html, int originPanel){ this.originPanel = originPanel; DOM.setCapture(floater.getElement()); floater.setHTML(html); // Initialize values dragged=true; selectedTreeItem = null; lastSelectedTreeItem = null; timer = new Timer() { public void run() { dropEnabled=true; } }; timer.scheduleRepeating(1500); // 1,5 seconds } /** * Move document or folder */ final AsyncCallback<Object> callbackMove = new AsyncCallback<Object>() { public void onSuccess(Object result) { } public void onFailure(Throwable caught) { Main.get().showError("Move", caught); } }; /** * getSelectedElement * * @param element * @return */ public Element getSelectedElement(Element element){ if (DOM.getFirstChild(element).getClassName().contains("gwt-TreeItem")) { // Case node without childs return DOM.getFirstChild(element); } else { return DOM.getChild(DOM.getChild(DOM.getChild(DOM.getChild(DOM.getChild(element,0),0),0),1),0); } } /** * Prevents folder incosistences changing moved path on childs recursivelly * nodes drawed * * @param item The tree node */ public void preventFolderInconsitences(TreeItem item, String oldPath, String newPath, String parentPath) { GWTFolder folderItem = (GWTFolder) item.getUserObject(); folderItem.setPath(folderItem.getPath().replaceFirst(oldPath,newPath)); folderItem.setParentPath(parentPath); // Recursively changing paht value for (int i=0; i<item.getChildCount();i++) { preventFolderInconsitences(item.getChild(i), oldPath, newPath, folderItem.getPath()); } } /* (non-Javadoc) * @see com.google.gwt.user.client.ui.HasWidgets#add(com.google.gwt.user.client.ui.Widget) */ public void add(Widget w) { } /* (non-Javadoc) * @see com.google.gwt.user.client.ui.HasWidgets#clear() */ public void clear() { } /* (non-Javadoc) * @see com.google.gwt.user.client.ui.HasWidgets#iterator() */ public Iterator<Widget> iterator() { return null; } /* (non-Javadoc) * @see com.google.gwt.user.client.ui.HasWidgets#remove(com.google.gwt.user.client.ui.Widget) */ public boolean remove(Widget w) { return true; } }