/* * Lokomo OneCMDB - An Open Source Software for Configuration * Management of Datacenter Resources * * Copyright (C) 2006 Lokomo Systems AB * * 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. * * Lokomo Systems AB can be contacted via e-mail: info@lokomo.com or via * paper mail: Lokomo Systems AB, Sv�rdv�gen 27, SE-182 33 * Danderyd, Sweden. * */ package org.onecmdb.ui.gwt.desktop.client.widget; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.onecmdb.ui.gwt.desktop.client.WindowFactory; import org.onecmdb.ui.gwt.desktop.client.service.CMDBAsyncCallback; import org.onecmdb.ui.gwt.desktop.client.service.content.ContentData; import org.onecmdb.ui.gwt.desktop.client.service.content.ContentFile; import org.onecmdb.ui.gwt.desktop.client.service.content.ContentFolder; import org.onecmdb.ui.gwt.desktop.client.service.content.ContentServiceFactory; import org.onecmdb.ui.gwt.desktop.client.service.model.CMDBPermissions; import org.onecmdb.ui.gwt.desktop.client.service.model.CMDBSession; import com.extjs.gxt.ui.client.Events; import com.extjs.gxt.ui.client.Style.LayoutRegion; import com.extjs.gxt.ui.client.Style.Scroll; import com.extjs.gxt.ui.client.binder.TreeBinder; import com.extjs.gxt.ui.client.data.BaseModelData; import com.extjs.gxt.ui.client.data.BaseTreeLoader; import com.extjs.gxt.ui.client.data.ModelData; import com.extjs.gxt.ui.client.data.ModelStringProvider; import com.extjs.gxt.ui.client.data.RpcProxy; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.MenuEvent; import com.extjs.gxt.ui.client.event.MessageBoxEvent; import com.extjs.gxt.ui.client.event.SelectionListener; import com.extjs.gxt.ui.client.event.WindowEvent; import com.extjs.gxt.ui.client.store.Store; import com.extjs.gxt.ui.client.store.StoreSorter; import com.extjs.gxt.ui.client.store.TreeStore; import com.extjs.gxt.ui.client.util.Margins; import com.extjs.gxt.ui.client.widget.ContentPanel; import com.extjs.gxt.ui.client.widget.Dialog; import com.extjs.gxt.ui.client.widget.Info; import com.extjs.gxt.ui.client.widget.LayoutContainer; import com.extjs.gxt.ui.client.widget.MessageBox; import com.extjs.gxt.ui.client.widget.TabItem; import com.extjs.gxt.ui.client.widget.TabPanel; import com.extjs.gxt.ui.client.widget.WidgetComponent; import com.extjs.gxt.ui.client.widget.button.Button; import com.extjs.gxt.ui.client.widget.button.ButtonBar; import com.extjs.gxt.ui.client.widget.button.IconButton; import com.extjs.gxt.ui.client.widget.button.ToolButton; import com.extjs.gxt.ui.client.widget.layout.BorderLayout; import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData; import com.extjs.gxt.ui.client.widget.layout.FillLayout; import com.extjs.gxt.ui.client.widget.layout.FitLayout; import com.extjs.gxt.ui.client.widget.layout.RowData; import com.extjs.gxt.ui.client.widget.layout.RowLayout; import com.extjs.gxt.ui.client.widget.menu.Menu; import com.extjs.gxt.ui.client.widget.menu.MenuItem; import com.extjs.gxt.ui.client.widget.menu.SeparatorMenuItem; import com.extjs.gxt.ui.client.widget.toolbar.AdapterToolItem; import com.extjs.gxt.ui.client.widget.toolbar.TextToolItem; import com.extjs.gxt.ui.client.widget.toolbar.ToolBar; import com.extjs.gxt.ui.client.widget.tree.Tree; import com.extjs.gxt.ui.client.widget.tree.TreeItem; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.KeyboardListener; import com.google.gwt.user.client.ui.RichTextArea; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.Widget; public class ContentViewerWidget extends LayoutContainer { private BaseTreeLoader loader; private Tree tree; //private TextArea textArea; private TabPanel tabFolder; private ContentFolder rootFolder; private boolean readonly; private CMDBPermissions permissions; private HashMap<String, TabItem> tabMap = new HashMap<String, TabItem>(); public ContentViewerWidget() { this(new ContentFolder()); } public ContentViewerWidget(ContentFolder root) { this.rootFolder = root; } public void setPermissions(CMDBPermissions permissions) { this.permissions = permissions; } @Override protected void onRender(Element parent, int index) { super.onRender(parent, index); init(); } public void init() { setLayout(new BorderLayout()); RpcProxy<? extends ContentData, List<? extends ContentData>> proxy = new RpcProxy<ContentData, List<? extends ContentData>>() { @Override protected void load(ContentData loadConfig, AsyncCallback<List<? extends ContentData>> callback){ loadConfig.getChildren(callback); } }; // tree loader loader = new BaseTreeLoader(proxy) { @Override public boolean hasChildren(ModelData parent) { return (parent instanceof ContentFolder); } }; // trees store TreeStore<? extends ContentData> store = new TreeStore<ContentData>(loader); store.setStoreSorter(new StoreSorter<ContentData>() { @Override public int compare(Store store, ContentData m1, ContentData m2, String property) { boolean m1Folder = m1 instanceof ContentFolder; boolean m2Folder = m2 instanceof ContentFolder; if (m1Folder && !m2Folder) { return -1; } else if (!m1Folder && m2Folder) { return 1; } return super.compare(store, m1, m2, property); } }); tree = new Tree(); tree.setContextMenu(getContentMenu()); tree.addListener(Events.OnDoubleClick, new Listener<BaseEvent>() { public void handleEvent(BaseEvent be) { TreeItem item = tree.getSelectedItem(); if (item.getModel() instanceof ContentFile) { final ContentFile file = (ContentFile)item.getModel(); if (true) { updateEditArea(file, null, false); return; } Info.display("Loading...", (String)file.getName()); ContentServiceFactory.get().get("token", file, new CMDBAsyncCallback<String>() { @Override public void onSuccess(String arg0) { updateEditArea(file, arg0, false); } }); } } }); TreeBinder<? extends ContentData> binder = new TreeBinder<ContentData>(tree, store); binder.setIconProvider(new ModelStringProvider<ContentData>() { public String getStringValue(ContentData model, String property) { String name = model.getName(); if (name == null) { return(null); } if (name.endsWith(".gif")) { return(CMDBSession.get().getContentRepositoryURL() + "/" + model.getPath()); } if (name.endsWith(".jpg")) { return(CMDBSession.get().getContentRepositoryURL() + "/" + model.getPath()); } if (name.endsWith(".png")) { return(CMDBSession.get().getContentRepositoryURL() + "/" + model.getPath()); } if (model instanceof ContentFile) { return(GWT.getModuleBaseURL() + "/images/file_obj.gif"); } return(null); } }); binder.setDisplayProperty("name"); loader.load(this.rootFolder); BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST, 200); westData.setSplit(true); westData.setCollapsible(true); westData.setMargins(new Margins(5)); BorderLayoutData southData = new BorderLayoutData(LayoutRegion.SOUTH, 50); //southData.setSplit(false); southData.setCollapsible(false); //southData.setFloatable(false); southData.setMargins(new Margins(0, 5, 5, 5)); BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER); centerData.setMargins(new Margins(5, 0, 5, 0)); ContentPanel westPanel = new ContentPanel(); westPanel.setLayout(new FitLayout()); westPanel.setScrollMode(Scroll.AUTO); westPanel.setLayoutOnChange(true); westPanel.add(tree); westPanel.getHeader().addTool(new ToolButton("x-tool-refresh", new SelectionListener<ComponentEvent>() { @Override public void componentSelected(ComponentEvent ce) { getLoader().load(rootFolder); } })); tabFolder = new TabPanel(); tabFolder.setTabScroll(true); LayoutContainer statusPanel = new LayoutContainer(); add(westPanel, westData); add(tabFolder, centerData); add(statusPanel, southData); layout(); } protected void updateEditArea(final ContentFile file, String arg0, boolean edit) { //tabFolder. //TabItem item = tabMap.get(file.getPath()); //if (item == null) { TabItem item = new TabItem(); item.setClosable(true); item.setText((String)file.getName()); item.setIconStyle("icon-tabs"); //tabMap.put(file.getPath(), item); tabFolder.add(item); //} if (edit) { final TextArea textArea = new TextArea(); textArea.setText(arg0); ToolBar buttonBar = new ToolBar(); TextToolItem save = new TextToolItem("Save", "save-icon"); save.addSelectionListener(new SelectionListener<ComponentEvent>() { @Override public void componentSelected(ComponentEvent ce) { ContentServiceFactory.get().put(CMDBSession.get().getToken(), file, textArea.getText(), new CMDBAsyncCallback<Boolean>() { @Override public void onSuccess(Boolean arg0) { Info.display("Saved", "Saved ok!"); } }); } }); buttonBar.add(save); if (permissions != null) { save.setEnabled(permissions.isEditable()); } if (this.readonly) { save.setEnabled(false); } /* ContentPanel centerPanel = new ContentPanel(); centerPanel.setLayout(new RowLayout()); centerPanel.add(toolBar, new RowData(1,-1)); centerPanel.add(new WidgetComponent(textArea), new RowData(1, 1)); */ item.setLayout(new RowLayout()); item.add(buttonBar, new RowData(1,-1)); item.add(new WidgetComponent(textArea), new RowData(1, 1)); } else { // Add url. item.setUrl(CMDBSession.get().getContentRepositoryURL() + file.getPath()); } tabFolder.setSelection(item); item.layout(); } public BaseTreeLoader getLoader() { return(loader); } private Tree getTree() { return(tree); } public Menu getContentMenu() { Menu contextMenu = new Menu(); contextMenu.setWidth(130); { MenuItem open = new MenuItem(); open.setText("<b>Open in Browser</b>"); open.setIconStyle("icon-open"); open.addSelectionListener(new SelectionListener<ComponentEvent>() { @Override public void componentSelected(ComponentEvent ce) { final TreeItem item = (TreeItem)tree.getSelectionModel().getSelectedItem(); if (item == null) { return; } ContentData folder = (ContentData) item.getModel(); if (folder instanceof ContentFile) { updateEditArea((ContentFile)folder, null, false); } } }); contextMenu.add(open); } if (permissions == null || permissions.isEditable()) { MenuItem edit = new MenuItem(); edit.setIconStyle("icon-edit"); edit.setText("Edit"); edit.addSelectionListener(new SelectionListener<ComponentEvent>() { @Override public void componentSelected(ComponentEvent ce) { TreeItem item = tree.getSelectedItem(); if (item.getModel() instanceof ContentFile) { final ContentFile file = (ContentFile)item.getModel(); Info.display("Loading...", (String)file.getName()); ContentServiceFactory.get().get("token", file, new CMDBAsyncCallback<String>() { @Override public void onSuccess(String arg0) { updateEditArea(file, arg0, true); } }); } } }); contextMenu.add(edit); } contextMenu.add(new SeparatorMenuItem()); if (permissions == null || permissions.isEditable()) { MenuItem insert = new MenuItem(); insert.setText("New Folder"); insert.setIconStyle("icon-add"); insert.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { final TreeItem item = (TreeItem)tree.getSelectionModel().getSelectedItem(); ContentData folder = new ContentFolder(); folder.setPath(""); if (item != null) { folder = (ContentData) item.getModel(); } final ContentData data = folder; final MessageBox box = MessageBox.prompt("Folder Name", "Please enter folder name:"); box.addCallback(new Listener<MessageBoxEvent>() { public void handleEvent(MessageBoxEvent be) { Button btn = be.buttonClicked; if (btn.getItemId().equals(Dialog.OK)) { final ContentFolder folder = new ContentFolder(); folder.setPath(data.getPath() + "/" + be.value); ContentServiceFactory.get().create(CMDBSession.get().getToken(), folder, new AsyncCallback<Boolean>() { public void onFailure(Throwable arg0) { Info.display("Failed","Can't create folder " + folder.getPath()); } public void onSuccess(Boolean arg0) { if (arg0) { Info.display("Created", folder.getPath() + " created"); if (item == null) { getLoader().load(rootFolder); } else { getLoader().loadChildren(item.getModel()); } } else { Info.display("Failed","Can't create folder " + folder.getPath()); } } }); } } }); } }); contextMenu.add(insert); } if (permissions == null || permissions.isEditable()) { MenuItem insert = new MenuItem(); insert.setText("New File"); insert.setIconStyle("icon-add"); insert.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { final TreeItem item = (TreeItem)tree.getSelectionModel().getSelectedItem(); ContentData folder = new ContentFolder(); folder.setPath(""); if (item != null) { folder = (ContentData) item.getModel(); } final ContentData data = (ContentData) folder; final MessageBox box = MessageBox.prompt("File Name", "Please enter file name:"); box.addCallback(new Listener<MessageBoxEvent>() { public void handleEvent(MessageBoxEvent be) { Button btn = be.buttonClicked; if (btn.getItemId().equals(Dialog.OK)) { final ContentFile folder = new ContentFile(); folder.setPath(data.getPath() + "/" + be.value); ContentServiceFactory.get().create(CMDBSession.get().getToken(), folder, new AsyncCallback<Boolean>() { public void onFailure(Throwable arg0) { Info.display("Failed","Can't create file " + folder.getPath()); } public void onSuccess(Boolean arg0) { if (arg0) { Info.display("Created", folder.getPath() + " created"); if (item == null) { getLoader().load(rootFolder); } else { getLoader().loadChildren(item.getModel()); } } else { Info.display("Failed","Can't create file " + folder.getPath()); } } }); } } }); } }); contextMenu.add(insert); } if (permissions == null || permissions.isDeletable()) { MenuItem remove = new MenuItem(); remove.setText("Delete"); remove.setIconStyle("icon-delete"); remove.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { TreeItem item = (TreeItem)tree.getSelectionModel().getSelectedItem(); if (item == null) { return; } final TreeItem parent = item.getParentItem(); final ContentData data = (ContentData) item.getModel(); final MessageBox box = MessageBox.confirm("Delete", "Delete " + data.getPath() +"<br/>Are you sure?", new Listener<WindowEvent>() { public void handleEvent(WindowEvent be) { Button btn = be.buttonClicked; if (btn.getItemId().equals(Dialog.YES)) { ContentServiceFactory.get().delete(CMDBSession.get().getToken(), data, new AsyncCallback<Boolean>() { public void onFailure(Throwable arg0) { Info.display("Failed","Can't delete " + data.getPath()); } public void onSuccess(Boolean arg0) { if (arg0) { Info.display("Delete", data.getPath() + " deleted"); ModelData model = parent.getModel(); if (model == null) { getLoader().load(rootFolder); } else { getLoader().loadChildren(model); } } else { Info.display("Failed", "Can't delete " + data.getPath()); } } }); } } }); } }); contextMenu.add(remove); contextMenu.add(new SeparatorMenuItem()); } if (permissions == null || permissions.isEditable()) { MenuItem upload = new MenuItem(); upload.setText("Upload"); //remove.setIconStyle("icon-delete"); upload.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { TreeItem item = (TreeItem)getTree().getSelectionModel().getSelectedItem(); new FileUploadWidget((ContentData)item.getModel()).show(); } }); contextMenu.add(upload); } MenuItem download = new MenuItem(); download.setText("Download"); //remove.setIconStyle("icon-delete"); download.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { TreeItem item = (TreeItem)getTree().getSelectionModel().getSelectedItem(); if (item.getModel() instanceof ContentFile) { ContentFile file = (ContentFile)item.getModel(); String url = CMDBSession.get().getContentRepositoryURL() + file.getPath(); Window.open(url, "_blank", ""); } } }); contextMenu.add(download); contextMenu.add(new SeparatorMenuItem()); MenuItem refresh = new MenuItem(); refresh.setText("Refresh"); //remove.setIconStyle("icon-delete"); refresh.addSelectionListener(new SelectionListener<MenuEvent>() { public void componentSelected(MenuEvent ce) { DeferredCommand.addCommand(new Command() { public void execute() { TreeItem item = (TreeItem)getTree().getSelectionModel().getSelectedItem(); if (item == null) { getLoader().load(rootFolder); } else { getLoader().loadChildren(item.getModel()); } } }); } }); contextMenu.add(refresh); return(contextMenu); } public void setReadonly(boolean readonly) { this.readonly = readonly; } }