package com.griddynamics.jagger.webclient.client.trends; import com.google.gwt.cell.client.Cell; import com.google.gwt.cell.client.CheckboxCell; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.*; import com.google.gwt.event.logical.shared.*; import com.google.gwt.http.client.URL; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.HasDirection; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.safehtml.shared.SafeHtmlUtils; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.cellview.client.*; import com.google.gwt.user.client.History; 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.ui.*; import com.google.gwt.user.datepicker.client.DateBox; import com.google.gwt.view.client.*; import com.googlecode.gflot.client.*; import com.googlecode.gflot.client.options.*; import com.griddynamics.jagger.dbapi.dto.*; import com.griddynamics.jagger.dbapi.model.*; import com.griddynamics.jagger.util.FormatCalculator; import com.griddynamics.jagger.util.MonitoringIdUtils; import com.griddynamics.jagger.webclient.client.*; import com.griddynamics.jagger.webclient.client.components.*; import com.griddynamics.jagger.webclient.client.components.control.CheckHandlerMap; import com.griddynamics.jagger.webclient.client.components.control.SimpleNodeValueProvider; import com.griddynamics.jagger.webclient.client.data.*; import com.griddynamics.jagger.webclient.client.dto.*; import com.griddynamics.jagger.webclient.client.handler.ShowCurrentValueHoverListener; import com.griddynamics.jagger.webclient.client.handler.ShowTaskDetailsListener; import com.griddynamics.jagger.webclient.client.mvp.JaggerPlaceHistoryMapper; import com.griddynamics.jagger.webclient.client.resources.JaggerResources; import com.griddynamics.jagger.webclient.client.resources.SessionDataGridResources; import com.griddynamics.jagger.webclient.client.resources.SessionPagerResources; import com.sencha.gxt.data.shared.ModelKeyProvider; import com.sencha.gxt.data.shared.TreeStore; import com.sencha.gxt.widget.core.client.ContentPanel; import com.sencha.gxt.widget.core.client.tree.Tree; import java.util.*; /** * @author "Artem Kirillov" (akirillov@griddynamics.com) * @since 5/28/12 */ public class Trends extends DefaultActivity { interface TrendsUiBinder extends UiBinder<Widget, Trends> { } private TabIdentifier tabSummary; private TabIdentifier tabTrends; private TabIdentifier tabMetrics; private TabIdentifier tabNodes; private TagBox tagFilterBox; private List<TagDto> allTags; private boolean allTagsLoadComplete = true; private Set<String> tagNames = new HashSet<String>(); private DateTimeFormat dateFormatter = DateTimeFormat.getFormat(FormatCalculator.DATE_FORMAT); private static TrendsUiBinder uiBinder = GWT.create(TrendsUiBinder.class); @UiField TabLayoutPanel searchTabPanel; @UiField TabLayoutPanel mainTabPanel; @UiField PlotsPanel plotPanel; @UiField(provided = true) DataGrid<SessionDataDto> sessionsDataGrid; @UiField(provided = true) SimplePager sessionsPager; @UiField PlotsPanel plotTrendsPanel; @UiField ScrollPanel summaryPanelScrollPanel; @UiField SummaryPanel summaryPanel; @UiField NodesPanel nodesPanel; TextBox sessionIdsTextBox = new TextBox(); TextBox sessionTagsTextBox = new TextBox(); DateBox sessionsFrom = new DateBox(); DateBox sessionsTo = new DateBox(); @UiField HorizontalPanel tagsPanel; @UiField HorizontalPanel idsPanel; @UiField HorizontalPanel datesPanel; private Button tagButton; private Timer stopTypingSessionIdsTimer; private Timer stopTypingSessionTagsTimer; private PlotSaver plotSaver = new PlotSaver(); @UiHandler("uncheckSessionsButton") void handleUncheckSessionsButtonClick(ClickEvent e) { MultiSelectionModel model = (MultiSelectionModel<?>) sessionsDataGrid.getSelectionModel(); model.clear(); } @UiHandler("showCheckedSessionsButton") void handleShowCheckedSessionsButtonClick(ClickEvent e) { Set<SessionDataDto> sessionDataDtoSet = ((MultiSelectionModel<SessionDataDto>) sessionsDataGrid.getSelectionModel()).getSelectedSet(); filterSessions(sessionDataDtoSet); } @UiHandler("clearSessionFiltersButton") void handleClearSessionFiltersButtonClick(ClickEvent e) { sessionsTo.setValue(null, true); sessionsFrom.setValue(null, true); sessionTagsTextBox.setValue(null,true); sessionIdsTextBox.setValue(null, true); stopTypingSessionIdsTimer.schedule(10); stopTypingSessionTagsTimer.schedule(10); } @UiHandler("getHyperlink") void getHyperlink(ClickEvent event) { MultiSelectionModel<SessionDataDto> sessionModel = (MultiSelectionModel)sessionsDataGrid.getSelectionModel(); if (sessionModel.getSelectedSet().isEmpty()) { return; } Set<String> selectedSessionIds = new HashSet<String>(); for (SessionDataDto sessionDataDto : sessionModel.getSelectedSet()) { selectedSessionIds.add(sessionDataDto.getSessionId()); } Set<TaskDataDto> allSelectedTests = controlTree.getSelectedTests(); Map<Set<String>, List<TaskDataDto>> sessionsToTestsMap = new TreeMap<Set<String>, List<TaskDataDto>>( new Comparator<Set<String>>() { @Override public int compare(Set<String> o1, Set<String> o2) { boolean c1 = o1.containsAll(o2); boolean c2 = o2.containsAll(o1); if (c1 && c2) return 0; if (c1) return -1; return 1; } }); for (TaskDataDto taskDataDto : allSelectedTests) { Set<String> sessionIds = taskDataDto.getSessionIds(); selectedSessionIds.removeAll(sessionIds); if (sessionsToTestsMap.containsKey(sessionIds)) { sessionsToTestsMap.get(sessionIds).add(taskDataDto); } else { List<TaskDataDto> taskList = new ArrayList<TaskDataDto>(); taskList.add(taskDataDto); sessionsToTestsMap.put(sessionIds, taskList); } } if (!selectedSessionIds.isEmpty()) { sessionsToTestsMap.put(selectedSessionIds, null); } List<LinkFragment> linkFragments = new ArrayList<LinkFragment>(); for (Map.Entry<Set<String>, List<TaskDataDto>> sessionsToTestsEntry : sessionsToTestsMap.entrySet()) { List<TaskDataDto> tests = sessionsToTestsEntry.getValue(); LinkFragment linkFragment = new LinkFragment(); if (tests == null) { // this is fragment with no tests chosen linkFragment.setSelectedSessionIds(sessionsToTestsEntry.getKey()); linkFragments.add(linkFragment); continue; } Map<String, List<String>> trends = getTestTrendsMap(controlTree.getRootNode().getDetailsNode().getTests(), tests); HashSet<TestsMetrics> testsMetricses = new HashSet<TestsMetrics>(tests.size()); HashMap<String, TestsMetrics> map = new HashMap<String, TestsMetrics>(tests.size()); for (TaskDataDto taskDataDto : tests){ TestsMetrics testsMetrics = new TestsMetrics(taskDataDto.getTaskName(), new HashSet<String>(), new HashSet<String>()); TestNode testNode = controlTree.findTestNode(taskDataDto); if (testNode == null) continue; Set<MetricNode> checkedNodes = controlTree.getCheckedMetrics(testNode); if (checkedNodes.size() < testNode.getMetrics().size()) { for (MetricNode metricNode : checkedNodes) { for (MetricNameDto mnd : metricNode.getMetricNameDtoList()) { testsMetrics.getMetrics().add(mnd.getMetricName()); } } } testsMetricses.add(testsMetrics); map.put(taskDataDto.getTaskName(), testsMetrics); } for (Map.Entry<String, List<String>> entry : trends.entrySet()) { map.get(entry.getKey()).getTrends().addAll(entry.getValue()); } linkFragment.setSelectedSessionIds(sessionsToTestsEntry.getKey()); linkFragment.setSelectedTestsMetrics(testsMetricses); linkFragments.add(linkFragment); } TrendsPlace newPlace = new TrendsPlace( mainTabPanel.getSelectedIndex() == tabSummary.getTabIndex() ? tabSummary.getTabName() : mainTabPanel.getSelectedIndex() == tabTrends.getTabIndex() ? tabTrends.getTabName() : tabMetrics.getTabName() ); newPlace.setLinkFragments(linkFragments); String linkText = "http://" + Window.Location.getHost() + Window.Location.getPath() + Window.Location.getQueryString() + "#" + new JaggerPlaceHistoryMapper().getToken(newPlace); linkText = URL.encode(linkText); //create a dialog for copy link final DialogBox dialog = new DialogBox(false, true); dialog.setText("Share link"); dialog.setModal(true); dialog.setAutoHideEnabled(true); dialog.setPopupPosition(event.getClientX(), event.getClientY()); final TextArea textArea = new TextArea(); textArea.setText(linkText); textArea.setWidth("300px"); textArea.setHeight("40px"); //select text Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { textArea.setVisible(true); textArea.setFocus(true); textArea.selectAll(); } }); dialog.add(textArea); dialog.show(); } private String getMonitoringIdByMetricNameDtoId(String metricNameDtoId) { for (String defaultMonitoringParam : defaultMonitoringParameters.keySet()) { for (String id : defaultMonitoringParameters.get(defaultMonitoringParam)) { if (id.equals(metricNameDtoId)) { return defaultMonitoringParam; } } } return null; } private Map<String, List<String>> getTestTrendsMap(List<TestDetailsNode> tests, List<TaskDataDto> taskDataDtos) { Map<String, List<String>> resultMap = new LinkedHashMap<String, List<String>>(); for (TestDetailsNode test : tests) { if (controlTree.isChosen(test)) { if (taskDataDtos.contains(test.getTaskDataDto())) { Map<String,Boolean> uniteAgentsForMonitoringNames = new HashMap<String, Boolean>(); List<String> trends = new ArrayList<String>(); List<String> trendsMonitoring = new ArrayList<String>(); for (PlotNode plotNode : test.getMetrics()) { // temporary work around to make URL shorter starts here // it groups metricNameDtoId|agentName id to old monitoringId|agentName if (plotNode.getMetricNameDtoList().size() > 0) { MetricNameDto metricNameDto = plotNode.getMetricNameDtoList().get(0); if (metricNameDto.getOrigin() == MetricNameDto.Origin.TEST_GROUP_METRIC) { MonitoringIdUtils.MonitoringId monitoringId = MonitoringIdUtils.splitMonitoringMetricId(metricNameDto.getMetricName()); if (monitoringId != null) { String monitoringOldName = getMonitoringIdByMetricNameDtoId(monitoringId.getMonitoringName()); if (monitoringOldName != null) { if (!uniteAgentsForMonitoringNames.containsKey(monitoringOldName)){ uniteAgentsForMonitoringNames.put(monitoringOldName,true); } if (controlTree.isChecked(plotNode)) { trendsMonitoring.add(monitoringOldName + MonitoringIdUtils.AGENT_NAME_SEPARATOR + monitoringId.getAgentName()); // for this plotNode we are using work around. we will not go normal way continue; } else { // plot for some of agent of this monitoring metric is not checked // we will not process this monitoring metric in next workaround uniteAgentsForMonitoringNames.put(monitoringOldName,false); } } } } } // temporary work around to make URL shorter ends here // this is correct way, but is has very long URL if (controlTree.isChecked(plotNode)) { for (MetricNameDto metricNameDto : plotNode.getMetricNameDtoList()) { trends.add(metricNameDto.getMetricName()); } } } // temporary work around to make URL shorter SECOND ROUND starts here // it groups old monitoringId|agentName to old monitoringId List<String> newTrendMonitoring = new ArrayList<String>(); for (Map.Entry<String,Boolean> canWeOptimizeMore : uniteAgentsForMonitoringNames.entrySet()) { if (canWeOptimizeMore.getValue()) { // remove monitoringId|agentName Iterator<String> iterator = trendsMonitoring.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id.matches("^" + canWeOptimizeMore.getKey() + ".*")) { iterator.remove(); } } // leave monitoringId newTrendMonitoring.add(canWeOptimizeMore.getKey()); } } trendsMonitoring.addAll(newTrendMonitoring); // temporary work around to make URL shorter SECOND ROUND ends here trends.addAll(trendsMonitoring); resultMap.put(test.getTaskDataDto().getTaskName(), trends); } } } return resultMap; } private final Map<String, Set<MarkingDto>> markingsMap = new HashMap<String, Set<MarkingDto>>(); private FlowPanel loadIndicator; private final SessionDataAsyncDataProvider sessionDataProvider = new SessionDataAsyncDataProvider(); private final SessionDataForSessionIdsAsyncProvider sessionDataForSessionIdsAsyncProvider = new SessionDataForSessionIdsAsyncProvider(); private final SessionDataForDatePeriodAsyncProvider sessionDataForDatePeriodAsyncProvider = new SessionDataForDatePeriodAsyncProvider(); private final SessionDataForSessionTagsAsyncProvider sessionDataForSessionTagsAsyncProvider = new SessionDataForSessionTagsAsyncProvider(); @UiField Widget widget; ControlTree<String> controlTree; private final ModelKeyProvider <AbstractIdentifyNode> modelKeyProvider = new ModelKeyProvider<AbstractIdentifyNode>() { @Override public String getKey(AbstractIdentifyNode item) { return item.getId(); } }; @UiField SimplePanel controlTreePanel; /** * used to disable sessionDataGrid while rpc call */ @UiField ContentPanel sessionDataGridContainer; public Trends(JaggerResources resources) { super(resources); createWidget(); } private TrendsPlace place; private boolean selectTests = false; /** * fields that contain gid/plot information * to provide rendering in time of choosing special tab(mainTab) to avoid view problems */ private HashMap<MetricNode, SummaryIntegratedDto> chosenMetrics = new HashMap<MetricNode, SummaryIntegratedDto>(); private Map<MetricNode, PlotIntegratedDto> chosenPlots = new HashMap<MetricNode, PlotIntegratedDto>(); /** * Field to hold number of sessions that were chosen. * spike for rendering metrics plots */ private ArrayList<String> chosenSessions = new ArrayList<String>(); //tells if trends plot should be redraw private boolean hasChanged = false; public void updatePlace(TrendsPlace place){ if (this.place != null) return; this.place = place; final TrendsPlace finalPlace = this.place; if (place.getSelectedSessionIds().isEmpty()){ noSessionsFromLink(); return; } loadRangeForSessionIds(place.getSelectedSessionIds()); SessionDataService.Async.getInstance().getBySessionIds(0, place.getSelectedSessionIds().size(), place.getSelectedSessionIds(), new AsyncCallback<PagedSessionDataDto>() { @Override public void onFailure(Throwable caught) { new ExceptionPanel(finalPlace , caught.getMessage()); noSessionsFromLink(); } @Override public void onSuccess(PagedSessionDataDto result) { for (SessionDataDto session : result.getSessionDataDtoList()){ sessionsDataGrid.getSelectionModel().setSelected(session, true); } sessionsDataGrid.getSelectionModel().addSelectionChangeHandler(new SessionSelectChangeHandler()); sessionsDataGrid.getSelectionModel().setSelected(result.getSessionDataDtoList().iterator().next(), true); chooseTab(finalPlace.getToken()); } }); History.newItem(NameTokens.EMPTY); } private WebClientProperties webClientProperties = new WebClientProperties(); private Map<String,Set<String>> defaultMonitoringParameters = Collections.emptyMap(); public void getPropertiesUpdatePlace(final TrendsPlace place){ CommonDataService.Async.getInstance().getWebClientStartProperties(new AsyncCallback<WebClientStartProperties>() { @Override public void onFailure(Throwable caught) { new ExceptionPanel("Default properties will be used. Exception while properties retrieving: " + caught.getMessage()); updatePlace(place); } @Override public void onSuccess(WebClientStartProperties result) { webClientProperties = result.getWebClientProperties(); defaultMonitoringParameters = result.getDefaultMonitoringParameters(); updatePlace(place); } }); } private void noSessionsFromLink() { sessionsDataGrid.getSelectionModel().addSelectionChangeHandler(new SessionSelectChangeHandler()); selectTests = true; chooseTab(place.getToken()); } private void loadRangeForSessionIds(Set<String> sessionIds){ final int rangeLength = sessionsDataGrid.getVisibleRange().getLength(); SessionDataService.Async.getInstance().getStartPosition(sessionIds, new AsyncCallback<Long>() { @Override public void onFailure(Throwable caught) { new ExceptionPanel(caught.getMessage()); } @Override public void onSuccess(Long result) { sessionsDataGrid.setVisibleRange(result.intValue(), rangeLength); } }); } private void filterSessions(Set<SessionDataDto> sessionDataDtoSet) { if (sessionDataDtoSet == null || sessionDataDtoSet.isEmpty()) { sessionIdsTextBox.setText(null); sessionTagsTextBox.setText(null); stopTypingSessionIdsTimer.schedule(10); stopTypingSessionTagsTimer.schedule(10); return; } final StringBuilder builder = new StringBuilder(); boolean first = true; for (SessionDataDto sessionDataDto : sessionDataDtoSet) { if (!first) { builder.append("/"); } builder.append(sessionDataDto.getSessionId()); first = false; } sessionIdsTextBox.setText(builder.toString()); stopTypingSessionIdsTimer.schedule(10); } @Override protected Widget initializeWidget() { return widget; } private void createWidget() { setupSessionDataGrid(); setupPager(); setupLoadIndicator(); uiBinder.createAndBindUi(this); setupTabPanel(); setupSearchTabPanel(); setupSessionNumberTextBox(); setupSessionTagsTextBox(); setupSessionsDateRange(); setupControlTree(); } private final Widget NO_SESSION_CHOSEN = new Label("Choose at least One session"); private void setupControlTree() { controlTree = new ControlTree<String>(new TreeStore<AbstractIdentifyNode>(modelKeyProvider), new SimpleNodeValueProvider()); setupControlTree(controlTree); Label label = new Label("Choose at least One session"); label.setHorizontalAlignment(HasHorizontalAlignment.HorizontalAlignmentConstant.startOf(HasDirection.Direction.DEFAULT)); label.setStylePrimaryName(JaggerResources.INSTANCE.css().centered()); label.setHeight("100%"); NO_SESSION_CHOSEN.setStyleName(JaggerResources.INSTANCE.css().controlFont()); controlTreePanel.add(NO_SESSION_CHOSEN); } private void setupControlTree(ControlTree<String> tree) { tree.setTitle("Control Tree"); tree.setCheckable(true); tree.setCheckStyle(Tree.CheckCascade.NONE); tree.setCheckNodes(Tree.CheckNodes.BOTH); tree.setWidth("100%"); tree.setHeight("100%"); CheckHandlerMap.setTree(tree); plotPanel.setControlTree(tree); plotTrendsPanel.setControlTree(tree); } // @param yMinimum - set null if you don't want to set y minimum (will be set automatically) private SimplePlot createPlot(PlotsPanel panel, final String id, Markings markings, String xAxisLabel, Double yMinimum, boolean isMetric, final List<Integer> sessionIds) { PlotOptions plotOptions = PlotOptions.create(); plotOptions.setZoomOptions(ZoomOptions.create().setAmount(1.02)); plotOptions.setGlobalSeriesOptions(GlobalSeriesOptions.create() .setLineSeriesOptions(LineSeriesOptions.create().setLineWidth(1).setShow(true).setFill(0.1)) .setPointsOptions(PointsSeriesOptions.create().setRadius(1).setShow(true)).setShadowSize(0d)); plotOptions.setCanvasEnabled(true); FontOptions fontOptions = FontOptions.create() .setSize(11D) .setColor("black"); AxisOptions xAxisOptions = AxisOptions.create().setZoomRange(true) .setFont(fontOptions); if (!panel.isEmpty()) { xAxisOptions.setMaximum(panel.getMaxXAxisVisibleValue()); xAxisOptions.setMinimum(panel.getMinXAxisVisibleValue()); } else { if (!isMetric) xAxisOptions.setMinimum(0); } if (isMetric) { // todo : JFG-803 simplify trends plotting mechanism xAxisOptions .setTickDecimals(0) .setTickFormatter(new TickFormatter() { @Override public String formatTickValue(double tickValue, Axis axis) { if (tickValue >= 0 && tickValue < sessionIds.size()) return "" + sessionIds.get((int) tickValue); else return ""; } }); } plotOptions.addXAxisOptions(xAxisOptions); AxisOptions yAxisOptions = AxisOptions.create() .setFont(fontOptions).setLabelWidth(40).setTickFormatter(new TickFormatter() { private NumberFormat format; @Override public String formatTickValue(double tickValue, Axis axis) { // decided to show values as 7 positions only if (tickValue == 0) { return "0"; } if (format == null) { double tempDouble = tickValue * 5; format = NumberFormat.getFormat(FormatCalculator.getNumberFormat(tempDouble)); } return format.format(tickValue).replace('E', 'e'); } }) .setZoomRange(false); if (yMinimum != null) { yAxisOptions.setMinimum(yMinimum); } plotOptions.addYAxisOptions(yAxisOptions); plotOptions.setLegendOptions(LegendOptions.create().setShow(false)); plotOptions.setCanvasEnabled(true); if (markings == null) { // Make the grid hoverable plotOptions.setGridOptions(GridOptions.create().setHoverable(true)); } else { // Make the grid hoverable and add markings plotOptions.setGridOptions(GridOptions.create().setHoverable(true).setMarkings(markings).setClickable(true)); } // create the plot SimplePlot plot = new SimplePlot(plotOptions); plot.setHeight(200); plot.setWidth("100%"); final PopupPanel popup = new PopupPanel(); popup.addStyleName(getResources().css().infoPanel()); final HTML popupPanelContent = new HTML(); popup.add(popupPanelContent); // add hover listener if (isMetric) { plot.addHoverListener(new ShowCurrentValueHoverListener(popup, popupPanelContent, xAxisLabel, sessionIds), false); } else { plot.addHoverListener(new ShowCurrentValueHoverListener(popup, popupPanelContent, xAxisLabel, null), false); } if (!isMetric && markings != null && !markingsMap.isEmpty()) { final PopupPanel taskInfoPanel = new PopupPanel(); taskInfoPanel.setWidth("200px"); taskInfoPanel.addStyleName(getResources().css().infoPanel()); final HTML taskInfoPanelContent = new HTML(); taskInfoPanel.add(taskInfoPanelContent); taskInfoPanel.setAutoHideEnabled(true); plot.addClickListener(new ShowTaskDetailsListener(id, markingsMap, taskInfoPanel, 200, taskInfoPanelContent), false); } return plot; } private void setupTabPanel(){ final int indexSummary = 0; final int indexTrends = 1; final int indexMetrics = 2; final int indexNodes = 3; tabSummary = new TabIdentifier(NameTokens.SUMMARY,indexSummary); tabTrends = new TabIdentifier(NameTokens.TRENDS,indexTrends); tabMetrics = new TabIdentifier(NameTokens.METRICS,indexMetrics); tabNodes = new TabIdentifier(NameTokens.NODES,indexNodes); mainTabPanel.addSelectionHandler(new SelectionHandler<Integer>() { @Override public void onSelection(SelectionEvent<Integer> event) { int selected = event.getSelectedItem(); switch (selected) { case indexSummary: onSummaryTabSelected(); break; case indexTrends: onTrendsTabSelected(); break; case indexMetrics: onMetricsTabSelected(); break; case indexNodes: onNodesTabSelected(); default: } } }); } private boolean needRefresh = false; private void onSummaryTabSelected() { mainTabPanel.forceLayout(); controlTree.onSummaryTrendsTab(); // to make columns fit 100% width if grid created not on Summary Tab //summaryPanel.getSessionComparisonPanel().refresh(); if (needRefresh) { summaryPanel.getSessionComparisonPanel().refresh(); needRefresh = false; } } private void onTrendsTabSelected() { mainTabPanel.forceLayout(); controlTree.onSummaryTrendsTab(); if (!chosenMetrics.isEmpty() && hasChanged) { for(Map.Entry<MetricNode, SummaryIntegratedDto> entry : chosenMetrics.entrySet()) { String plotId = entry.getKey().getId(); if (plotTrendsPanel.containsElementWithId(plotId)) { // plot already presented on trends panel continue; } renderPlots( plotTrendsPanel, entry.getKey(), entry.getValue().getPlotIntegratedDto(), plotId, true ); plotTrendsPanel.scrollToBottom(); } hasChanged = false; } } private void onMetricsTabSelected() { mainTabPanel.forceLayout(); controlTree.onMetricsTab(); for (MetricNode metricNode : chosenPlots.keySet()) { String id = metricNode.getId(); if (!plotPanel.containsElementWithId(id)) { renderPlots(plotPanel, metricNode, chosenPlots.get(metricNode), id); plotPanel.scrollToBottom(); } } } private void onNodesTabSelected() { mainTabPanel.forceLayout(); controlTree.onSummaryTrendsTab(); nodesPanel.getNodeInfo(); } private void chooseTab(String token) { if (tabSummary.getTabName().equals(token)) { mainTabPanel.selectTab(tabSummary.getTabIndex()); } else if (tabTrends.getTabName().equals(token)) { mainTabPanel.selectTab(tabTrends.getTabIndex()); } else if (tabMetrics.getTabName().equals(token)) { mainTabPanel.selectTab(tabMetrics.getTabIndex()); } else if (tabNodes.getTabName().equals(token)){ mainTabPanel.selectTab(tabNodes.getTabIndex()); } else { new ExceptionPanel("Unknown tab with name " + token + " selected"); } } private void setupSessionDataGrid() { SessionDataGridResources resources = GWT.create(SessionDataGridResources.class); sessionsDataGrid = new DataGrid<SessionDataDto>(15, resources); sessionsDataGrid.setEmptyTableWidget(new Label("No Sessions")); // Add a selection model so we can select cells. final SelectionModel<SessionDataDto> selectionModel = new MultiSelectionModel<SessionDataDto>(new ProvidesKey<SessionDataDto>() { @Override public Object getKey(SessionDataDto item) { return item.getSessionId(); } }); sessionsDataGrid.setSelectionModel(selectionModel, DefaultSelectionEventManager.<SessionDataDto>createCheckboxManager()); // Checkbox column. This table will uses a checkbox column for selection. // Alternatively, you can call dataGrid.setSelectionEnabled(true) to enable mouse selection. Column<SessionDataDto, Boolean> checkColumn = new Column<SessionDataDto, Boolean>(new CheckboxCell(true, false)) { @Override public Boolean getValue(SessionDataDto object) { // Get the value from the selection model. return selectionModel.isSelected(object); } }; sessionsDataGrid.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>")); sessionsDataGrid.setColumnWidth(checkColumn, 40, Style.Unit.PX); TextColumn<SessionDataDto> nameColumn = new TextColumn<SessionDataDto>() { @Override public String getCellStyleNames(Cell.Context context, SessionDataDto object) { return super.getCellStyleNames(context, object) + " " + JaggerResources.INSTANCE.css().controlFont(); } @Override public String getValue(SessionDataDto object) { return object.getName(); } }; sessionsDataGrid.addColumn(nameColumn, "Name"); sessionsDataGrid.setColumnWidth(nameColumn, 25, Style.Unit.PCT); TextColumn<SessionDataDto> startDateColumn = new TextColumn<SessionDataDto>() { @Override public String getCellStyleNames(Cell.Context context, SessionDataDto object) { return super.getCellStyleNames(context, object) + " " + JaggerResources.INSTANCE.css().controlFont(); } @Override public String getValue(SessionDataDto object) { return dateFormatter.format(object.getStartDate()); } }; sessionsDataGrid.addColumn(startDateColumn, "Start Date"); sessionsDataGrid.setColumnWidth(startDateColumn, 30, Style.Unit.PCT); TextColumn<SessionDataDto> endDateColumn = new TextColumn<SessionDataDto>() { @Override public String getCellStyleNames(Cell.Context context, SessionDataDto object) { return super.getCellStyleNames(context, object) + " " + JaggerResources.INSTANCE.css().controlFont(); } @Override public String getValue(SessionDataDto object) { return dateFormatter.format(object.getEndDate()); } }; sessionsDataGrid.addColumn(endDateColumn, "End Date"); sessionsDataGrid.setColumnWidth(endDateColumn, 30, Style.Unit.PCT); sessionDataProvider.addDataDisplay(sessionsDataGrid); } private void setupPager() { SimplePager.Resources pagerResources = GWT.create(SessionPagerResources.class); sessionsPager = new SimplePager(SimplePager.TextLocation.CENTER, pagerResources, false, 0, true); //sessionsPager.setStylePrimaryName(JaggerResources.INSTANCE.css().controlFont()); sessionsPager.setDisplay(sessionsDataGrid); } private void setupLoadIndicator() { ImageResource imageResource = getResources().getLoadIndicator(); Image image = new Image(imageResource); loadIndicator = new FlowPanel(); loadIndicator.addStyleName(getResources().css().centered()); loadIndicator.add(image); } private void setupSessionNumberTextBox() { stopTypingSessionIdsTimer = new Timer() { @Override public void run() { final String currentContent = sessionIdsTextBox.getText().trim(); // If session ID text box is empty then load all sessions if (currentContent.isEmpty()) { sessionDataProvider.addDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionIdsAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); return; } Set<String> sessionIds = new HashSet<String>(); if (currentContent.contains(",") || currentContent.contains(";") || currentContent.contains("/")) { sessionIds.addAll(Arrays.asList(currentContent.split("\\s*[,;/]\\s*"))); } else { sessionIds.add(currentContent); } sessionDataForSessionIdsAsyncProvider.setSessionIds(sessionIds); sessionDataProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForDatePeriodAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionTagsAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionIdsAsyncProvider.addDataDisplayIfNotExists(sessionsDataGrid); } }; sessionIdsTextBox.addKeyUpHandler(new KeyUpHandler() { @Override public void onKeyUp(KeyUpEvent event) { sessionsFrom.setValue(null, true); sessionsTo.setValue(null, true); sessionTagsTextBox.setValue(null, true); stopTypingSessionIdsTimer.schedule(500); } }); } private void setupSessionsDateRange() { DateTimeFormat format = DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.YEAR_MONTH_NUM_DAY); sessionsFrom.setFormat(new DateBox.DefaultFormat(format)); sessionsTo.setFormat(new DateBox.DefaultFormat(format)); sessionsFrom.getTextBox().addValueChangeHandler(new EmptyDateBoxValueChangePropagator(sessionsFrom)); sessionsTo.getTextBox().addValueChangeHandler(new EmptyDateBoxValueChangePropagator(sessionsTo)); final ValueChangeHandler<Date> valueChangeHandler = new ValueChangeHandler<Date>() { @Override public void onValueChange(ValueChangeEvent<Date> dateValueChangeEvent) { sessionTagsTextBox.setValue(null, true); sessionIdsTextBox.setValue(null, true); Date fromDate = sessionsFrom.getValue(); Date toDate = sessionsTo.getValue(); if (fromDate == null || toDate == null) { sessionDataProvider.addDataDisplayIfNotExists(sessionsDataGrid); sessionDataForDatePeriodAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); return; } sessionDataForDatePeriodAsyncProvider.setDateRange(fromDate, toDate); sessionDataProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionIdsAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionTagsAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForDatePeriodAsyncProvider.addDataDisplayIfNotExists(sessionsDataGrid); } }; sessionsTo.addValueChangeHandler(valueChangeHandler); sessionsFrom.addValueChangeHandler(valueChangeHandler); } private void setupSessionTagsTextBox() { stopTypingSessionTagsTimer = new Timer() { @Override public void run() { final String generalContent = sessionTagsTextBox.getText().trim(); // If session tags text box is empty then load all sessions if (generalContent.isEmpty()) { sessionDataProvider.addDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionTagsAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); return; } if (generalContent.contains(",") || generalContent.contains(";") || generalContent.contains("/")) { tagNames.addAll(Arrays.asList(generalContent.split("\\s*[,;/]\\s*"))); } else { tagNames.add(generalContent); } sessionDataForSessionTagsAsyncProvider.setTagNames(tagNames); sessionDataProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForDatePeriodAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionIdsAsyncProvider.removeDataDisplayIfNotExists(sessionsDataGrid); sessionDataForSessionTagsAsyncProvider.addDataDisplayIfNotExists(sessionsDataGrid); } }; sessionTagsTextBox.addKeyUpHandler(new KeyUpHandler() { @Override public void onKeyUp(KeyUpEvent event) { sessionsTo.setValue(null, true); sessionsFrom.setValue(null, true); sessionIdsTextBox.setValue(null, true); tagNames.clear(); stopTypingSessionTagsTimer.schedule(500); } }); tagFilterBox.addCloseHandler(new CloseHandler<PopupPanel>() { @Override public void onClose(CloseEvent<PopupPanel> popupPanelCloseEvent) { sessionsTo.setValue(null, true); sessionsFrom.setValue(null, true); sessionIdsTextBox.setValue(null, true); if (!tagNames.isEmpty()) sessionTagsTextBox.setValue(toParsableString(tagNames)); tagNames.clear(); stopTypingSessionTagsTimer.schedule(500); } }); } private void renderPlots(PlotsPanel panel, MetricNode metricNode, PlotIntegratedDto plotSeriesDto, String id) { renderPlots(panel, metricNode, plotSeriesDto, id, false); } private void renderPlots(final PlotsPanel panel, MetricNode metricNode, PlotIntegratedDto plotSeriesDto, String id, boolean isTrend) { Markings markings = null; if (plotSeriesDto.getMarkingSeries() != null) { markings = Markings.create(); for (MarkingDto plotDatasetDto : plotSeriesDto.getMarkingSeries()) { double x = plotDatasetDto.getValue(); markings.addMarking(Marking.create().setX(com.googlecode.gflot.client.options.Range.create().setFrom(x).setTo(x)).setLineWidth(1).setColor(plotDatasetDto.getColor())); } markingsMap.put(id, new TreeSet<MarkingDto>(plotSeriesDto.getMarkingSeries())); } final SimplePlot plot; List<Integer> trendSessionIds = null; if (isTrend) { // Trends plot panel // todo : JFG-803 simplify trends plotting mechanism trendSessionIds = new ArrayList<Integer>(); double yMin = Double.MAX_VALUE; for (PlotSingleDto plotDatasetDto : plotSeriesDto.getPlotSeries()) { // find all sessions in plot for (PointDto pointDto : plotDatasetDto.getPlotData()) { int sId = (int) pointDto.getX(); if (!trendSessionIds.contains(sId)) { trendSessionIds.add(sId); } if (pointDto.getY() < yMin) { yMin = pointDto.getY(); } } } Collections.sort(trendSessionIds); plot = createPlot(panel, id, markings, plotSeriesDto.getXAxisLabel(), yMin, true, trendSessionIds); } else { plot = createPlot(panel, id, markings, plotSeriesDto.getXAxisLabel(), null, false, null); } LegendTree legendTree = new LegendTree(plot, panel, trendSessionIds); MetricGroupNode<LegendNode> inTree = plotSeriesDto.getLegendTree(); translateIntoTree(inTree, legendTree); // All lines checked by default legendTree.checkAll(); // Add X axis label final String xAxisLabel = plotSeriesDto.getXAxisLabel(); Label zoomInLabel = new Label("Zoom In"); zoomInLabel.addStyleName(getResources().css().zoomLabel()); zoomInLabel.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { panel.zoomIn(); } }); Label zoomBack = new Label("Zoom default"); zoomBack.addStyleName(getResources().css().zoomLabel()); zoomBack.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { panel.zoomDefault(plot); } }); Label zoomOutLabel = new Label("Zoom Out"); zoomOutLabel.addStyleName(getResources().css().zoomLabel()); zoomOutLabel.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { panel.zoomOut(); } }); FlowPanel zoomPanel = new FlowPanel(); zoomPanel.addStyleName(getResources().css().zoomPanel()); zoomPanel.add(zoomInLabel); zoomPanel.add(zoomOutLabel); zoomPanel.add(zoomBack); PlotRepresentation plotRepresentation = new PlotRepresentation( metricNode, zoomPanel, plot, legendTree, xAxisLabel, plotSeriesDto); PlotContainer pc = new PlotContainer(id, plotSeriesDto.getPlotHeader(), plotRepresentation, plotSaver); panel.addElement(pc); } /** * Populate Tree tree with data. * @param inTree model of tree with data * @param tree tree that will be populated with data */ private void translateIntoTree( AbstractIdentifyNode inTree, AbstractTree<AbstractIdentifyNode, ?> tree) { TreeStore<AbstractIdentifyNode> ll = tree.getStore(); for (AbstractIdentifyNode ln : inTree.getChildren()) { addToStore(ll, ln); } } private void addToStore(TreeStore<AbstractIdentifyNode> store, AbstractIdentifyNode node) { store.add(node); for (AbstractIdentifyNode child : node.getChildren()) { addToStore(store, child, node); } } private void addToStore(TreeStore<AbstractIdentifyNode> store, AbstractIdentifyNode node, AbstractIdentifyNode parent) { store.add(parent, node); for (AbstractIdentifyNode child : node.getChildren()) { try { addToStore(store, child, node); } catch (AssertionError e) { new ExceptionPanel(place, "Was not able to insert node with id '" + child.getId() + "' and name '" + child.getDisplayName() + "' into control tree. Id is already in use. Error message:\n" + e.getMessage()); } } } private void enableControl() { sessionDataGridContainer.enable(); controlTree.enableTree(); } private void disableControl() { sessionDataGridContainer.disable(); controlTree.disable(); } /** * Handles selection on SessionDataGrid */ private class SessionSelectChangeHandler implements SelectionChangeEvent.Handler { @Override public void onSelectionChange(SelectionChangeEvent event) { // Currently selection model for sessions is a single selection model Set<SessionDataDto> selected = ((MultiSelectionModel<SessionDataDto>) event.getSource()).getSelectedSet(); controlTree.disable(); //Refresh summary chosenMetrics.clear(); chosenPlots.clear(); summaryPanel.updateSessions(selected, webClientProperties, dateFormatter); needRefresh = mainTabPanel.getSelectedIndex() != tabSummary.getTabIndex(); // Reset node info and remember selected sessions // Fetch info when on Nodes tab nodesPanel.clear(); nodesPanel.updateSetup(selected,place); if (mainTabPanel.getSelectedIndex() == tabNodes.getTabIndex()) nodesPanel.getNodeInfo(); CheckHandlerMap.setTestInfoFetcher(testInfoFetcher); CheckHandlerMap.setMetricFetcher(metricFetcher); CheckHandlerMap.setTestPlotFetcher(testPlotFetcher); CheckHandlerMap.setSessionComparisonPanel(summaryPanel.getSessionComparisonPanel()); // Clear plots display plotPanel.clear(); plotTrendsPanel.clear(); // Clear markings dto map markingsMap.clear(); chosenSessions.clear(); if(selected.isEmpty()){ controlTreePanel.clear(); controlTreePanel.add(NO_SESSION_CHOSEN); controlTree.clearStore(); return; } final Set<String> sessionIds = new HashSet<String>(); for (SessionDataDto sessionDataDto : selected) { sessionIds.add(sessionDataDto.getSessionId()); chosenSessions.add(sessionDataDto.getSessionId()); } Collections.sort(chosenSessions, new Comparator<String>() { @Override public int compare(String o1, String o2) { return (Long.parseLong(o2) - Long.parseLong(o1)) > 0 ? 0 : 1; } }); disableControl(); ControlTreeCreatorService.Async.getInstance().getControlTreeForSessions(sessionIds, webClientProperties.isShowOnlyMatchedTests(), new AsyncCallback<RootNode>() { @Override public void onFailure(Throwable caught) { caught.printStackTrace(); new ExceptionPanel(caught.getMessage()); enableControl(); } @Override public void onSuccess(RootNode result) { if (!selectTests) { // if it was link selectTests = true; processLink(result); } else if (controlTree.getStore().getAllItemsCount() == 0) { controlTree = createControlTree(result); controlTree.setRootNode(result); controlTreePanel.clear(); controlTreePanel.add(controlTree); if (mainTabPanel.getSelectedIndex() != tabMetrics.getTabIndex()) { controlTree.onSummaryTrendsTab(); } else { controlTree.onMetricsTab(); } enableControl(); } else { updateControlTree(result); enableControl(); } } }); } private void processLink(RootNode result) { ControlTree<String> tempTree = createControlTree(result); tempTree.disableEvents(); tempTree.setCheckedWithParent(result.getSummaryNode().getSessionInfo()); for (LinkFragment linkFragment : place.getLinkFragments()) { for (TestsMetrics testsMetrics : linkFragment.getSelectedTestsMetrics()) { TestNode testNode = getTestNodeByNameAndSessionIds(testsMetrics.getTestName(), linkFragment.getSelectedSessionIds(), result); boolean needTestInfo = false; if (testNode == null) { // have not find appropriate TestNode new ExceptionPanel("could not find Test with test name \'" + testsMetrics.getTestName() + "\' for summary"); continue; } else { if (testsMetrics.getMetrics().isEmpty()) { // check all metrics tempTree.setCheckedExpandedWithParent(testNode); } else { tempTree.setExpanded(testNode, true); for (MetricNode metricNode : testNode.getMetrics()) { for (MetricNameDto metricNameDto : metricNode.getMetricNameDtoList()) { if (testsMetrics.getMetrics().contains(metricNameDto.getMetricName())) { tempTree.setCheckedExpandedWithParent(metricNode); needTestInfo = true; } } } if (needTestInfo) { tempTree.setCheckedWithParent(testNode.getTestInfo()); } } } TestDetailsNode testDetailsNode = getTestDetailsNodeByNameAndSessionIds(testsMetrics.getTestName(), linkFragment.getSelectedSessionIds(), result); if (testDetailsNode == null) { // have not find appropriate TestDetailNode new ExceptionPanel("could not find Test with test name \'" + testsMetrics.getTestName() + "\' for details"); } else { // To be compatible with old hyperlinks with monitoring parameters // Replace old monitoring parameters Ids with new metricNameDto ids Set<String> newTrends = new HashSet<String>(); Iterator<String> iterator = testsMetrics.getTrends().iterator(); while (iterator.hasNext()) { String id = iterator.next(); for (String defaultMonitoringParam : defaultMonitoringParameters.keySet()) { if (id.matches("^" + defaultMonitoringParam + ".*")) { if (id.equals(defaultMonitoringParam)) { // select all for (String metricId : defaultMonitoringParameters.get(defaultMonitoringParam)) { String regex = "^" + MonitoringIdUtils.getEscapedStringForRegex(metricId) + ".*"; newTrends.addAll(getMatchingMetricNameDtos(regex,testDetailsNode)); } } else { // selection per agent node MonitoringIdUtils.MonitoringId monitoringId = MonitoringIdUtils.splitMonitoringMetricId(id); if (monitoringId != null) { for (String metricId : defaultMonitoringParameters.get(defaultMonitoringParam)) { String monitoringMetricId = MonitoringIdUtils.getMonitoringMetricId(metricId, monitoringId.getAgentName()); String regex = "^" + MonitoringIdUtils.getEscapedStringForRegex(monitoringMetricId) + ".*"; newTrends.addAll(getMatchingMetricNameDtos(regex,testDetailsNode)); } } } // old monitoring id was replaced with new metricNameDto ids iterator.remove(); break; } } } testsMetrics.getTrends().addAll(newTrends); for (PlotNode plotNode : testDetailsNode.getMetrics()) { for (MetricNameDto metricNameDto : plotNode.getMetricNameDtoList()) { if (testsMetrics.getTrends().contains(metricNameDto.getMetricName())) { tempTree.setCheckedExpandedWithParent(plotNode); } } } } } } tempTree.enableEvents(); controlTreePanel.clear(); controlTree = tempTree; controlTree.setRootNode(result); if (mainTabPanel.getSelectedIndex() == tabMetrics.getTabIndex()) { controlTree.onMetricsTab(); } else { controlTree.onSummaryTrendsTab(); } controlTreePanel.add(controlTree); fireCheckEvents(); } private Set<String> getMatchingMetricNameDtos(String regex, TestDetailsNode testDetailsNode) { Set <String> result = new HashSet<String>(); for (PlotNode plotNode : testDetailsNode.getMetrics()) { for (MetricNameDto metricNameDto : plotNode.getMetricNameDtoList()) { String metricId = metricNameDto.getMetricName(); if (metricId.matches(regex)) { result.add(metricId); } } } return result; } /** * @param testName name of the test * @param selectedSessionIds session ids of chosen test * @return null if no Test found */ private TestNode getTestNodeByNameAndSessionIds(String testName, Set<String> selectedSessionIds, RootNode rootNode) { for (TestNode testNode : rootNode.getSummaryNode().getTests()) { if (testNode.getDisplayName().equals(testName)) { if (testNode.getTaskDataDto().getSessionIds().containsAll(selectedSessionIds) && selectedSessionIds.containsAll(testNode.getTaskDataDto().getSessionIds())) return testNode; } } return null; } /** * @param testName name of the test * @return null if no Test found */ public TestDetailsNode getTestDetailsNodeByNameAndSessionIds(String testName, Set<String> selectedSessionIds, RootNode rootNode) { for (TestDetailsNode testNode : rootNode.getDetailsNode().getTests()) { if (testNode.getDisplayName().equals(testName)) { if (testNode.getTaskDataDto().getSessionIds().containsAll(selectedSessionIds) && selectedSessionIds.containsAll(testNode.getTaskDataDto().getSessionIds())) return testNode; } } return null; } private void updateControlTree(RootNode result) { ControlTree<String> tempTree = createControlTree(result); tempTree.disableEvents(); for (AbstractIdentifyNode s : controlTree.getStore().getAll()) { AbstractIdentifyNode model = tempTree.getStore().findModelWithKey(s.getId()); if (model == null) continue; tempTree.setChecked(model, controlTree.getChecked(s)); if (controlTree.isExpanded(s)) { tempTree.setExpanded(model, true); } else { tempTree.setExpanded(model, false); } } // collapse/expand root nodes for (AbstractIdentifyNode s : controlTree.getStore().getRootItems()) { AbstractIdentifyNode model = tempTree.getStore().findModelWithKey(s.getId()); if (controlTree.isExpanded(s)) { tempTree.setExpanded(model, true); } else { tempTree.setExpanded(model, false); } } tempTree.enableEvents(); controlTreePanel.clear(); controlTree = tempTree; controlTree.setRootNode(result); controlTreePanel.add(controlTree); fireCheckEvents(); } private void fireCheckEvents() { disableControl(); RootNode rootNode = controlTree.getRootNode(); SummaryNode summaryNode = rootNode.getSummaryNode(); fetchSessionInfoData(summaryNode.getSessionInfo()); fetchMetricsForTests(summaryNode.getTests()); fetchPlotsForTests(); } private void fetchPlotsForTests() { testPlotFetcher.fetchPlots(controlTree.getCheckedPlots()); } private void fetchMetricsForTests(List<TestNode> testNodes) { List<TaskDataDto> taskDataDtos = new ArrayList<TaskDataDto>(); for (TestNode testNode : testNodes) { if (controlTree.isChecked(testNode.getTestInfo())) { taskDataDtos.add(testNode.getTaskDataDto()); } } testInfoFetcher.fetchTestInfo(taskDataDtos, false); metricFetcher.fetchMetrics(controlTree.getCheckedMetrics(), false); } private void fetchSessionInfoData(SessionInfoNode sessionInfoNode) { if (Tree.CheckState.CHECKED.equals(controlTree.getChecked(sessionInfoNode))) { summaryPanel.getSessionComparisonPanel().addSessionInfo(); } } private ControlTree<String> createControlTree(RootNode result) { TreeStore<AbstractIdentifyNode> temporaryStore = new TreeStore<AbstractIdentifyNode>(modelKeyProvider); ControlTree<String> newTree = new ControlTree<String>(temporaryStore, new SimpleNodeValueProvider()); setupControlTree(newTree); translateIntoTree(result, newTree); return newTree; } } /** * make server calls to fetch testInfo */ private TestInfoFetcher testInfoFetcher = new TestInfoFetcher(); public class TestInfoFetcher { public void fetchTestInfo(final Collection<TaskDataDto> taskDataDtos, final boolean enableTree) { TestInfoService.Async.getInstance().getTestInfos(taskDataDtos, new AsyncCallback<Map<TaskDataDto, Map<String, TestInfoDto>>>() { @Override public void onFailure(Throwable caught) { caught.printStackTrace(); new ExceptionPanel(place, caught.getMessage()); if (enableTree) enableControl(); } @Override public void onSuccess(Map<TaskDataDto, Map<String, TestInfoDto>> result) { SessionComparisonPanel scp = summaryPanel.getSessionComparisonPanel(); for (TaskDataDto td : result.keySet()) { scp.addTestInfo(td, result.get(td)); } if (enableTree) enableControl(); } }); } } /** * make server calls to fetch metric data (summary table, trends plots) */ private MetricFetcher metricFetcher = new MetricFetcher(); public class MetricFetcher extends PlotsServingBase { public void fetchMetrics(Set<MetricNode> metrics, final boolean enableTree) { hasChanged = true; if (metrics.isEmpty()) { // Remove plots from display which were unchecked chosenMetrics.clear(); plotTrendsPanel.clear(); summaryPanel.getSessionComparisonPanel().clearTreeStore(); if (enableTree) enableControl(); } else { final Set<MetricNode> notLoaded = new HashSet<MetricNode>(); final Map<MetricNode, SummaryIntegratedDto> loaded = new HashMap<MetricNode, SummaryIntegratedDto>(); for (MetricNode metricNode : metrics){ if (!summaryPanel.getCachedMetrics().containsKey(metricNode)){ notLoaded.add(metricNode); }else{ loaded.put(metricNode, summaryPanel.getCachedMetrics().get(metricNode)); } } //Generate all id of plots which should be displayed Set<String> selectedMetricsIds = new HashSet<String>(); for (MetricNode metricNode : metrics) { selectedMetricsIds.add(metricNode.getId()); } List<SummaryIntegratedDto> toRemoveFromTable = new ArrayList<SummaryIntegratedDto>(); // Remove plots from display which were unchecked Set<MetricNode> metricNodesToRemove = new HashSet<MetricNode>(); for (MetricNode metricNode : chosenMetrics.keySet()) { if (!selectedMetricsIds.contains(metricNode.getId())) { toRemoveFromTable.add(chosenMetrics.get(metricNode)); metricNodesToRemove.add(metricNode); } } if (!metricNodesToRemove.isEmpty()) { plotTrendsPanel.removeByMetricNodes(metricNodesToRemove); for (MetricNode metricNode : metricNodesToRemove) { chosenMetrics.remove(metricNode); } } summaryPanel.getSessionComparisonPanel().removeRecords(toRemoveFromTable); if (!notLoaded.isEmpty()) { disableControl(); MetricDataService.Async.getInstance().getMetrics(notLoaded, webClientProperties.isEnableDecisionsPerMetricHighlighting(), new AsyncCallback<Map<MetricNode, SummaryIntegratedDto>>() { @Override public void onFailure(Throwable caught) { caught.printStackTrace(); new ExceptionPanel(place, caught.getMessage()); if (enableTree) enableControl(); } @Override public void onSuccess(Map<MetricNode, SummaryIntegratedDto> result) { loaded.putAll(result); renderMetrics(loaded); if (enableTree) enableControl(); } }); } else { renderMetrics(loaded); } } } private void renderMetrics(Map<MetricNode, SummaryIntegratedDto> loaded) { summaryPanel.getSessionComparisonPanel().addMetricRecords(loaded); renderMetricPlots(loaded); summaryPanelScrollPanel.scrollToBottom(); } private void renderMetricPlots(Map<MetricNode, SummaryIntegratedDto> result) { for (MetricNode metricNode : result.keySet()) { if (!chosenMetrics.containsKey(metricNode)) { chosenMetrics.put(metricNode, result.get(metricNode)); } } if (mainTabPanel.getSelectedIndex() == tabTrends.getTabIndex()) { onTrendsTabSelected(); } } } /** * make server calls to fetch test scope plot data */ private TestPlotFetcher testPlotFetcher = new TestPlotFetcher(); public class TestPlotFetcher extends PlotsServingBase { public void fetchPlots(Set<MetricNode> selectedNodes) { if (selectedNodes.isEmpty()) { enableControl(); } else { disableControl(); PlotProviderService.Async.getInstance().getPlotData(selectedNodes, new AsyncCallback<Map<MetricNode, PlotIntegratedDto>>() { @Override public void onFailure(Throwable caught) { caught.printStackTrace(); new ExceptionPanel(place, caught.toString()); enableControl(); } @Override public void onSuccess(Map<MetricNode, PlotIntegratedDto> result) { for (MetricNode metricNode : result.keySet()) { // DOM id for plot = metricNode.Id - is unique key // If plot has already displayed, then pass it if (chosenPlots.containsKey(metricNode)) { continue; } chosenPlots.put(metricNode, result.get(metricNode)); } if (mainTabPanel.getSelectedIndex() == tabMetrics.getTabIndex()) { onMetricsTabSelected(); } enableControl(); } }); } } /** * Removes plots * @param metricNodes metricNodes to remove */ public void removePlots(Set<MetricNode> metricNodes) { plotPanel.removeByMetricNodes(metricNodes); for (MetricNode metricNode : metricNodes) { chosenPlots.remove(metricNode); } } } private void allTags() { allTags = new ArrayList<TagDto>(); SessionDataService.Async.getInstance().getAllTags(new AsyncCallback<List<TagDto>>() { @Override public void onFailure(Throwable throwable) { new ExceptionPanel("Fail to fetch all tags from the database: " + throwable.getMessage()); } @Override public void onSuccess(List<TagDto> tagDtos) { allTags.addAll(tagDtos); allTagsLoadComplete = true; } }); } void setupSearchTabPanel() { final int indexId = 0; final int indexTag = 1; final int indexDate = 2; allTags(); tagFilterBox = new TagBox(); tagButton = new Button("..."); tagButton.setStyleName(JaggerResources.INSTANCE.css().tagButton()); tagButton.setSize("30px","23px"); tagButton.setEnabled(allTagsLoadComplete); tagButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent clickEvent) { tagNames.clear(); tagFilterBox.popUpForFilter(allTags, tagNames); } }); Label from = new Label("From "); Label to = new Label(" to "); from.setStyleName(JaggerResources.INSTANCE.css().searchPanel()); to.setStyleName(JaggerResources.INSTANCE.css().searchPanel()); datesPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); setPanel(datesPanel, from, sessionsFrom, to, sessionsTo); datesPanel.setBorderWidth(0); sessionsFrom.setSize("97%","21px"); sessionsFrom.setStyleName(JaggerResources.INSTANCE.css().searchPanel()); sessionsTo.setSize("97%","21px"); sessionsTo.setStyleName(JaggerResources.INSTANCE.css().searchPanel()); DockPanel dockTag = new DockPanel(); dockTag.setBorderWidth(0); dockTag.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); sessionTagsTextBox.setSize("108%","21px"); sessionTagsTextBox.setStyleName(JaggerResources.INSTANCE.css().searchPanel()); dockTag.setSize("100%","100%"); dockTag.add(sessionTagsTextBox,DockPanel.WEST); dockTag.add(tagButton,DockPanel.EAST); tagsPanel.setBorderWidth(0); setPanel(tagsPanel,dockTag); setPanel(idsPanel, sessionIdsTextBox); idsPanel.setBorderWidth(0); sessionIdsTextBox.setSize("99%", "21px"); sessionIdsTextBox.setStyleName(JaggerResources.INSTANCE.css().searchPanel()); searchTabPanel.selectTab(indexId); searchTabPanel.getTabWidget(indexId).setTitle("Search by a session's id"); searchTabPanel.getTabWidget(indexTag).setTitle("Search by session's tags"); searchTabPanel.getTabWidget(indexDate).setTitle("Search by a session's date"); searchTabPanel.setTitle("A search bar"); searchTabPanel.addSelectionHandler(new SelectionHandler<Integer>() { @Override public void onSelection(SelectionEvent<Integer> event) { int selected = event.getSelectedItem(); switch (selected) { case indexId: onIdSearchTabSelected(); break; case indexTag: onTagSearchTabSelected(); break; case indexDate: onDateSearchTabSelected(); break; default: } } }); } private void onDateSearchTabSelected() { searchTabPanel.forceLayout(); } private void onIdSearchTabSelected() { searchTabPanel.forceLayout(); } private void onTagSearchTabSelected() { searchTabPanel.forceLayout(); } private void setPanel(HorizontalPanel panel, Widget... widgets){ panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); for (Widget widget:widgets){ panel.add(widget); } panel.setSize("100%","100%"); } // Tab index should be defined in single place // to avoid problems during adding/deleting new tabs private class TabIdentifier { public TabIdentifier(String tabName, int tabIndex) { this.tabName = tabName; this.tabIndex = tabIndex; } public String getTabName() { return tabName; } public int getTabIndex() { return tabIndex; } private String tabName = ""; private int tabIndex = 0; } private String toParsableString(Collection T){ String str=""; for(Object t:T){ str+=t.toString()+'/'; } return str; } }