1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package pl.edu.agh.cast.ui.dialogs;
19
20 import java.lang.reflect.InvocationTargetException;
21 import java.util.ArrayList;
22 import java.util.LinkedList;
23 import java.util.List;
24
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IConfigurationElement;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.NullProgressMonitor;
29 import org.eclipse.jface.operation.IRunnableWithProgress;
30 import org.eclipse.jface.viewers.ILabelProviderListener;
31 import org.eclipse.jface.viewers.IStructuredContentProvider;
32 import org.eclipse.jface.viewers.ITableLabelProvider;
33 import org.eclipse.jface.viewers.TableViewer;
34 import org.eclipse.jface.viewers.Viewer;
35 import org.eclipse.jface.viewers.ViewerSorter;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.dnd.TextTransfer;
38 import org.eclipse.swt.dnd.Transfer;
39 import org.eclipse.swt.events.MouseAdapter;
40 import org.eclipse.swt.events.MouseEvent;
41 import org.eclipse.swt.events.SelectionEvent;
42 import org.eclipse.swt.events.SelectionListener;
43 import org.eclipse.swt.graphics.Color;
44 import org.eclipse.swt.layout.GridData;
45 import org.eclipse.swt.layout.GridLayout;
46 import org.eclipse.swt.widgets.Button;
47 import org.eclipse.swt.widgets.Combo;
48 import org.eclipse.swt.widgets.Display;
49 import org.eclipse.swt.widgets.Event;
50 import org.eclipse.swt.widgets.Label;
51 import org.eclipse.swt.widgets.Listener;
52 import org.eclipse.swt.widgets.Shell;
53 import org.eclipse.swt.widgets.Table;
54 import org.eclipse.swt.widgets.TableColumn;
55 import org.eclipse.swt.widgets.TableItem;
56 import org.eclipse.swt.widgets.Text;
57
58 import pl.edu.agh.cast.Activator;
59 import pl.edu.agh.cast.CastApplication;
60 import pl.edu.agh.cast.backward.editor.EditorUtilBackward;
61 import pl.edu.agh.cast.model.DefaultStatisticsProvider;
62 import pl.edu.agh.cast.model.IStatisticsProvider;
63 import pl.edu.agh.cast.model.base.IDataProvider;
64 import pl.edu.agh.cast.model.visual.backward.Statistic;
65 import pl.edu.agh.cast.util.IExceptionHandler;
66 import pl.edu.agh.cast.util.Messages;
67
68
69
70
71
72
73 public class StatisticsDialog extends org.eclipse.swt.widgets.Dialog {
74
75 private static final IStatisticsProvider DEFAULT_STATISTICS_PROVIDER = new DefaultStatisticsProvider();
76
77 private static final String ROW_SEPARATOR = "\n";
78
79 private static final String COLUMN_SEPARATOR = "\t";
80
81 private static final String ID = "id";
82
83 private Shell dialogShell;
84
85 private Table table;
86
87 private TableViewer viewer;
88
89 private TableColumn sourceColumn;
90
91 private TableColumn targetColumn;
92
93 private TableColumn nodeNameColumn;
94
95 private TableColumn totalColumn;
96
97 private Combo statisticsCombo;
98
99 private List<IConfigurationElement> statisticsEvaluators = new LinkedList<IConfigurationElement>();
100
101 private IDataProvider dataProvider;
102
103 private Button copyToClipboardButton;
104
105 private Label statisticsLabel;
106
107 private Text description;
108
109 private Label descriptionLabel;
110
111 private List<Statistic> currentStatistics;
112
113 private Button hideZerosRows;
114
115
116
117
118
119
120
121
122
123
124
125 public StatisticsDialog(IDataProvider diagram, Shell parent, int style) {
126 super(parent, style);
127 dataProvider = diagram;
128 }
129
130
131
132
133 public void open() {
134 try {
135 Shell parent = getParent();
136 dialogShell = new Shell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL);
137
138 dialogShell.setText(Messages.ShowStatisticsDialog_1);
139
140 GridLayout dialogShellLayout = new GridLayout();
141 dialogShellLayout.numColumns = 3;
142 dialogShell.setLayout(dialogShellLayout);
143 dialogShell.layout();
144 dialogShell.pack();
145 dialogShell.setSize(584, 442);
146
147 table = new Table(dialogShell, SWT.NONE);
148 table.setLinesVisible(true);
149 GridData tableLData = new GridData();
150 tableLData.grabExcessHorizontalSpace = true;
151 tableLData.grabExcessVerticalSpace = true;
152 tableLData.verticalAlignment = GridData.FILL;
153 tableLData.horizontalAlignment = GridData.FILL;
154 tableLData.horizontalSpan = 3;
155 table.setLayoutData(tableLData);
156 table.setHeaderVisible(true);
157
158 statisticsLabel = new Label(dialogShell, SWT.NONE);
159 statisticsLabel.setText(Messages.StatisticsDialog_1);
160 statisticsLabel.setSize(-1, -1);
161
162 statisticsCombo = new Combo(dialogShell, SWT.READ_ONLY);
163 statisticsCombo.setSize(-1, -1);
164
165 copyToClipboardButton = new Button(dialogShell, SWT.PUSH | SWT.CENTER);
166 copyToClipboardButton.setText(Messages.StatisticsDialog_0);
167 GridData copyToClipboardButtonLData = new GridData();
168 copyToClipboardButtonLData.verticalAlignment = GridData.FILL;
169 copyToClipboardButtonLData.horizontalAlignment = GridData.END;
170 copyToClipboardButton.setLayoutData(copyToClipboardButtonLData);
171 copyToClipboardButton.setSize(-1, -1);
172 copyToClipboardButton.addMouseListener(new MouseAdapter() {
173 @Override
174 public void mouseUp(MouseEvent evt) {
175 copyToClipboard(evt);
176 }
177 });
178
179 descriptionLabel = new Label(dialogShell, SWT.NONE);
180 descriptionLabel.setText(Messages.StatisticsDialog_2);
181 GridData descriptionLabelData = new GridData();
182 descriptionLabelData.verticalAlignment = GridData.BEGINNING;
183 descriptionLabel.setLayoutData(descriptionLabelData);
184
185 description = new Text(dialogShell, SWT.MULTI | SWT.READ_ONLY);
186 description.setText(Messages.StatisticsDialog_3);
187 description.setEnabled(false);
188 GridData descriptionData = new GridData();
189 descriptionData.horizontalSpan = 2;
190 descriptionData.horizontalAlignment = GridData.FILL;
191 descriptionData.grabExcessHorizontalSpace = true;
192 description.setLayoutData(descriptionData);
193
194 new Label(dialogShell, SWT.NONE);
195
196 hideZerosRows = new Button(dialogShell, SWT.CHECK);
197 hideZerosRows.setText(Messages.StatisticsDialog_HideZeros);
198 hideZerosRows.addListener(SWT.Selection, new Listener() {
199 public void handleEvent(Event arg0) {
200 fillData();
201 }
202
203 });
204
205 nodeNameColumn = new TableColumn(table, SWT.NONE);
206 nodeNameColumn.setText(Messages.EntityHeader);
207 nodeNameColumn.setWidth(120);
208 nodeNameColumn.setResizable(true);
209 nodeNameColumn.setData(ID, Messages.EntityHeader);
210
211 targetColumn = new TableColumn(table, SWT.NONE);
212 targetColumn.setText(Messages.IncomingCallsHeader);
213 targetColumn.setWidth(150);
214 targetColumn.setResizable(true);
215 targetColumn.setData(ID, Messages.IncomingCallsHeader);
216
217 sourceColumn = new TableColumn(table, SWT.NONE);
218 sourceColumn.setText(Messages.OutgoingCallsHeader);
219 sourceColumn.setWidth(150);
220 sourceColumn.setResizable(true);
221 sourceColumn.setData(ID, Messages.OutgoingCallsHeader);
222
223 totalColumn = new TableColumn(table, SWT.NONE);
224 totalColumn.setText(Messages.TotalHeader);
225 totalColumn.setWidth(150);
226 totalColumn.setResizable(true);
227 totalColumn.setData(ID, Messages.TotalHeader);
228
229 dialogShell.setLocation(getParent().toDisplay(100, 100));
230 setupViewer();
231 setData(DEFAULT_STATISTICS_PROVIDER.statistics(dataProvider, new NullProgressMonitor()));
232 fillStatistics();
233 dialogShell.open();
234 Display display = dialogShell.getDisplay();
235 while (!dialogShell.isDisposed()) {
236 if (!display.readAndDispatch()) {
237 display.sleep();
238 }
239 }
240 } catch (Exception e) {
241 e.printStackTrace();
242 }
243 }
244
245 private void fillStatistics() {
246 for (IConfigurationElement contribution : Activator.getStatisticsConfigurations()) {
247 statisticsCombo.add(Messages.AllRelations);
248 statisticsEvaluators.add(null);
249 for (IConfigurationElement stat : contribution.getChildren()) {
250 statisticsCombo.add(stat.getAttribute(Activator.STATISTIC_NAME));
251 statisticsEvaluators.add(stat);
252 }
253 statisticsCombo.select(0);
254 }
255 statisticsCombo.addSelectionListener(new SelectionListener() {
256
257 public void widgetDefaultSelected(SelectionEvent e) {
258 }
259
260 public void widgetSelected(SelectionEvent e) {
261 final IConfigurationElement stat = statisticsEvaluators.get(statisticsCombo.getSelectionIndex());
262
263 final IStatisticsProvider provider;
264 if (stat == null) {
265 provider = null;
266 } else {
267 try {
268 provider = (IStatisticsProvider)stat.createExecutableExtension(Activator.STATISTIC_CLASS);
269 } catch (CoreException e1) {
270 Activator.getLogger().error("Error while initializing statistics", e1);
271 return;
272 }
273 }
274
275 EditorUtilBackward.runWithProgressMonitorInUIThread(new IRunnableWithProgress() {
276 public void run(IProgressMonitor progress) throws InvocationTargetException, InterruptedException {
277 doCalculateStatistics(stat, provider, progress);
278 }
279 }, new IExceptionHandler() {
280 public void handleException(Exception e) {
281 Activator.getLogger().error("Error calculating statistics", e);
282 };
283 });
284 }
285 });
286 statisticsCombo.addSelectionListener(new SelectionListener() {
287
288 public void widgetDefaultSelected(SelectionEvent e) {
289 }
290
291 public void widgetSelected(SelectionEvent e) {
292 IConfigurationElement stat = statisticsEvaluators.get(statisticsCombo.getSelectionIndex());
293 if (stat == null) {
294 description.setText(Messages.StatisticsDialog_3);
295 } else {
296 description.setText(stat.getAttribute(Activator.STATISTIC_DESCRIPTION));
297 }
298 }
299
300 });
301
302 }
303
304 private void doCalculateStatistics(final IConfigurationElement stat, IStatisticsProvider provider,
305 IProgressMonitor progress) {
306 if (stat == null) {
307
308 setData(DEFAULT_STATISTICS_PROVIDER.statistics(dataProvider, progress));
309 targetColumn.setText(Messages.IncomingCallsHeader);
310 sourceColumn.setText(Messages.OutgoingCallsHeader);
311 } else {
312 setData(provider.statistics(dataProvider, progress));
313 targetColumn.setText(stat.getAttribute(Activator.STATISTIC_TARGET_LABEL));
314 sourceColumn.setText(stat.getAttribute(Activator.STATISTIC_SOURCE_LABEL));
315 }
316 }
317
318 private void setupViewer() {
319 viewer = new TableViewer(table);
320
321 attachContentProvider();
322 attachLabelProvider();
323 attachSortListeners();
324 }
325
326 private void attachSortListeners() {
327 Listener sortListener = new Listener() {
328 public void handleEvent(Event e) {
329
330 TableColumn sortColumn = viewer.getTable().getSortColumn();
331 TableColumn currentColumn = (TableColumn)e.widget;
332 int dir = viewer.getTable().getSortDirection();
333 if (sortColumn == currentColumn) {
334 dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
335 } else {
336 viewer.getTable().setSortColumn(currentColumn);
337 dir = SWT.UP;
338 }
339
340 String sortIdentifier = null;
341
342 if (currentColumn.getData(ID).equals(Sorter.ENTITY)) {
343 sortIdentifier = Sorter.ENTITY;
344 } else if (currentColumn.getData(ID).equals(Sorter.TARGET)) {
345 sortIdentifier = Sorter.TARGET;
346 } else if (currentColumn.getData(ID).equals(Sorter.SOURCE)) {
347 sortIdentifier = Sorter.SOURCE;
348 } else if (currentColumn.getData(ID).equals(Sorter.TOTAL)) {
349 sortIdentifier = Sorter.TOTAL;
350 }
351
352 viewer.getTable().setSortDirection(dir);
353 viewer.setSorter(new Sorter(sortIdentifier, dir));
354 fillData();
355 }
356 };
357
358 nodeNameColumn.addListener(SWT.Selection, sortListener);
359 sourceColumn.addListener(SWT.Selection, sortListener);
360 targetColumn.addListener(SWT.Selection, sortListener);
361 totalColumn.addListener(SWT.Selection, sortListener);
362
363 }
364
365 private void setData(List<Statistic> statistics) {
366 currentStatistics = statistics;
367 fillData();
368 }
369
370 private void fillData() {
371 for (int i = 0; i < viewer.getTable().getItemCount(); i++) {
372 viewer.clear(i);
373 }
374 viewer.setItemCount(0);
375
376 List<Statistic> data = new ArrayList<Statistic>();
377 boolean hideZeros = hideZerosRows.getSelection();
378 for (Statistic statistic : currentStatistics) {
379 if (hideZeros && statistic.getTotal() == 0) {
380 continue;
381 }
382 data.add(statistic);
383 }
384
385 viewer.add(data.toArray());
386 double sourceSummary = 0;
387 double targetSummary = 0;
388 for (Statistic stat : data) {
389 sourceSummary += stat.getSource();
390 targetSummary += stat.getTarget();
391 }
392 Statistic summaryStatistics = new Statistic(data.size() + "",
393 sourceSummary, targetSummary);
394 summaryStatistics.setSummary(true);
395 viewer.add(summaryStatistics);
396 TableItem ti = viewer.getTable().getItem(viewer.getTable().getItemCount() - 1);
397 Color blue = new Color(table.getDisplay(), 0, 200, 255);
398
399 for (int i = 0; i < 5; i++) {
400 ti.setBackground(i, blue);
401 }
402 }
403
404 private void attachLabelProvider() {
405 viewer.setLabelProvider(new ITableLabelProvider() {
406 public org.eclipse.swt.graphics.Image getColumnImage(Object element, int columnIndex) {
407 return null;
408 }
409
410 public String getColumnText(Object element, int columnIndex) {
411 String text = null;
412 switch (columnIndex) {
413 case 0: {
414 text = ((Statistic)element).getNodeName();
415 break;
416 }
417 case 1: {
418 text = ((Statistic)element).getTargetLabel();
419 break;
420 }
421 case 2: {
422 text = ((Statistic)element).getSourceLabel();
423 break;
424 }
425 case 3: {
426 text = ((Statistic)element).getTotalLabel();
427 break;
428 }
429 default: {
430 throw new IllegalArgumentException("Invalid column index "
431 + columnIndex);
432 }
433 }
434 return text;
435 }
436
437 public void addListener(ILabelProviderListener listener) {
438 }
439
440 public void dispose() {
441 }
442
443 public boolean isLabelProperty(Object element, String property) {
444 return false;
445 }
446
447 public void removeListener(ILabelProviderListener lpl) {
448 }
449 });
450 }
451
452 private void attachContentProvider() {
453 viewer.setContentProvider(new IStructuredContentProvider() {
454 public Object[] getElements(Object inputElement) {
455 return (Object[])inputElement;
456 }
457
458 public void dispose() {
459 }
460
461 public void inputChanged(Viewer view, Object oldInput, Object newInput) {
462 }
463
464 });
465 }
466
467 private void copyToClipboard(MouseEvent evt) {
468 StringBuilder builder = new StringBuilder();
469 int columnsCount = viewer.getTable().getColumnCount();
470 for (TableItem item : viewer.getTable().getItems()) {
471 boolean first = true;
472 for (int i = 0; i < columnsCount; i++) {
473 if (first) {
474 first = false;
475 } else {
476 builder.append(COLUMN_SEPARATOR);
477 }
478 builder.append(item.getText(i));
479 }
480 builder.append(ROW_SEPARATOR);
481 }
482 CastApplication.getClipboard().setContents(new Object[] { builder.toString() },
483 new Transfer[] { TextTransfer.getInstance() });
484 }
485
486
487
488
489
490
491 private static class Sorter extends ViewerSorter {
492
493 public static final String ENTITY = Messages.EntityHeader;
494
495 public static final String TARGET = Messages.IncomingCallsHeader;
496
497 public static final String SOURCE = Messages.OutgoingCallsHeader;
498
499 public static final String TOTAL = Messages.TotalHeader;
500
501 private String column;
502
503 private int dir;
504
505 public Sorter(String column, int dir) {
506 super();
507 this.column = column;
508 this.dir = dir;
509 }
510
511
512
513
514
515
516
517 @Override
518 public int compare(Viewer viewer, Object e1, Object e2) {
519 int returnValue = 0;
520
521 Statistic s1 = (Statistic)e1;
522 Statistic s2 = (Statistic)e2;
523 if (s1.isSummary()) {
524 return 1;
525 }
526 if (s2.isSummary()) {
527 return -1;
528 }
529 if (this.column == ENTITY) {
530 returnValue = s1.getNodeName().compareTo(s2.getNodeName());
531 } else if (this.column == TARGET) {
532 returnValue = s1.getTarget() - s2.getTarget() > 0 ? 1 : -1;
533 } else if (this.column == SOURCE) {
534 returnValue = s1.getSource() - s2.getSource() > 0 ? 1 : -1;
535 } else if (this.column == TOTAL) {
536 returnValue = s1.getSource() + s1.getTarget() - s2.getSource() - s2.getTarget() > 0 ? 1 : -1;
537 }
538
539 if (this.dir == SWT.DOWN) {
540 returnValue = returnValue * -1;
541 }
542 return returnValue;
543 }
544 }
545
546 }