From 87311f7eff552477b5545ebd5a314012b0040c0e Mon Sep 17 00:00:00 2001 From: Massimiliano Assante Date: Wed, 13 Nov 2013 17:56:13 +0000 Subject: [PATCH] added report reference dialog git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/user/reports@85444 82a268e6-3cf1-43bd-a215-b396298e98cf --- .classpath | 5 +- .settings/com.google.gdt.eclipse.core.prefs | 2 +- .settings/org.eclipse.wst.common.component | 9 ++ pom.xml | 27 ++-- .../reportgenerator/client/Headerbar.java | 37 ++++- .../client/Presenter/Presenter.java | 100 ++++++++++-- .../client/ReportConstants.java | 5 +- .../client/ReportGenerator.java | 151 ------------------ .../reportgenerator/client/ReportService.java | 11 ++ .../client/ReportServiceAsync.java | 8 + .../reportgenerator/client/ToolboxPanel.java | 8 +- .../client/model/TemplateComponent.java | 13 +- .../client/targets/ClientTuple.java | 22 ++- .../client/targets/SequenceWidget.java | 15 ++ .../client/toursteps/Intro.java | 26 --- .../client/toursteps/Intro.ui.xml | 31 ---- .../server/servlet/ReportServiceImpl.java | 104 +++++++++++- .../shared/VMETypeIdentifier.java | 9 ++ .../reportgenerator/ReportGenerator.gwt.xml | 7 +- src/main/webapp/ReportGenerator.css | 4 +- src/main/webapp/WEB-INF/web.xml | 16 +- src/main/webapp/images/iconReport.png | Bin 0 -> 2893 bytes src/main/webapp/images/reportRef.png | Bin 0 -> 1624 bytes 23 files changed, 348 insertions(+), 262 deletions(-) delete mode 100644 src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.java delete mode 100644 src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.ui.xml create mode 100644 src/main/java/org/gcube/portlets/user/reportgenerator/shared/VMETypeIdentifier.java create mode 100644 src/main/webapp/images/iconReport.png create mode 100644 src/main/webapp/images/reportRef.png diff --git a/.classpath b/.classpath index fc67732..fc0dc22 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,6 @@ - + @@ -31,6 +31,5 @@ - - + diff --git a/.settings/com.google.gdt.eclipse.core.prefs b/.settings/com.google.gdt.eclipse.core.prefs index f719d60..8e5c4eb 100644 --- a/.settings/com.google.gdt.eclipse.core.prefs +++ b/.settings/com.google.gdt.eclipse.core.prefs @@ -2,6 +2,6 @@ <<<<<<<=.mine >>>>>>>=.r71295 eclipse.preferences.version=1 -lastWarOutDir=/Users/massi/Documents/workspace/reports/target/reports-4.6.1-SNAPSHOT +lastWarOutDir=/Users/massi/Documents/workspace/reports/target/reports-4.6.2-SNAPSHOT warSrcDir=src/main/webapp warSrcDirIsOutput=false diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 2dc054b..ad7b9c6 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -5,6 +5,15 @@ + + uses + + + uses + + + uses + diff --git a/pom.xml b/pom.xml index 57e9ecb..a492dcc 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ org.gcube.portlets.user reports war - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT gCube Reports Portlet gCube Reports Portlet. @@ -85,7 +85,7 @@ gwt-servlet ${setScope} - + org.gcube.core common-scope-maps [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) @@ -98,19 +98,13 @@ org.gcube.applicationsupportlayer aslsocial - ${setScope} + ${setScope} org.gcube.portlets.user gcube-widgets ${setScope} - - org.gcube.portlets.widgets - guided-tour-widget - [1.2.0-SNAPSHOT, 2.0.0-SNAPSHOT) - ${setScope} - org.gcube.portal custom-portal-handler @@ -122,6 +116,21 @@ 2.2.5 ${setScope} + + org.gcube.portlets.widgets + user-selection-dialog + [1.0.1-SNAPSHOT, 2.0.0-SNAPSHOT) + + + org.gcube.application + gcube-reporting-modeler + [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) + + + org.gcube.application.rsg + reports-store-gateway-client + 0.0.1-SNAPSHOT + org.gcube.common csv4j diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/Headerbar.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/Headerbar.java index 9aae4b9..7653d12 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/Headerbar.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/Headerbar.java @@ -49,7 +49,8 @@ public class Headerbar extends Composite{ private static final String EXPORT_HTML = "Export to HTML"; private static final String EXPORT_FIMES = "Export to FiMES XML"; private static final String EXPORT_XML = "Export to XML"; - private static final String EXPORT_ENCRYPTED_REPORT = "Save an Encrypted Version to Desktop"; + private static final String IMPORT_VME = "Import VME Report"; +// private static final String EXPORT_ENCRYPTED_REPORT = "Save an Encrypted Version to Desktop"; private static final String VIEW_USER_COMMENTS = "View user comments"; @@ -95,6 +96,8 @@ public class Headerbar extends Composite{ private MenuItem viewComments; private MenuItem discardSection; + + private MenuItem importVME; @@ -105,6 +108,7 @@ public class Headerbar extends Composite{ MenuItem sectionsMenu; MenuItem biblioMenu; MenuItem exportMenu; + MenuItem importMenu; MenuItemSeparator separator1; MenuItemSeparator separator2; MenuItemSeparator separator3; @@ -135,6 +139,9 @@ public class Headerbar extends Composite{ separator4 = menuBar.addSeparator(); exportMenu = getExportsMenu(); menuBar.addItem(exportMenu); + menuBar.addSeparator(); + importMenu = getImportMenu(); + menuBar.addItem(importMenu); mainLayout.setSize("100%", "24px"); mainLayout.setStyleName("menubar"); @@ -205,6 +212,8 @@ public class Headerbar extends Composite{ separator4 = menuBar.addSeparator(); exportMenu = getExportsMenu(); menuBar.addItem(exportMenu); + + ReportGenerator.get().getToolbarPanel().clear(); ReportGenerator.get().getToolbarPanel().add(new HTML("  ", true)); enableExports(); @@ -330,6 +339,24 @@ public class Headerbar extends Composite{ return toReturn; } + private MenuItem getImportMenu() { + MenuBar importMenu = new MenuBar(true); + + importMenu.setAnimationEnabled(true); + MenuItem toReturn = new MenuItem("Import", importMenu); + + Command importVMEReport = new Command() { + public void execute() { + presenter.showVMEImportDialog(); + } + }; + + importVME = new MenuItem(IMPORT_VME, true, importVMEReport); + + + importMenu.addItem(importVME); + return toReturn; + } private MenuItem getExportsMenu() { MenuBar exportsMenu = new MenuBar(true); @@ -342,7 +369,7 @@ public class Headerbar extends Composite{ optionHTML = new MenuItem(""+ EXPORT_HTML +"", true, getDisabledExportMenuItemCmd()); optionFimes = new MenuItem(""+ EXPORT_FIMES +"", true, getDisabledExportMenuItemCmd()); optionXML = new MenuItem(""+ EXPORT_XML +"", true, getDisabledExportMenuItemCmd()); - optionEncryptedModel = new MenuItem(""+ EXPORT_ENCRYPTED_REPORT +"", true, getDisabledExportMenuItemCmd()); +// optionEncryptedModel = new MenuItem(""+ EXPORT_ENCRYPTED_REPORT +"", true, getDisabledExportMenuItemCmd()); exportsMenu.addItem(optionDOCX); @@ -350,7 +377,7 @@ public class Headerbar extends Composite{ exportsMenu.addItem(optionPDF); exportsMenu.addItem(optionXML); exportsMenu.addSeparator(); - exportsMenu.addItem(optionEncryptedModel); +// exportsMenu.addItem(optionEncryptedModel); //optionsMenu.addItem(optionPDF); //exportsMenu.addItem(optionFimes); @@ -375,6 +402,8 @@ public class Headerbar extends Composite{ } }; + + // Create the Options menu MenuBar optionsMenu = new MenuBar(true); @@ -408,7 +437,7 @@ public class Headerbar extends Composite{ optionXML.setHTML(EXPORT_XML); optionXML.setCommand(generatedXML); - optionEncryptedModel.setHTML(EXPORT_ENCRYPTED_REPORT); +// optionEncryptedModel.setHTML(EXPORT_ENCRYPTED_REPORT); optionEncryptedModel.setCommand(generateEncryptedModel); // importModel.setHTML("Import from Template or Report"); diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/Presenter/Presenter.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/Presenter/Presenter.java index 8374a59..a1d93b6 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/Presenter/Presenter.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/Presenter/Presenter.java @@ -1,5 +1,6 @@ package org.gcube.portlets.user.reportgenerator.client.Presenter; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -8,6 +9,7 @@ import org.gcube.portlets.d4sreporting.common.shared.ComponentType; import org.gcube.portlets.d4sreporting.common.shared.Metadata; import org.gcube.portlets.d4sreporting.common.shared.Model; import org.gcube.portlets.user.reportgenerator.client.Headerbar; +import org.gcube.portlets.user.reportgenerator.client.ReportConstants; import org.gcube.portlets.user.reportgenerator.client.ReportGenerator; import org.gcube.portlets.user.reportgenerator.client.ReportService; import org.gcube.portlets.user.reportgenerator.client.ReportServiceAsync; @@ -49,12 +51,18 @@ import org.gcube.portlets.user.reportgenerator.client.targets.TextTableImage; import org.gcube.portlets.user.reportgenerator.client.uibinder.ExportOptions; import org.gcube.portlets.user.reportgenerator.shared.SessionInfo; import org.gcube.portlets.user.reportgenerator.shared.UserBean; +import org.gcube.portlets.user.reportgenerator.shared.VMETypeIdentifier; import org.gcube.portlets.widgets.exporter.client.ReportExporterPopup; import org.gcube.portlets.widgets.exporter.client.event.ExportingCompletedEvent; import org.gcube.portlets.widgets.exporter.client.event.ExportingCompletedEventHandler; import org.gcube.portlets.widgets.exporter.client.event.ReportExporterEvent; import org.gcube.portlets.widgets.exporter.client.event.ReportExporterEventHandler; import org.gcube.portlets.widgets.exporter.shared.TypeExporter; +import org.gcube.portlets.widgets.userselection.client.UserSelectionDialog; +import org.gcube.portlets.widgets.userselection.client.events.SelectedUserEvent; +import org.gcube.portlets.widgets.userselection.client.events.SelectedUserEventHandler; +import org.gcube.portlets.widgets.userselection.client.events.UsersFetchedEvent; +import org.gcube.portlets.widgets.userselection.shared.ItemSelectableBean; import com.extjs.gxt.ui.client.widget.MessageBox; import com.extjs.gxt.ui.client.widget.layout.FitLayout; @@ -126,8 +134,21 @@ public class Presenter { return eventBus; } - + + private UserSelectionDialog itemSelectionDialog; + private void handleEvents() { + + eventBus.addHandler(SelectedUserEvent.TYPE, new SelectedUserEventHandler() { + @Override + public void onSelectedUser(SelectedUserEvent event) { + itemSelectionDialog.hide(); + if (event.getSelectedUser().getType().equals(VMETypeIdentifier.Vme.toString())) + importVMEReport(event.getSelectedUser()); + else + associateVMRReportRef(event.getSelectedUser()); + } + }); eventBus.addHandler(ExportingCompletedEvent.TYPE, new ExportingCompletedEventHandler() { @Override @@ -187,14 +208,6 @@ public class Presenter { } }); - // eventBus.addHandler(ImportFinishedEvent.TYPE, new ImportFinishedEventHandler(){ - // public void onFinishedImport(ImportFinishedEvent event) { - // importDlg.hide(); - // openImportedFimesXML(event.getPathFile()); - // } - // - // }); - eventBus.addHandler(ItemSelectionEvent.TYPE, new ItemSelectionEventHandler() { @SuppressWarnings("unchecked") public void onItemSelected(ItemSelectionEvent event) { @@ -1254,4 +1267,73 @@ public class Presenter { public void clearExportPanel() { exportsPanel.clear(); } + + /** + * + */ + public void showVMEImportDialog() { + itemSelectionDialog = new UserSelectionDialog("Import: Please select the VME Report", eventBus); + itemSelectionDialog.center(); + itemSelectionDialog.show(); + reportService.listVMEReports(new AsyncCallback>() { + @Override + public void onFailure(Throwable caught) { + //handled by the Widget + } + + @Override + public void onSuccess(ArrayList result) { + for (ItemSelectableBean item : result) { + item.setIconURL(ReportConstants.REPORT_ICON); + } + eventBus.fireEvent(new UsersFetchedEvent(result)); + } + }); + } + + /** + * + */ + public void showVMERefAssociateDialog(VMETypeIdentifier refType) { + itemSelectionDialog = new UserSelectionDialog("Associate " + refType.toString() + ": Please select one ", eventBus); + itemSelectionDialog.center(); + itemSelectionDialog.show(); + reportService.listVMEReportRefByType(refType, new AsyncCallback>() { + @Override + public void onFailure(Throwable caught) { + //handled by the Widget + } + + @Override + public void onSuccess(ArrayList result) { + for (ItemSelectableBean item : result) { + item.setIconURL(ReportConstants.REPORT_REF_ICON); + } + eventBus.fireEvent(new UsersFetchedEvent(result)); + } + }); + } + + private void importVMEReport(ItemSelectableBean selectedReport) { + showLoading(); + reportService.importVMEReport(selectedReport.getId(), selectedReport.getName(), new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Window.alert("Could not Load template, please try again later: " + caught.getMessage()); + } + + @Override + public void onSuccess(Model toLoad) { + if (toLoad != null) + loadModel(toLoad); + else + Window.alert("Could not Load template, error on server."); + } + }); + + } + + private void associateVMRReportRef (ItemSelectableBean selectedReport) { + Window.alert("You selected " + selectedReport.getName() + " of type " + selectedReport.getType()); + } } diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportConstants.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportConstants.java index c648288..c2cb6b0 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportConstants.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportConstants.java @@ -27,6 +27,7 @@ public class ReportConstants { */ public static final String IMAGE_PREV_PAGE = GWT.getModuleBaseURL() + "../images/prev_p.gif"; - - + public static final String REPORT_ICON = GWT.getModuleBaseURL() + "../images/iconReport.png"; + + public static final String REPORT_REF_ICON = GWT.getModuleBaseURL() + "../images/reportRef.png"; } diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportGenerator.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportGenerator.java index 70fa853..a33a87d 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportGenerator.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportGenerator.java @@ -1,18 +1,10 @@ package org.gcube.portlets.user.reportgenerator.client; import org.gcube.portlets.user.reportgenerator.client.Presenter.Presenter; -import org.gcube.portlets.user.reportgenerator.client.toursteps.Intro; import org.gcube.portlets.user.workspace.client.AppControllerExplorer; import org.gcube.portlets.user.workspace.client.rpc.GWTWorkspaceServiceAsync; -import org.gcube.portlets.widgets.guidedtour.client.GCUBEGuidedTour; -import org.gcube.portlets.widgets.guidedtour.client.steps.GCUBETemplate1Text1Image; -import org.gcube.portlets.widgets.guidedtour.client.steps.GCUBETemplate2Text2Image; -import org.gcube.portlets.widgets.guidedtour.client.steps.TourStep; -import org.gcube.portlets.widgets.guidedtour.client.types.VerticalAlignment; import com.google.gwt.core.client.EntryPoint; -import com.google.gwt.core.client.GWT; -import com.google.gwt.core.client.RunAsyncCallback; import com.google.gwt.event.logical.shared.ResizeEvent; import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.user.client.Window; @@ -173,150 +165,7 @@ public class ReportGenerator implements EntryPoint { //showGuidedTour() ; } - private void showGuidedTour() { - - GWT.runAsync(GCUBEGuidedTour.class, new RunAsyncCallback() { - public void onSuccess() { - TourStep step1 = new GCUBETemplate1Text1Image(true) { - - @Override - public String setStepTitle() { - return "gCube Reporting"; - } - - @Override - public String setStepImage() { - return "images/tour/tour1.jpg"; - } - - @Override - public String setStepBody() { - return new Intro().getHTML(); - } - }; - - TourStep step2 = new GCUBETemplate1Text1Image(false) { - - @Override - public String setStepTitle() { - return "Structure View"; - } - - @Override - public String setStepImage() { - return "images/tour/tour2.jpg"; - } - @Override - public String setStepBody() { - return "
" + - "
" + - "Use the Report Structure View to see your report structure. (View > Structure)" + - "
" + - "
" + - "Use the Report Structure View to navigate through your report." + - "
" + - "
"; - } - }; - TourStep step3 = new GCUBETemplate2Text2Image(false) { - - @Override - public String setStepTitle() { - return "User Comments"; - } - - @Override - public String setStepImage() { - return "images/tour/tourComment.jpg"; - } - - @Override - public String setStepBody() { - return "
" + - "
" + - "Use comments to collaborate with your colleagues." + - "
" + - "
"; - } - - @Override - public String setStepOtherImage() { - return "images/tour/tourFormat.jpg"; - } - - @Override - public String setStepOtherBody() { - return "
" + - "
" + - "Format text as you would in a word processor using the Formatting Bar." + - "
" + - "
"; - } - }; - TourStep step4 = new GCUBETemplate1Text1Image(false) { - - @Override - public String setStepTitle() { - return "Bibliography"; - } - - @Override - public String setStepImage() { - return "images/tour/tourBiblio.jpg"; - } - - @Override - public String setStepBody() { - return "
" + - "
" + - "Use the Bibliography to add references" + - "
" + - "
"; - } - }; - - TourStep step5 = new GCUBETemplate1Text1Image(false) { - - @Override - public String setStepTitle() { - return "Export"; - } - - @Override - public String setStepImage() { - return "images/tour/tourExports.jpg"; - } - - @Override - public String setStepBody() { - return "
" + - "
" + - "Generate different export formats such as OpenXML (docx) or HTML." + - "
" + - "
"; - } - }; - //step1.setTextVerticalAlignment(VerticalAlignment.ALIGN_MIDDLE); - step2.setTextVerticalAlignment(VerticalAlignment.ALIGN_MIDDLE); - step3.setTextVerticalAlignment(VerticalAlignment.ALIGN_MIDDLE); - step4.setTextVerticalAlignment(VerticalAlignment.ALIGN_MIDDLE); - step5.setTextVerticalAlignment(VerticalAlignment.ALIGN_MIDDLE); - String guideUrl = "https://gcube.wiki.gcube-system.org/gcube/index.php/Common_Functionality#Report_Generation"; - GCUBEGuidedTour gt = new GCUBEGuidedTour("gCube Reports Generator", ReportGenerator.class.getName(), guideUrl, 780, 450, false); - gt.addStep(step1); - gt.addStep(step2); - gt.addStep(step3); - gt.addStep(step4); - gt.addStep(step5); - gt.openTour(); - } - - public void onFailure(Throwable reason) { - Window.alert("There are networks problem, please check your connection."); - } - }); - } /** * diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportService.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportService.java index 2edce4b..ddc90f3 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportService.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportService.java @@ -1,12 +1,16 @@ package org.gcube.portlets.user.reportgenerator.client; +import java.util.ArrayList; + import org.gcube.portlets.d4sreporting.common.shared.Model; import org.gcube.portlets.d4sreporting.common.shared.RepTimeSeries; import org.gcube.portlets.d4sreporting.common.shared.Table; import org.gcube.portlets.widgets.exporter.shared.SaveReportFileException; import org.gcube.portlets.widgets.exporter.shared.SaveReportFileExistException; import org.gcube.portlets.widgets.exporter.shared.TypeExporter; +import org.gcube.portlets.widgets.userselection.shared.ItemSelectableBean; import org.gcube.portlets.user.reportgenerator.shared.SessionInfo; +import org.gcube.portlets.user.reportgenerator.shared.VMETypeIdentifier; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; @@ -16,6 +20,13 @@ import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; */ @RemoteServiceRelativePath("ReportServiceImpl") public interface ReportService extends RemoteService{ + + ArrayList listVMEReports(); + + ArrayList listVMEReportRefByType(VMETypeIdentifier refType); + + Model importVMEReport(String id, String name); + String save(String filePath, String workspaceFolderId, String ItemName, TypeExporter type, boolean overwrite) throws SaveReportFileException, SaveReportFileExistException; diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportServiceAsync.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportServiceAsync.java index de149ce..11c423c 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportServiceAsync.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ReportServiceAsync.java @@ -1,10 +1,14 @@ package org.gcube.portlets.user.reportgenerator.client; +import java.util.ArrayList; + import org.gcube.portlets.d4sreporting.common.shared.Model; import org.gcube.portlets.d4sreporting.common.shared.RepTimeSeries; import org.gcube.portlets.d4sreporting.common.shared.Table; import org.gcube.portlets.widgets.exporter.shared.TypeExporter; +import org.gcube.portlets.widgets.userselection.shared.ItemSelectableBean; import org.gcube.portlets.user.reportgenerator.shared.SessionInfo; +import org.gcube.portlets.user.reportgenerator.shared.VMETypeIdentifier; import com.google.gwt.user.client.rpc.AsyncCallback; /** @@ -70,4 +74,8 @@ public interface ReportServiceAsync { void save(String filePath, String workspaceFolderId, String ItemName, TypeExporter type, boolean overwrite, AsyncCallback callback); void renewHTTPSession(AsyncCallback callback); + void listVMEReports(AsyncCallback> callback); + void importVMEReport(String id, String name, AsyncCallback callback); + void listVMEReportRefByType(VMETypeIdentifier refType, + AsyncCallback> callback); } diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ToolboxPanel.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ToolboxPanel.java index a688deb..7336717 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/ToolboxPanel.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/ToolboxPanel.java @@ -29,10 +29,10 @@ public class ToolboxPanel extends SimplePanel { public ToolboxPanel(AppControllerExplorer appController) { this.appController = appController; - AsyncTreePanel tp = appController.getTree(TOOLBOX_WIDTH, TOOLBOX_HEIGHT); - this.tp = tp; - add(tp); - this.appController.hideSharingFacilities(); //sharing disabled we have problems from Reports +// AsyncTreePanel tp = appController.getTree(TOOLBOX_WIDTH, TOOLBOX_HEIGHT); +// this.tp = tp; +// add(tp); +// this.appController.hideSharingFacilities(); //sharing disabled we have problems from Reports } public void showExportedVersion(String id, String fileName) { diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/model/TemplateComponent.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/model/TemplateComponent.java index 9e84064..a5e4d88 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/model/TemplateComponent.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/model/TemplateComponent.java @@ -301,6 +301,9 @@ public class TemplateComponent { HTML comment = new HTML(); comment.setStyleName("commentArea"); String contentC = (String) sc.getPossibleContent(); + if (contentC == null) { + contentC = "Empty Comment"; + } // replace all the line braks by
, and all the double spaces by the html version   String htmlPreservedLineBreaks2 = contentC.replaceAll("(\r\n|\n)","
"); htmlPreservedLineBreaks2 = htmlPreservedLineBreaks2.replaceAll("\\s\\s","  "); @@ -309,6 +312,9 @@ public class TemplateComponent { break; case INSTRUCTION: String content = (String) sc.getPossibleContent(); + if (content == null) { + content = "Empty Instruction"; + } // replace all the line braks by
, and all the double spaces by the html version   String htmlPreservedLineBreaks = content.replaceAll("(\r\n|\n)","
"); htmlPreservedLineBreaks = htmlPreservedLineBreaks.replaceAll("\\s\\s","  "); @@ -316,6 +322,7 @@ public class TemplateComponent { instr.setStyleName("instructionArea"); instr.setHTML(htmlPreservedLineBreaks); this.content = instr; + break; case TIME_SERIES: TSArea tsa; @@ -481,7 +488,7 @@ public class TemplateComponent { content = tuples; break; } - + return new BasicComponent(x, y, width, height, templatePage, type, idInBasket, "param empty", content, this.doubleColLayout, isLocked(), metadata); } @@ -497,7 +504,7 @@ public class TemplateComponent { } return sComps; } - + /** * this method constructs a Sequence that can be serializable from the TextTableImage Widget * @param repSeq @@ -510,7 +517,7 @@ public class TemplateComponent { } return sComps; } - + /** diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/ClientTuple.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/ClientTuple.java index 4adf9f1..9d8b8be 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/ClientTuple.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/ClientTuple.java @@ -6,7 +6,9 @@ import org.gcube.portlets.d4sreporting.common.shared.Tuple; import org.gcube.portlets.d4sreporting.common.shared.RepeatableSequence; import org.gcube.portlets.user.reportgenerator.client.Presenter.Presenter; import org.gcube.portlets.user.reportgenerator.client.model.TemplateComponent; +import org.gcube.portlets.user.reportgenerator.shared.VMETypeIdentifier; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.VerticalPanel; /** @@ -21,7 +23,7 @@ public class ClientTuple extends Composite implements ClientSequence { private ArrayList tupleList; private SequenceWidget first; - + private Presenter p; /** * s @@ -29,6 +31,7 @@ public class ClientTuple extends Composite implements ClientSequence { * @param ms */ public ClientTuple(Presenter p, ArrayList tupleList) { + this.p = p; this.tupleList = tupleList; for (Tuple seq : tupleList) { if (myPanel.getWidgetCount()==0) { // if is the first one @@ -67,7 +70,22 @@ public class ClientTuple extends Composite implements ClientSequence { @Override public boolean add(RepeatableSequence sequence) { - return false; + Tuple tuple = (Tuple) sequence; + VMETypeIdentifier type2Pass = null; + if (tuple.getKey().equals("GENERAL_MEASURE")) + type2Pass = VMETypeIdentifier.GeneralMeasure; + else if (tuple.getKey().equals("INFORMATION_SOURCE")) + type2Pass = VMETypeIdentifier.InformationSource; + else if (tuple.getKey().equals("FISHERY_AREA_HISTORY")) + type2Pass = VMETypeIdentifier.FisheryAreasHistory; + else if (tuple.getKey().equals("VMES_HISTORY")) + type2Pass = VMETypeIdentifier.VmesHistory; + else { + Window.alert("Could not find any valid Report Ref, got " + tuple.getKey()); + return false; + } + p.showVMERefAssociateDialog(type2Pass); + return true; } diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/SequenceWidget.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/SequenceWidget.java index 13c0c03..754d155 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/SequenceWidget.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/client/targets/SequenceWidget.java @@ -13,6 +13,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; @@ -97,9 +98,15 @@ public class SequenceWidget extends Composite { addAnother(); } }); + + } } + private void selectNew() { + owner.add(repSequence); + } + public void enableClear() { Button clearB = new Button("Clear Association"); clearB.getElement().getStyle().setWidth(130, Unit.PX); @@ -137,6 +144,14 @@ public class SequenceWidget extends Composite { selectEntryB.getElement().getStyle().setWidth(130, Unit.PX); selectEntryB.getElement().getStyle().setMargin(10, Unit.PX); selectEntryB.addStyleName("deleteAssociationButton"); + + selectEntryB.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + selectNew(); + } + }); + buttonsWrapperPanel.add(selectEntryB); } diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.java b/src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.java deleted file mode 100644 index 01a2c47..0000000 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * - */ -package org.gcube.portlets.user.reportgenerator.client.toursteps; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.Element; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.user.client.ui.HTML; - -/** - * @author massi - * - */ -public class Intro extends HTML { - - private static IntroUiBinder uiBinder = GWT.create(IntroUiBinder.class); - - interface IntroUiBinder extends UiBinder { - } - - public Intro() { - setHTML(uiBinder.createAndBindUi(this).getInnerHTML()); - } - -} diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.ui.xml b/src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.ui.xml deleted file mode 100644 index 9df30c6..0000000 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/client/toursteps/Intro.ui.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - /* Add CSS here. See the GWT docs on UI Binder for more details */ - .important { - font-weight: bold; - } - -
- -
-
- gCube Reporting - allows users to create Reports and generate different - export formats - (OpenXML, HTML, PDF) based on results retrieved from the - infrastructure. -
-
- gCube Templates are loaded by this - gCube Report Generator - to produce actual reports. -
-
- Discover - gCube Reporting features through this quick tour. -
-
-
-
\ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/server/servlet/ReportServiceImpl.java b/src/main/java/org/gcube/portlets/user/reportgenerator/server/servlet/ReportServiceImpl.java index 1b7b926..f431de9 100644 --- a/src/main/java/org/gcube/portlets/user/reportgenerator/server/servlet/ReportServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/server/servlet/ReportServiceImpl.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.Random; import java.util.UUID; import java.util.Vector; @@ -30,6 +31,9 @@ import org.apache.commons.io.IOUtils; import org.gcube.application.framework.accesslogger.library.impl.AccessLogger; import org.gcube.application.framework.core.session.ASLSession; import org.gcube.application.framework.core.session.SessionManager; +import org.gcube.application.reporting.ReportsModeler; +import org.gcube.application.rsg.service.dto.ReportEntry; +import org.gcube.application.rsg.service.dto.ReportType; import org.gcube.applicationsupportlayer.social.ApplicationNotificationsManager; import org.gcube.applicationsupportlayer.social.NotificationsManager; import org.gcube.common.homelibrary.home.HomeLibrary; @@ -72,9 +76,11 @@ import org.gcube.portlets.user.reportgenerator.server.servlet.loggers.OpenWorkfl import org.gcube.portlets.user.reportgenerator.server.servlet.loggers.SaveWorkflowLogEntry; import org.gcube.portlets.user.reportgenerator.shared.SessionInfo; import org.gcube.portlets.user.reportgenerator.shared.UserBean; +import org.gcube.portlets.user.reportgenerator.shared.VMETypeIdentifier; import org.gcube.portlets.widgets.exporter.shared.SaveReportFileException; import org.gcube.portlets.widgets.exporter.shared.SaveReportFileExistException; import org.gcube.portlets.widgets.exporter.shared.TypeExporter; +import org.gcube.portlets.widgets.userselection.shared.ItemSelectableBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,7 +107,7 @@ public class ReportServiceImpl extends RemoteServiceServlet implements ReportSe private boolean withinPortal = true; private static final String TEST_SCOPE = "/gcube/devsec/devVRE"; - + /** * @@ -291,7 +297,7 @@ public class ReportServiceImpl extends RemoteServiceServlet implements ReportSe } _log.info("\n\n** zipToExtract: " + zipToExtract); - + if (bi.getFolderItemType() == FolderItemType.REPORT || bi.getFolderItemType() == FolderItemType.REPORT_TEMPLATE) { if (fromBasket) { @@ -389,13 +395,15 @@ public class ReportServiceImpl extends RemoteServiceServlet implements ReportSe _log.debug("seekModel: modelName DIFFERENT upgrading"); File dirToLookIn = new File(templatePath); File[] innerFiles = dirToLookIn.listFiles(); - for (int i = 0; i < innerFiles.length; i++) + for (int i = 0; i < innerFiles.length; i++) { + _log.debug("scanning files in extracted folder: " + innerFiles[i].getName()); if (innerFiles[i].getName().endsWith(".d4st")) { String toReturn = innerFiles[i].getName(); toReturn = toReturn.substring(0, toReturn.length()-5); _log.debug("seekModel: returning.. =" + toReturn); return toReturn; } + } } throw new FileNotFoundException(); } @@ -1188,7 +1196,7 @@ public class ReportServiceImpl extends RemoteServiceServlet implements ReportSe Model toConvert = null; try { String path = myUtil.getTemplateFolder(getVreName(), getUsername()); - + String reportFileName = seekModel(templatePath, UUID.randomUUID().toString()); //random name just to make sure it look for the name String pathToReport = path + "CURRENT_OPEN/"+reportFileName+".d4st"; _log.trace("WF PathToReport = " + pathToReport); @@ -1443,4 +1451,92 @@ public class ReportServiceImpl extends RemoteServiceServlet implements ReportSe HttpSession session = this.getThreadLocalRequest().getSession(); _log.info("HTTP Session renewed" + new Date(session.getLastAccessedTime())); } + + @Override + public ArrayList listVMEReports() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + ArrayList toReturn = new ArrayList(); + ReportType type = new ReportType(); + type.setTypeIdentifier("Vme"); + + for (ReportEntry re : getFakeReports(type)) { + toReturn.add(new ItemSelectableBean(""+re.getId(), re.getName(), "", VMETypeIdentifier.Vme.toString())); + } + + return toReturn; + } + + @Override + public ArrayList listVMEReportRefByType(VMETypeIdentifier refType) { + if (refType == VMETypeIdentifier.Vme) + throw new IllegalArgumentException("VME Type is not a reference"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + ArrayList toReturn = new ArrayList(); + ReportType type = new ReportType(); + type.setTypeIdentifier(refType.toString()); + + for (ReportEntry re : getFakeReports(type)) { + toReturn.add(new ItemSelectableBean(""+re.getId(), re.getName(), "", refType.toString())); + } + return toReturn; + } + + private List getFakeReports(ReportType type) { + Random generator = new Random(); + int n = generator.nextInt(15) + 5; + ArrayList toReturn = new ArrayList(); + if (type.equals("Vme")) { + ReportEntry re = new ReportEntry(); + for (int i = 0; i < n; i++) { + re = new ReportEntry(); + re.setId(i); + re.setName( "VME Name " + i); + toReturn.add(re); + } + } else { + ReportEntry re = new ReportEntry(); + for (int i = 0; i < n; i++) { + re = new ReportEntry(); + re.setId(i); + re.setName( type.getTypeIdentifier() + "-" + i); + toReturn.add(re); + } + } + return toReturn; + } + + @Override + public Model importVMEReport(String id, String name) { + String reportName = "Sample VME Report imported with id: " + id; + ReportsModeler rm = new ReportsModeler( + UUID.randomUUID().toString(), + reportName, + getASLSession().getUsername(), + new Date(), + new Date(), + getASLSession().getUsername() + ); + rm.addInstruction(null); + rm.addTitle(name, false); + rm.addHeading(1, "VME Name (Non Editable) "); + rm.addTextInput("Corner Rise Seamounts"); + rm.addHeading(2, "This is a Heading of Level 2 that is editable", false); + rm.addTextInput("Corner Rise Seamounts2"); + rm.addHeading(3, "This is a Heading of Level 3 that is editable", false); + rm.addTextInput(); + try { + return rm.getReportInstance(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + } diff --git a/src/main/java/org/gcube/portlets/user/reportgenerator/shared/VMETypeIdentifier.java b/src/main/java/org/gcube/portlets/user/reportgenerator/shared/VMETypeIdentifier.java new file mode 100644 index 0000000..bf65631 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/reportgenerator/shared/VMETypeIdentifier.java @@ -0,0 +1,9 @@ +package org.gcube.portlets.user.reportgenerator.shared; + +public enum VMETypeIdentifier { + Vme, + GeneralMeasure, + InformationSource, + FisheryAreasHistory, + VmesHistory; +} diff --git a/src/main/resources/org/gcube/portlets/user/reportgenerator/ReportGenerator.gwt.xml b/src/main/resources/org/gcube/portlets/user/reportgenerator/ReportGenerator.gwt.xml index fc31b8a..dc04bce 100644 --- a/src/main/resources/org/gcube/portlets/user/reportgenerator/ReportGenerator.gwt.xml +++ b/src/main/resources/org/gcube/portlets/user/reportgenerator/ReportGenerator.gwt.xml @@ -6,10 +6,11 @@ - + - - + + diff --git a/src/main/webapp/ReportGenerator.css b/src/main/webapp/ReportGenerator.css index 170c592..d87c47f 100644 --- a/src/main/webapp/ReportGenerator.css +++ b/src/main/webapp/ReportGenerator.css @@ -707,13 +707,13 @@ tableBorder td { font-size: 20px; } -gwt-MenuBar { +.gwt-MenuBar { cursor: default; border: none; } .gwt-MenuBar-vertical { - background: #e3e8f3 url(images/hborder.png) repeat-x 0px -2003px; + background: #e3e8f3 url(images/hborder.png) repeat-x 0px -2003px !important; border: 1px solid #BBBBBB; } diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 7c4e2f1..c91c8ac 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -15,15 +15,15 @@ - - quicktourServlet - org.gcube.portlets.widgets.guidedtour.server.TourServiceImpl - + + + + - - quicktourServlet - /reports/quicktourServlet - + + + + diff --git a/src/main/webapp/images/iconReport.png b/src/main/webapp/images/iconReport.png new file mode 100644 index 0000000000000000000000000000000000000000..78ef51ef57467557907c345b2fd69af8601dee7e GIT binary patch literal 2893 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 literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/reportRef.png b/src/main/webapp/images/reportRef.png new file mode 100644 index 0000000000000000000000000000000000000000..f38e1e38f74800680eac196c3c0d930977c25957 GIT binary patch literal 1624 zcmV-e2B-OnP)OPV02>Kl!Vkj; z;y=IKwTh=tuw2a;nxHJE*u4wTIERJA7#$2C_6gk!m5CXZQ62aBy%(PYD@|7wuGeK9NIco065s%2{$ZmnAYwgy$Y#iJyB1<_ByURMc zrIHi7QP9C99!VeIVZrPgvm6KsWZZO6?FgLM6AVLjQ$>xjNF313=}LgIR|qSFwF{x% z<6I*$^bECLk?Xy;VigqT0-Mg2`9cM;x|s$MIxZ!!Comp%1U=S3djcN15z2wE+a}Zm z5UeBURe%to_N8f>xwKmctOT7MutZ27J03wV`7QfHn=>8lEFdIGSsW@t1+&rx5t>Y@ ziVrrM&05)^+8GP2Q<_bubh8G6omBHK9WZ|zI4FtT?tr0jqFw2w#EMZ-PB@)T^-T7v zL^P_`PNxG=^qI>Q)jr?ua6lr!9X$vzix6P2*==Ag4e*`V1<(HVSlsjt3JNyj_s*(L0?hAj4X7*Gg$22}NObqd{(T2!DF6eBNOWu{5f<`~d&QtF{};<%St4p{>%@-jJH*UYABzp&Ul$Ua-rX!#uX#(X zShYsvtynEyU#TcwTd}JBIghwv^%}AI&3y4rVUh57yh7r@!NcN{ZQDg{UA@T5TPXm< zD+j_G+Sb{_h`@^r+iY3PoIiypBAI}{(ZEzwSr(*0&Fy~GyH9BX!`wk*r~9NA1}kwrHjG1hM|K7V)4tb zK*Bm#ovFiv0giwGMA&s4K0MX@UI?O;;y4`+71!tUg>FH#CYtC!7PvN+!nyG~IEzlA z+4T@El$T@j*J zZ`|@^##CfvWI%$cBIKy4sUZv7aP8_7xwB{HOQRV88!?s`-Kj4`4@yoRojz{-mxduUtIM^uw&GrM zvuZlTyVaGKmeIL-$}ryBWxauHhrLn8`(7*8BlU W_Ko(*c3B?)0000