##// END OF EJS Templates
Get rid of compile warning
Jani Honkonen -
r1945:f053f32e1829
parent child
Show More
@@ -1,583 +1,582
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "window.h"
22 22 #include "view.h"
23 23 #include "charts.h"
24 24 #include <QChartView>
25 25 #include <QAreaSeries>
26 26 #include <QLegend>
27 27 #include <QGridLayout>
28 28 #include <QFormLayout>
29 29 #include <QComboBox>
30 30 #include <QSpinBox>
31 31 #include <QCheckBox>
32 32 #include <QGroupBox>
33 33 #include <QLabel>
34 34 #include <QGraphicsScene>
35 35 #include <QGraphicsGridLayout>
36 36 #include <QGraphicsLinearLayout>
37 37 #include <QGraphicsProxyWidget>
38 38 #include <QGLWidget>
39 39 #include <QApplication>
40 40 #include <QDebug>
41 41 #include <QMenu>
42 42
43 43 Window::Window(QWidget* parent) :
44 44 QMainWindow(parent),
45 45 m_listCount(3),
46 46 m_valueMax(10),
47 47 m_valueCount(7),
48 48 m_scene(new QGraphicsScene(this)),
49 49 m_view(0),
50 50 m_dataTable(Model::generateRandomData(m_listCount, m_valueMax, m_valueCount)),
51 51 m_form(0),
52 52 m_themeComboBox(0),
53 53 m_antialiasCheckBox(0),
54 54 m_animatedComboBox(0),
55 55 m_legendComboBox(0),
56 56 m_templateComboBox(0),
57 57 m_openGLCheckBox(0),
58 58 m_zoomCheckBox(0),
59 59 m_scrollCheckBox(0),
60 60 m_rubberBand(new QGraphicsRectItem()),
61 61 m_baseLayout(new QGraphicsGridLayout()),
62 62 m_menu(createMenu()),
63 63 m_state(NoState),
64 64 m_currentState(NoState),
65 65 m_template(0)
66 66 {
67 67 createProxyWidgets();
68 68 connectSignals();
69 69
70 70 // create layout
71 71 QGraphicsLinearLayout *settingsLayout = new QGraphicsLinearLayout();
72 72 settingsLayout->setOrientation(Qt::Vertical);
73 73 settingsLayout->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
74 74 settingsLayout->addItem(m_widgetHash["openGLCheckBox"]);
75 75 settingsLayout->addItem(m_widgetHash["antialiasCheckBox"]);
76 76 settingsLayout->addItem(m_widgetHash["themeLabel"]);
77 77 settingsLayout->addItem(m_widgetHash["themeComboBox"]);
78 78 settingsLayout->addItem(m_widgetHash["animationsLabel"]);
79 79 settingsLayout->addItem(m_widgetHash["animatedComboBox"]);
80 80 settingsLayout->addItem(m_widgetHash["legendLabel"]);
81 81 settingsLayout->addItem(m_widgetHash["legendComboBox"]);
82 82 settingsLayout->addItem(m_widgetHash["templateLabel"]);
83 83 settingsLayout->addItem(m_widgetHash["templateComboBox"]);
84 84 settingsLayout->addItem(m_widgetHash["scrollCheckBox"]);
85 85 settingsLayout->addItem(m_widgetHash["zoomCheckBox"]);
86 86 settingsLayout->addStretch();
87 87 m_baseLayout->addItem(settingsLayout, 0, 3, 2, 1);
88 88
89 89 //create charts
90 90 Charts::ChartList list = Charts::chartList();
91 91
92 92 for (int i = 0; i < 9; ++i) {
93 93 QChart* chart = 0;
94 94 if(i<list.size()){
95 95 chart = list.at(i)->createChart(m_dataTable);
96 96 }else{
97 97 chart = new QChart();
98 98 chart->setTitle(tr("Empty"));
99 99 }
100 100
101 101 m_baseLayout->addItem(chart, i / 3, i % 3);
102 102 m_chartHash[chart] = i;
103 103 }
104 104
105 105 m_form = new QGraphicsWidget();
106 106 m_form->setLayout(m_baseLayout);
107 107 m_scene->addItem(m_form);
108 108 m_scene->addItem(m_rubberBand);
109 109 m_rubberBand->setVisible(false);
110 110
111 111 m_view = new View(m_scene, m_form);
112 112 m_view->setMinimumSize(m_form->preferredSize().toSize());
113 113
114 114 // Set defaults
115 115 m_antialiasCheckBox->setChecked(true);
116 116 updateUI();
117 117 setCentralWidget(m_view);
118 118 }
119 119
120 120 Window::~Window()
121 121 {
122 122 }
123 123
124 124 void Window::connectSignals()
125 125 {
126 126 QObject::connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
127 127 QObject::connect(m_antialiasCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
128 128 QObject::connect(m_openGLCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
129 129 QObject::connect(m_zoomCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
130 130 QObject::connect(m_scrollCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateUI()));
131 131 QObject::connect(m_animatedComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
132 132 QObject::connect(m_legendComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
133 133 QObject::connect(m_templateComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()));
134 134 }
135 135
136 136 void Window::createProxyWidgets()
137 137 {
138 138 m_themeComboBox = createThemeBox();
139 139 m_antialiasCheckBox = new QCheckBox(tr("Anti-aliasing"));
140 140 m_animatedComboBox = createAnimationBox();
141 141 m_legendComboBox = createLegendBox();
142 142 m_openGLCheckBox = new QCheckBox(tr("OpenGL"));
143 143 m_zoomCheckBox = new QCheckBox(tr("Zoom"));
144 144 m_scrollCheckBox = new QCheckBox(tr("Scroll"));
145 145 m_templateComboBox= createTempleteBox();
146 146 m_widgetHash["themeComboBox"] = m_scene->addWidget(m_themeComboBox);
147 147 m_widgetHash["antialiasCheckBox"] = m_scene->addWidget(m_antialiasCheckBox);
148 148 m_widgetHash["animatedComboBox"] = m_scene->addWidget(m_animatedComboBox);
149 149 m_widgetHash["legendComboBox"] = m_scene->addWidget(m_legendComboBox);
150 150 m_widgetHash["openGLCheckBox"] = m_scene->addWidget(m_openGLCheckBox);
151 151 m_widgetHash["themeLabel"] = m_scene->addWidget(new QLabel("Theme"));
152 152 m_widgetHash["animationsLabel"] = m_scene->addWidget(new QLabel("Animations"));
153 153 m_widgetHash["legendLabel"] = m_scene->addWidget(new QLabel("Legend"));
154 154 m_widgetHash["templateLabel"] = m_scene->addWidget(new QLabel("Chart template"));
155 155 m_widgetHash["templateComboBox"] = m_scene->addWidget(m_templateComboBox);
156 156 m_widgetHash["zoomCheckBox"] = m_scene->addWidget(m_zoomCheckBox);
157 157 m_widgetHash["scrollCheckBox"] = m_scene->addWidget(m_scrollCheckBox);
158 158
159 159 }
160 160
161 161 QComboBox* Window::createThemeBox()
162 162 {
163 163 QComboBox* themeComboBox = new ComboBox(this);
164 164 themeComboBox->addItem("Light", QChart::ChartThemeLight);
165 165 themeComboBox->addItem("Blue Cerulean", QChart::ChartThemeBlueCerulean);
166 166 themeComboBox->addItem("Dark", QChart::ChartThemeDark);
167 167 themeComboBox->addItem("Brown Sand", QChart::ChartThemeBrownSand);
168 168 themeComboBox->addItem("Blue NCS", QChart::ChartThemeBlueNcs);
169 169 themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
170 170 themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
171 171 return themeComboBox;
172 172 }
173 173
174 174 QComboBox* Window::createAnimationBox()
175 175 {
176 176 QComboBox* animationComboBox = new ComboBox(this);
177 177 animationComboBox->addItem("No Animations", QChart::NoAnimation);
178 178 animationComboBox->addItem("GridAxis Animations", QChart::GridAxisAnimations);
179 179 animationComboBox->addItem("Series Animations", QChart::SeriesAnimations);
180 180 animationComboBox->addItem("All Animations", QChart::AllAnimations);
181 181 return animationComboBox;
182 182 }
183 183
184 184 QComboBox* Window::createLegendBox()
185 185 {
186 186 QComboBox* legendComboBox = new ComboBox(this);
187 187 legendComboBox->addItem("No Legend ", 0);
188 188 legendComboBox->addItem("Legend Top", Qt::AlignTop);
189 189 legendComboBox->addItem("Legend Bottom", Qt::AlignBottom);
190 190 legendComboBox->addItem("Legend Left", Qt::AlignLeft);
191 191 legendComboBox->addItem("Legend Right", Qt::AlignRight);
192 192 return legendComboBox;
193 193 }
194 194
195 195 QComboBox* Window::createTempleteBox()
196 196 {
197 197 QComboBox* templateComboBox = new ComboBox(this);
198 198 templateComboBox->addItem("No Template", 0);
199 199
200 200 Charts::ChartList list = Charts::chartList();
201 201 QMultiMap<QString, Chart*> categoryMap;
202 202
203 203 foreach(Chart* chart, list) {
204 204 categoryMap.insertMulti(chart->category(), chart);
205 205 }
206 206 foreach(const QString& category, categoryMap.uniqueKeys()) {
207 207 templateComboBox->addItem(category, category);
208 208 }
209 209 return templateComboBox;
210 210 }
211 211
212 212
213 213 void Window::updateUI()
214 214 {
215 215 checkTemplate();
216 216 checkOpenGL();
217 217 checkTheme();
218 218 checkAnimationOptions();
219 219 checkLegend();
220 220 checkState();
221 221 }
222 222
223 223 void Window::checkLegend()
224 224 {
225 225 Qt::Alignment alignment(m_legendComboBox->itemData(m_legendComboBox->currentIndex()).toInt());
226 226
227 227 if (!alignment) {
228 228 foreach (QChart *chart, m_chartHash.keys()) {
229 229 chart->legend()->hide();
230 230 }
231 231 }
232 232 else {
233 233 foreach (QChart *chart, m_chartHash.keys()) {
234 234 chart->legend()->setAlignment(alignment);
235 235 chart->legend()->show();
236 236 }
237 237 }
238 238 }
239 239
240 240 void Window::checkOpenGL()
241 241 {
242 242 bool opengl = m_openGLCheckBox->isChecked();
243 243 bool isOpengl = qobject_cast<QGLWidget*>(m_view->viewport());
244 244 if ((isOpengl && !opengl) || (!isOpengl && opengl)) {
245 245 m_view->deleteLater();
246 246 m_view = new View(m_scene, m_form);
247 247 m_view->setViewport(!opengl ? new QWidget() : new QGLWidget());
248 248 setCentralWidget(m_view);
249 249 }
250 250
251 251 bool antialias = m_antialiasCheckBox->isChecked();
252 252
253 253 if (opengl)
254 254 m_view->setRenderHint(QPainter::HighQualityAntialiasing, antialias);
255 255 else
256 256 m_view->setRenderHint(QPainter::Antialiasing, antialias);
257 257 }
258 258
259 259 void Window::checkAnimationOptions()
260 260 {
261 261 QChart::AnimationOptions options(
262 262 m_animatedComboBox->itemData(m_animatedComboBox->currentIndex()).toInt());
263 263 if (!m_chartHash.isEmpty() && m_chartHash.keys().at(0)->animationOptions() != options) {
264 264 foreach (QChart *chart, m_chartHash.keys())
265 265 chart->setAnimationOptions(options);
266 266 }
267 267 }
268 268
269 269 void Window::checkState()
270 270 {
271 271 bool scroll = m_scrollCheckBox->isChecked();
272 272
273 273 if (m_state != ScrollState && scroll) {
274 274 m_state = ScrollState;
275 275 m_zoomCheckBox->setChecked(false);
276 276 }
277 277 else if (!scroll && m_state == ScrollState) {
278 278 m_state = NoState;
279 279 }
280 280
281 281 bool zoom = m_zoomCheckBox->isChecked();
282 282
283 283 if (m_state != ZoomState && zoom) {
284 284 m_state = ZoomState;
285 285 m_scrollCheckBox->setChecked(false);
286 286 }
287 287 else if (!zoom && m_state == ZoomState) {
288 288 m_state = NoState;
289 289 }
290 290 }
291 291
292 292 void Window::checkTemplate()
293 293 {
294 294
295 295 int index = m_templateComboBox->currentIndex();
296 296 if (m_template == index || index == 0)
297 297 return;
298 298
299 299 m_template = index;
300 300
301 301 QString category = m_templateComboBox->itemData(index).toString();
302 302 Charts::ChartList list = Charts::chartList();
303 303
304 304 QList<QChart*> qchartList = m_chartHash.keys();
305 305
306 306 foreach(QChart* qchart,qchartList){
307 307 for(int i = 0 ; i < m_baseLayout->count();++i)
308 308 {
309 309 if(m_baseLayout->itemAt(i)==qchart){
310 310 m_baseLayout->removeAt(i);
311 311 break;
312 312 }
313 313 }
314 314 }
315 315
316 316 m_chartHash.clear();
317 317 qDeleteAll(qchartList);
318 318
319 319 QChart* qchart(0);
320 320
321 321 int j=0;
322 322 for (int i = 0; i < list.size(); ++i) {
323 323 Chart* chart = list.at(i);
324 324 if (chart->category() == category && j < 9) {
325 325 qchart = list.at(i)->createChart(m_dataTable);
326 326 m_baseLayout->addItem(qchart, j / 3, j % 3);
327 327 m_chartHash[qchart] = j;
328 328 j++;
329 329 }
330 330 }
331 331 for (; j < 9; ++j) {
332 332 qchart = new QChart();
333 333 qchart->setTitle(tr("Empty"));
334 334 m_baseLayout->addItem(qchart, j / 3, j % 3);
335 335 m_chartHash[qchart] = j;
336 336 }
337 337 }
338 338
339 339 void Window::checkTheme()
340 340 {
341 341 QChart::ChartTheme theme = (QChart::ChartTheme) m_themeComboBox->itemData(
342 342 m_themeComboBox->currentIndex()).toInt();
343 343
344 344 foreach (QChart *chart, m_chartHash.keys())
345 345 chart->setTheme(theme);
346 346
347 347 QPalette pal = window()->palette();
348 348 if (theme == QChart::ChartThemeLight) {
349 349 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
350 350 pal.setColor(QPalette::WindowText, QRgb(0x404044));
351 351 }
352 352 else if (theme == QChart::ChartThemeDark) {
353 353 pal.setColor(QPalette::Window, QRgb(0x121218));
354 354 pal.setColor(QPalette::WindowText, QRgb(0xd6d6d6));
355 355 }
356 356 else if (theme == QChart::ChartThemeBlueCerulean) {
357 357 pal.setColor(QPalette::Window, QRgb(0x40434a));
358 358 pal.setColor(QPalette::WindowText, QRgb(0xd6d6d6));
359 359 }
360 360 else if (theme == QChart::ChartThemeBrownSand) {
361 361 pal.setColor(QPalette::Window, QRgb(0x9e8965));
362 362 pal.setColor(QPalette::WindowText, QRgb(0x404044));
363 363 }
364 364 else if (theme == QChart::ChartThemeBlueNcs) {
365 365 pal.setColor(QPalette::Window, QRgb(0x018bba));
366 366 pal.setColor(QPalette::WindowText, QRgb(0x404044));
367 367 }
368 368 else if (theme == QChart::ChartThemeHighContrast) {
369 369 pal.setColor(QPalette::Window, QRgb(0xffab03));
370 370 pal.setColor(QPalette::WindowText, QRgb(0x181818));
371 371 }
372 372 else if (theme == QChart::ChartThemeBlueIcy) {
373 373 pal.setColor(QPalette::Window, QRgb(0xcee7f0));
374 374 pal.setColor(QPalette::WindowText, QRgb(0x404044));
375 375 }
376 376 else {
377 377 pal.setColor(QPalette::Window, QRgb(0xf0f0f0));
378 378 pal.setColor(QPalette::WindowText, QRgb(0x404044));
379 379 }
380 380 foreach(QGraphicsProxyWidget* widget , m_widgetHash) {
381 381 widget->setPalette(pal);
382 382 }
383 383 m_view->setBackgroundBrush(pal.color((QPalette::Window)));
384 384 m_rubberBand->setPen(pal.color((QPalette::WindowText)));
385 385 }
386 386
387 387 void Window::mousePressEvent(QMouseEvent *event)
388 388 {
389 389 if (event->button() == Qt::LeftButton) {
390 390
391 391 m_origin = event->pos();
392 392 m_currentState = NoState;
393 393
394 394 foreach (QChart *chart, m_chartHash.keys()) {
395 395
396 396 QRectF geometryRect = chart->geometry();
397 397 QRectF plotArea = chart->plotArea();
398 398 plotArea.translate(geometryRect.topLeft());
399 399 if (plotArea.contains(m_origin)) {
400 400 m_currentState = m_state;
401 401
402 402 if (m_currentState == NoState && m_templateComboBox->currentIndex()==0) {
403 403 handleMenu(chart);
404 404 }
405 405 break;
406 406 }
407 407 }
408 408
409 409 if (m_currentState == ZoomState) {
410 410 m_rubberBand->setRect(QRectF(m_origin, QSize()));
411 411 m_rubberBand->setVisible(true);
412 412 }
413 413
414 414 event->accept();
415 415 }
416 416
417 417 if (event->button() == Qt::RightButton) {
418 418 m_origin = event->pos();
419 419 m_currentState = m_state;
420 420 }
421 421 }
422 422
423 423 void Window::mouseMoveEvent(QMouseEvent *event)
424 424 {
425 425 if ( m_currentState != NoState) {
426 426
427 427 foreach (QChart *chart, m_chartHash.keys()) {
428 428
429 429 QRectF geometryRect = chart->geometry();
430 430 QRectF plotArea = chart->plotArea();
431 431 plotArea.translate(geometryRect.topLeft());
432 432
433 433 if (plotArea.contains(m_origin)) {
434 434 if (m_currentState == ScrollState) {
435 435 QPointF delta = m_origin - event->pos();
436 436 chart->scroll(delta.x(), -delta.y());
437 437 }
438 438 if (m_currentState == ZoomState && plotArea.contains(event->pos())) {
439 439 m_rubberBand->setRect(QRectF(m_origin, event->pos()).normalized());
440 440 }
441 441 break;
442 442 }
443 443 }
444 444 if(m_currentState == ScrollState) m_origin = event->pos();
445 445 event->accept();
446 446 }
447 447 }
448 448
449 449 void Window::mouseReleaseEvent(QMouseEvent *event)
450 450 {
451 451 if (event->button() == Qt::LeftButton) {
452 452 if (m_currentState == ZoomState) {
453 453 m_rubberBand->setVisible(false);
454 454
455 455 foreach (QChart *chart, m_chartHash.keys()) {
456 456
457 457 QRectF geometryRect = chart->geometry();
458 458 QRectF plotArea = chart->plotArea();
459 459 plotArea.translate(geometryRect.topLeft());
460 460
461 461 if (plotArea.contains(m_origin)) {
462 462 QRectF rect = m_rubberBand->rect();
463 463 rect.translate(-geometryRect.topLeft());
464 464 chart->zoomIn(rect);
465 465 break;
466 466 }
467 467 }
468 468 }
469 469
470 470 m_currentState = NoState;
471 471 event->accept();
472 472 }
473 473
474 474 if (event->button() == Qt::RightButton) {
475 475
476 476 if (m_currentState == ZoomState) {
477 477 foreach (QChart *chart, m_chartHash.keys()) {
478 478
479 479 QRectF geometryRect = chart->geometry();
480 480 QRectF plotArea = chart->plotArea();
481 481 plotArea.translate(geometryRect.topLeft());
482 482
483 483 if (plotArea.contains(m_origin)) {
484 QRectF rect = m_rubberBand->rect();
485 484 chart->zoomOut();
486 485 break;
487 486 }
488 487 }
489 488 }
490 489 }
491 490 }
492 491
493 492 void Window::comboBoxFocused(QComboBox *combobox)
494 493 {
495 494 foreach(QGraphicsProxyWidget* widget , m_widgetHash) {
496 495 if(widget->widget()==combobox)
497 496 widget->setZValue(2.0);
498 497 else
499 498 widget->setZValue(0.0);
500 499 }
501 500 }
502 501
503 502 void Window::handleMenu(QChart* qchart)
504 503 {
505 504 QAction *chosen = m_menu->exec(QCursor::pos());
506 505
507 506 if (chosen) {
508 507 Chart* chart = (Chart *) chosen->data().value<void *>();
509 508 int index = m_chartHash[qchart];
510 509 //not in 4.7.2 m_baseLayout->removeItem(qchart);
511 510 for(int i = 0 ; i < m_baseLayout->count();++i)
512 511 {
513 512 if(m_baseLayout->itemAt(i)==qchart){
514 513 m_baseLayout->removeAt(i);
515 514 break;
516 515 }
517 516 }
518 517
519 518 m_chartHash.remove(qchart);
520 519 QChart* newChart = chart->createChart(m_dataTable);
521 520 m_baseLayout->addItem(newChart, index / 3, index % 3);
522 521 m_chartHash[newChart] = index;
523 522 delete qchart;
524 523 updateUI();
525 524 }
526 525
527 526 }
528 527
529 528 QMenu* Window::createMenu()
530 529 {
531 530 Charts::ChartList list = Charts::chartList();
532 531 QMultiMap<QString, Chart*> categoryMap;
533 532
534 533 QMenu* result = new QMenu(this);
535 534
536 535 foreach(Chart* chart, list) {
537 536 categoryMap.insertMulti(chart->category(), chart);
538 537 }
539 538
540 539 foreach(const QString& category, categoryMap.uniqueKeys()) {
541 540 QMenu* menu(0);
542 541 QMultiMap<QString, Chart*> subCategoryMap;
543 542 if (category.isEmpty()) {
544 543 menu = result;
545 544 }
546 545 else {
547 546 menu = new QMenu(category, this);
548 547 result->addMenu(menu);
549 548 }
550 549
551 550 foreach(Chart* chart , categoryMap.values(category)) {
552 551 subCategoryMap.insert(chart->subCategory(), chart);
553 552 }
554 553
555 554 foreach(const QString& subCategory, subCategoryMap.uniqueKeys()) {
556 555 QMenu* subMenu(0);
557 556 if (subCategory.isEmpty()) {
558 557 subMenu = menu;
559 558 }
560 559 else {
561 560 subMenu = new QMenu(subCategory, this);
562 561 menu->addMenu(subMenu);
563 562 }
564 563
565 564 foreach(Chart* chart , subCategoryMap.values(subCategory)) {
566 565
567 566 createMenuAction(subMenu, QIcon(), chart->name(),
568 567 qVariantFromValue((void *) chart));
569 568 }
570 569 }
571 570 }
572 571
573 572 return result;
574 573 }
575 574
576 575 QAction* Window::createMenuAction(QMenu *menu, const QIcon &icon, const QString &text,
577 576 const QVariant &data)
578 577 {
579 578 QAction *action = menu->addAction(icon, text);
580 579 action->setCheckable(false);
581 580 action->setData(data);
582 581 return action;
583 582 }
General Comments 0
You need to be logged in to leave comments. Login now