comparison ui/mainwindow.cpp @ 654:129e611eaf50

Merge branch trustbridge-refactor
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 25 Jun 2014 15:16:24 +0200
parents 292c590ba9cb 39f03316f675
children 0ca15d937490
comparison
equal deleted inserted replaced
648:e41a2537b84d 654:129e611eaf50
24 #include <QGroupBox> 24 #include <QGroupBox>
25 #include <QSplitter> 25 #include <QSplitter>
26 #include <QLabel> 26 #include <QLabel>
27 #include <QImage> 27 #include <QImage>
28 #include <QCheckBox> 28 #include <QCheckBox>
29 #include <QButtonGroup>
30 #include <QToolButton>
29 31
30 #include "certificatelist.h" 32 #include "certificatelist.h"
31 #include "downloader.h" 33 #include "downloader.h"
32 #include "helpdialog.h" 34 #include "helpdialog.h"
33 #include "aboutdialog.h" 35 #include "aboutdialog.h"
71 MainWindow::MainWindow(bool trayMode): 73 MainWindow::MainWindow(bool trayMode):
72 mTrayMode(trayMode) 74 mTrayMode(trayMode)
73 { 75 {
74 createActions(); 76 createActions();
75 createTrayIcon(); 77 createTrayIcon();
76 createMenuBar();
77 createContent(); 78 createContent();
78 resize(950, 540); 79 resize(950, 540);
79 qRegisterMetaType<SSLConnection::ErrorCode>("SSLConnection::ErrorCode"); 80 qRegisterMetaType<SSLConnection::ErrorCode>("SSLConnection::ErrorCode");
80 qRegisterMetaType<Certificate::Status>("Certificate::Status"); 81 qRegisterMetaType<Certificate::Status>("Certificate::Status");
81 82
211 return; 212 return;
212 } 213 }
213 } 214 }
214 215
215 void MainWindow::handleNewList(const QString& fileName, const QDateTime& modDate) { 216 void MainWindow::handleNewList(const QString& fileName, const QDateTime& modDate) {
217 qDebug() << "new list available";
216 mSettings.setValue("List/available", fileName); 218 mSettings.setValue("List/available", fileName);
217 mSettings.setValue("List/availableDate", modDate); 219 mSettings.setValue("List/availableDate", modDate);
218 220
219 verifyListData(); 221 verifyListData();
220 if (!mListToInstall.isValid()) { 222 if (!mListToInstall.isValid()) {
419 mTrayIcon->setToolTip(tr("TrustBridge")); 421 mTrayIcon->setToolTip(tr("TrustBridge"));
420 422
421 connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); 423 connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
422 } 424 }
423 425
424 void MainWindow::createMenuBar()
425 {
426 mMenuBar = new QMenuBar(this);
427 QMenu *mMenu = new QMenu(tr("Menu"), mMenuBar);
428 mMenuBar->addMenu(mMenu);
429 QAction *update = mMenu->addAction(tr("Force Update"));
430 mMenu->addSeparator();
431 QAction *help = mMenu->addAction(tr("Help"));
432 QAction *about = mMenu->addAction(tr("About"));
433 mMenu->addSeparator();
434 QAction *quit = mMenu->addAction(tr("Quit"));
435 connect(update, SIGNAL(triggered()), this, SLOT(checkUpdates()));
436 connect(help, SIGNAL(triggered()), this, SLOT(showHelp()));
437 connect(about, SIGNAL(triggered()), this, SLOT(showAbout()));
438 connect(quit, SIGNAL(triggered()), this, SLOT(closeApp()));
439 setMenuBar(mMenuBar);
440 }
441
442 void MainWindow::createContent() 426 void MainWindow::createContent()
443 { 427 {
444 // Create a central widget containing the main layout. 428 // Create a central widget containing the main layout.
445 QWidget *base = new QWidget; 429 QWidget *base = new QWidget;
446 430
447 // Layouts and Container 431 // Layouts and Container
448 QHBoxLayout *mainLayout = new QHBoxLayout; 432 QVBoxLayout *mainLayout = new QVBoxLayout;
449 QVBoxLayout *infoLayout = new QVBoxLayout;
450 QVBoxLayout *certLayout = new QVBoxLayout;
451 QHBoxLayout *detailLayout = new QHBoxLayout;
452 QVBoxLayout *detailLabelLayout = new QVBoxLayout;
453 QVBoxLayout *detailContentLayout = new QVBoxLayout;
454 QHBoxLayout *headerLayout = new QHBoxLayout; 433 QHBoxLayout *headerLayout = new QHBoxLayout;
455 QVBoxLayout *headerTextLayout = new QVBoxLayout; 434 QVBoxLayout *headerTextLayout = new QVBoxLayout;
435 QHBoxLayout *centerLayout = new QHBoxLayout;
436 QVBoxLayout *buttonBarLayout = new QVBoxLayout;
456 QHBoxLayout *bottomLayout = new QHBoxLayout; 437 QHBoxLayout *bottomLayout = new QHBoxLayout;
457 QVBoxLayout *settingsLayout = new QVBoxLayout; 438 QHBoxLayout *containerLayout = new QHBoxLayout;
458 QVBoxLayout *listInfoLayout = new QVBoxLayout;
459
460 // The certificate list
461 QGroupBox *certBox = new QGroupBox(tr("Managed Certificates"));
462 mCertListWidget = new QListWidget;
463 connect(mCertListWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
464 this, SLOT(showDetails(QListWidgetItem*)));
465 certLayout->addWidget(mCertListWidget);
466
467 mCurrentListDate = new QLabel(tr("Current List Date: %1").arg(""));
468 mNewListDate = new QLabel("");
469 listInfoLayout->addWidget(mCurrentListDate);
470 listInfoLayout->addWidget(mNewListDate);
471 certLayout->addLayout(listInfoLayout);
472
473 certBox->setLayout(certLayout);
474 439
475 // The header (icon, about text) 440 // The header (icon, about text)
476 QImage *logoImage = new QImage(":/img/logo.png"); 441 QImage *logoImage = new QImage(":/img/logo.png");
477 QLabel *logo = new QLabel; 442 QLabel *logo = new QLabel;
478 logo->setBackgroundRole(QPalette::Base); 443 logo->setBackgroundRole(QPalette::Base);
479 logo->setPixmap(QPixmap::fromImage(*logoImage)); 444 logo->setPixmap(QPixmap::fromImage(*logoImage));
480 QLabel *title = new QLabel("<h2>" + QString::fromLatin1(APPNAME) + "</h2>"); 445 QLabel *title = new QLabel("<h1>" + QString::fromLatin1(APPNAME) + "</h1>");
481 QLabel *subTitle = new QLabel("This Software installs and removes Certificates"); 446 QLabel *subTitle = new QLabel("This Software installs and removes Certificates");
482 headerTextLayout->addWidget(title); 447 headerTextLayout->addWidget(title);
483 headerTextLayout->addWidget(subTitle); 448 headerTextLayout->addWidget(subTitle);
484 headerLayout->addWidget(logo); 449 headerLayout->addWidget(logo);
485 headerLayout->addLayout(headerTextLayout); 450 headerLayout->addLayout(headerTextLayout);
486 headerLayout->setStretch(0, 0); 451 headerLayout->setStretch(0, 0);
487 headerLayout->setStretch(1, 10); 452 headerLayout->setStretch(1, 10);
488 453
489 // The settings. 454 /***********************************
490 QGroupBox *settingsBox = new QGroupBox(tr("Settings")); 455 * The Buttonbar on the left side.
491 mAutoUpdateOption = new QCheckBox(tr("Autoupdate")); 456 ***********************************/
492 mAutoStartOption = new QCheckBox(tr("Autostart")); 457 mButtonGroup = new QButtonGroup;
493 settingsLayout->addWidget(mAutoUpdateOption); 458
494 settingsLayout->addWidget(mAutoStartOption); 459 QToolButton *updatesButton = new QToolButton;
495 settingsBox->setLayout(settingsLayout); 460 updatesButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
496 connect(mAutoUpdateOption, SIGNAL(stateChanged(int)), 461 updatesButton->setIcon(QIcon(":/img/view-refresh.png"));
497 this, SLOT(saveAutoUpdate(int))); 462 updatesButton->setIconSize(QSize(32, 32));
498 connect(mAutoStartOption, SIGNAL(stateChanged(int)), 463 updatesButton->setText(tr("Updates"));
499 this, SLOT(saveAutoStart(int))); 464 updatesButton->setFixedWidth(90);
500 mSettings.beginGroup("settings"); 465 updatesButton->setFixedHeight(70);
501 bool autoUpdate = mSettings.value("autoupdate", false).toBool(); 466 updatesButton->setCheckable(true);
502 bool autoStart = mSettings.value("autostart", true).toBool(); 467 updatesButton->setChecked(true);
503 mSettings.endGroup(); 468
504 mAutoUpdateOption->setCheckState(autoUpdate ? Qt::Checked : Qt::Unchecked); 469 QToolButton *allInstallButton = new QToolButton;
505 mAutoStartOption->setCheckState(autoStart ? Qt::Checked : Qt::Unchecked); 470 allInstallButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
506 471 allInstallButton->setIcon(QIcon(":/img/document-encrypt.png"));
507 472 allInstallButton->setIconSize(QSize(32, 32));
508 // The buttons. 473 allInstallButton->setText(tr("Trusted\nCertificates"));
509 bottomLayout->setAlignment(Qt::AlignBottom); 474 allInstallButton->setFixedWidth(90);
510 installButton = new QPushButton(tr("Install selected")); 475 allInstallButton->setFixedHeight(70);
511 installButton->setFixedHeight(80); 476 allInstallButton->setCheckable(true);
512 connect(installButton, SIGNAL(clicked()), this, SLOT(resizeButtons())); 477
513 connect(installButton, SIGNAL(clicked()), this, SLOT(checkAndInstallCerts())); 478 QToolButton *allRemoveButton = new QToolButton;
514 quitButton = new QPushButton(tr("Quit")); 479 allRemoveButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
515 quitButton->setFixedHeight(20); 480 allRemoveButton->setIcon(QIcon(":/img/task-attempt.png"));
516 connect(quitButton, SIGNAL(clicked()), this, SLOT(closeApp())); 481 allRemoveButton->setIconSize(QSize(32, 32));
517 bottomLayout->insertStretch(0, 10); 482 allRemoveButton->setText(tr("Insecure\nCertificates"));
518 bottomLayout->addWidget(installButton); 483 allRemoveButton->setFixedWidth(90);
519 bottomLayout->setAlignment(installButton, Qt::AlignBottom); 484 allRemoveButton->setFixedHeight(70);
520 bottomLayout->addWidget(quitButton); 485 allRemoveButton->setCheckable(true);
521 bottomLayout->setAlignment(quitButton, Qt::AlignBottom); 486
522 487 QToolButton *infoButton = new QToolButton;
488 infoButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
489 infoButton->setIcon(QIcon(":/img/dialog-information.png"));
490 infoButton->setIconSize(QSize(32, 32));
491 infoButton->setText(tr("Information"));
492 infoButton->setFixedWidth(90);
493 infoButton->setFixedHeight(70);
494 infoButton->setCheckable(true);
495
496 mButtonGroup->addButton(updatesButton);
497 mButtonGroup->addButton(allInstallButton);
498 mButtonGroup->addButton(allRemoveButton);
499 mButtonGroup->addButton(infoButton);
500 mButtonGroup->setId(updatesButton, 0);
501 mButtonGroup->setId(allInstallButton, 1);
502 mButtonGroup->setId(allRemoveButton, 2);
503 mButtonGroup->setId(infoButton, 3);
504
505 connect(mButtonGroup, SIGNAL(buttonClicked(int)),
506 this, SLOT(togglePages(int)));
507 buttonBarLayout->addWidget(updatesButton);
508 buttonBarLayout->addWidget(allInstallButton);
509 buttonBarLayout->addWidget(allRemoveButton);
510 buttonBarLayout->insertStretch(3, 10);
511 buttonBarLayout->addWidget(infoButton);
512
513 /********************************
514 * The main pages.
515 ********************************/
516
517 /********************************
518 * The updates page.
519 ********************************/
520 QVBoxLayout *updatesMainLayout = new QVBoxLayout;
521 mUpdatesPanel = new QScrollArea;
522 QScrollArea *updatesContent = new QScrollArea;
523 // updatesContent->setFrameShape(QFrame::NoFrame);
524 mUpdatesWidget = new QWidget;
525
526 /* The updates header */
527 QHBoxLayout *updatesHeaderLayout = new QHBoxLayout;
528 QVBoxLayout *updatesHeaderTextLayout = new QVBoxLayout;
529 QVBoxLayout *updatesHeaderButtonLayout = new QVBoxLayout;
530 QHBoxLayout *updatesHeaderActionLayout = new QHBoxLayout;
531 QHBoxLayout *updatesHeaderSearchLayout = new QHBoxLayout;
532
533 mUpdatesHeader =
534 new QLabel("<h2>" + tr("Updates (%1/%2)").arg(0).arg(0)+ "</h2>");
535 mLastCertUpdate =
536 new QLabel(tr("Last certificate update: %1").arg(""));
537 mLastSWupdate =
538 new QLabel(tr("Last Software update: %1").arg(""));
539 QLabel *updatesTip =
540 new QLabel("<h4>" + tr("The following certificate changes are recommended.") + "</h4>");
541
542 updatesHeaderTextLayout->addWidget(mUpdatesHeader);
543 updatesHeaderTextLayout->addWidget(mLastCertUpdate);
544 updatesHeaderTextLayout->addWidget(mLastSWupdate);
545 updatesHeaderTextLayout->addSpacing(10);
546 updatesHeaderTextLayout->addWidget(updatesTip);
547
548 QPushButton *searchUpdates = new QPushButton(tr("Search for Updates"));
549 searchUpdates->setIcon(QIcon(":/img/system-search.png"));
550 QPushButton *quitButton = new QPushButton(tr("Quit without saving"));
551 quitButton->setIcon(QIcon(":/img/system-shutdown.png"));
552 QPushButton *installButton = new QPushButton(tr("Update"));
523 #ifdef Q_OS_WIN 553 #ifdef Q_OS_WIN
524 if (is_admin()) { 554 if (is_admin()) {
525 QIcon uacShield = QApplication::style()->standardIcon(QStyle::SP_VistaShield); 555 QIcon uacShield = QApplication::style()->standardIcon(QStyle::SP_VistaShield);
526 installButton->setIcon(uacShield); 556 installButton->setIcon(uacShield);
527 } 557 }
558 #else
559 installButton->setIcon(QIcon(":/img/edit-redo.png"));
528 #endif 560 #endif
529 561 connect(quitButton, SIGNAL(clicked()), this, SLOT(closeApp()));
530 // The certificate details 562 connect(installButton, SIGNAL(clicked()), this, SLOT(checkAndInstallCerts()));
531 QGroupBox *detailBox = new QGroupBox(tr("Details")); 563 connect(searchUpdates, SIGNAL(clicked()), this, SLOT(checkUpdates()));
532 QLabel *subjectCN = new QLabel(tr("Subject Common Name:")); 564
533 QLabel *subjectOU = new QLabel(tr("Subject Organisation:")); 565 updatesHeaderActionLayout->addWidget(installButton);
534 QLabel *issuerCN = new QLabel(tr("Issuer Common Name:")); 566 updatesHeaderActionLayout->addWidget(quitButton);
535 QLabel *issuerOU = new QLabel(tr("Issuer Organisation:")); 567 updatesHeaderSearchLayout->insertStretch(0, 1);
536 QLabel *validFrom = new QLabel(tr("Valid from:")); 568 updatesHeaderSearchLayout->addWidget(searchUpdates);
537 QLabel *validTo = new QLabel(tr("Valid to:")); 569
538 QLabel *fingerprint = new QLabel(tr("Fingerprint:")); 570 updatesHeaderButtonLayout->addLayout(updatesHeaderSearchLayout);
539 detailLabelLayout->addWidget(subjectCN); 571 updatesHeaderButtonLayout->addLayout(updatesHeaderActionLayout);
540 detailLabelLayout->addWidget(subjectOU); 572
541 detailLabelLayout->addWidget(issuerCN); 573 updatesHeaderLayout->addLayout(updatesHeaderTextLayout);
542 detailLabelLayout->addWidget(issuerOU); 574 updatesHeaderLayout->insertStretch(1, 10);
543 detailLabelLayout->addWidget(validFrom); 575 updatesHeaderLayout->addLayout(updatesHeaderButtonLayout);
544 detailLabelLayout->addWidget(validTo); 576
545 detailLabelLayout->addWidget(fingerprint); 577 /* The central panels. */
546 mSubjectCN = new QLabel(tr("")); 578 QVBoxLayout *updatesCenterLayout = new QVBoxLayout;
547 mSubjectO = new QLabel(tr("")); 579 QHBoxLayout *updatesNewLayout = new QHBoxLayout;
548 mIssuerCN = new QLabel(tr("")); 580 QHBoxLayout *updatesRemoveLayout = new QHBoxLayout;
549 mIssuerO = new QLabel(tr("")); 581 QHBoxLayout *updatesManualLayout = new QHBoxLayout;
550 mValidFrom = new QLabel(tr("")); 582 mUpdatesNewCertificates =
551 mValidTo = new QLabel(tr("")); 583 new QLabel("<h3>" +
552 mFingerprint = new QLabel(tr("")); 584 tr("Install new Certificates (%1/%2)").arg(0).arg(0) +
553 mFingerprint->setFont(QFont("DejaVu Sans Mono")); 585 "</h3>");
554 detailContentLayout->addWidget(mSubjectCN); 586 mUpdatesDetailsNew = new QPushButton(tr("Show Details"));
555 detailContentLayout->addWidget(mSubjectO); 587 connect(mUpdatesDetailsNew,
556 detailContentLayout->addWidget(mIssuerCN); 588 SIGNAL(clicked()),
557 detailContentLayout->addWidget(mIssuerO); 589 this,
558 detailContentLayout->addWidget(mValidFrom); 590 SLOT(toggleUpdatesNew()));
559 detailContentLayout->addWidget(mValidTo); 591 updatesNewLayout->addWidget(mUpdatesNewCertificates);
560 detailContentLayout->addWidget(mFingerprint); 592 updatesNewLayout->addWidget(mUpdatesDetailsNew);
561 detailLayout->addLayout(detailLabelLayout); 593 updatesNewLayout->insertStretch(2, 10);
562 detailLayout->addLayout(detailContentLayout); 594 mUpdatesNew = new CertificateListWidget(this);
563 detailBox->setLayout(detailLayout); 595 connect(mUpdatesNew, SIGNAL(certListChanged(int)),
564 596 this, SLOT(listChanged(int)));
565 infoLayout->addSpacing(20); 597 mUpdatesNew->hide();
566 infoLayout->addLayout(headerLayout); 598
567 infoLayout->addWidget(detailBox); 599 mUpdatesRemoveCertificates =
568 infoLayout->addWidget(settingsBox); 600 new QLabel("<h3>" +
569 infoLayout->addLayout(bottomLayout); 601 tr("Remove insecure Certificates (%1/%2)").arg(0).arg(0) +
570 602 "</h3>");
571 mainLayout->addWidget(certBox); 603 mUpdatesDetailsRemove = new QPushButton(tr("Show Details"));
572 mainLayout->addLayout(infoLayout); 604 connect(mUpdatesDetailsRemove,
573 mainLayout->setStretchFactor(certBox, 37); 605 SIGNAL(clicked()),
574 mainLayout->setStretchFactor(infoLayout, 63); 606 this,
575 607 SLOT(toggleUpdatesRemove()));
576 // QMainWindow allready has a layout. All child layouts and widgets are 608 updatesRemoveLayout->addWidget(mUpdatesRemoveCertificates);
577 // managed in the central widget. 609 updatesRemoveLayout->addWidget(mUpdatesDetailsRemove);
610 updatesRemoveLayout->insertStretch(2, 10);
611 mUpdatesRemove = new CertificateListWidget(this);
612 connect(mUpdatesRemove, SIGNAL(certListChanged(int)),
613 this, SLOT(listChanged(int)));
614 mUpdatesRemove->hide();
615
616 mUpdatesManualCertificates =
617 new QLabel("<h3>" +
618 tr("Manualy changed Certificates (%1)").arg(0) +
619 "</h3>");
620 mUpdatesDetailsManual = new QPushButton(tr("Show Details"));
621 connect(mUpdatesDetailsManual,
622 SIGNAL(clicked()),
623 this,
624 SLOT(toggleUpdatesManual()));
625 updatesManualLayout->addWidget(mUpdatesManualCertificates);
626 updatesManualLayout->addWidget(mUpdatesDetailsManual);
627 updatesManualLayout->insertStretch(2, 10);
628 mUpdatesManual = new CertificateListWidget(this);
629 mUpdatesManual->hide();
630 connect(mUpdatesManual, SIGNAL(certChanged(bool, const Certificate&)),
631 this, SLOT(removeFromManual(bool, const Certificate&)));
632
633 updatesNewLayout->setAlignment(Qt::AlignTop);
634 updatesRemoveLayout->setAlignment(Qt::AlignTop);
635 updatesManualLayout->setAlignment(Qt::AlignTop);
636 updatesCenterLayout->addLayout(updatesNewLayout);
637 updatesCenterLayout->addWidget(mUpdatesNew);
638 updatesCenterLayout->addLayout(updatesRemoveLayout);
639 updatesCenterLayout->addWidget(mUpdatesRemove);
640 updatesCenterLayout->addLayout(updatesManualLayout);
641 updatesCenterLayout->addWidget(mUpdatesManual);
642 updatesCenterLayout->addStretch(1);
643
644 updatesCenterLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
645 mUpdatesWidget->setLayout(updatesCenterLayout);
646 updatesContent->setWidget(mUpdatesWidget);
647
648 updatesMainLayout->addLayout(updatesHeaderLayout);
649 updatesMainLayout->addWidget(updatesContent);
650 mUpdatesPanel->setLayout(updatesMainLayout);
651
652 /*********************************
653 * Panel for trusted certificates.
654 *********************************/
655 mInstallPanel = new QScrollArea;
656
657 QVBoxLayout *installPanelLayout = new QVBoxLayout;
658 QVBoxLayout *installHeaderLayout = new QVBoxLayout;
659 QVBoxLayout *installCenterLayout = new QVBoxLayout;
660
661 QLabel *installHeaderLabel =
662 new QLabel("<h2>" + tr("Trusted Certificates") + "</h2>");
663 QLabel *installHeaderText = new QLabel(tr("The following list of root"
664 " certificates was created by the BSI. The BSI vaidates authenticity,"
665 " security and actuality of these certificates"));
666 installHeaderLayout->addWidget(installHeaderLabel);
667 installHeaderLayout->addWidget(installHeaderText);
668
669 QLabel *installCenterText = new QLabel(tr("Please choose the certificates"
670 " you want to trust. TrustBridge will install these certificates for"
671 " secure communication via email or the internet (e.g. IE, Firefox,"
672 " Thunderbird)"));
673 installCenterLayout->addWidget(installCenterText);
674 mInstallList = new CertificateListWidget(this);
675 connect(mInstallList, SIGNAL(certChanged(bool, const Certificate&)),
676 this, SLOT(toggleInManual(bool, const Certificate&)));
677
678 installPanelLayout->addLayout(installHeaderLayout);
679 installPanelLayout->addLayout(installCenterLayout);
680 installPanelLayout->addWidget(mInstallList);
681 mInstallPanel->setLayout(installPanelLayout);
682
683 /**********************************
684 * Panel for insecure certificates.
685 **********************************/
686 mRemovePanel = new QScrollArea;
687 QVBoxLayout *removePanelLayout = new QVBoxLayout;
688 QVBoxLayout *removeHeaderLayout = new QVBoxLayout;
689 QVBoxLayout *removeCenterLayout = new QVBoxLayout;
690
691 QLabel *removeHeaderLabel =
692 new QLabel("<h2>" + tr("Insecure Certificates") + "</h2>");
693 QLabel *removeHeaderText = new QLabel(tr("The following list of root"
694 " certificates was created by the BSI. The BSI validates authenticity,"
695 " security and actuality of these certificates"));
696 removeHeaderLayout->addWidget(removeHeaderLabel);
697 removeHeaderLayout->addWidget(removeHeaderText);
698
699 QLabel *removeCenterText = new QLabel(tr("Please choose the certificates"
700 " you want to remove. TrustBridge will remove these certificates."));
701 removeCenterLayout->addWidget(removeCenterText);
702 mRemoveList = new CertificateListWidget(this);
703 connect(mRemoveList, SIGNAL(certChanged(bool, const Certificate&)),
704 this, SLOT(toggleInManual(bool, const Certificate&)));
705
706 removePanelLayout->addLayout(removeHeaderLayout);
707 removePanelLayout->addLayout(removeCenterLayout);
708 removePanelLayout->addWidget(mRemoveList);
709 mRemovePanel->setLayout(removePanelLayout);
710
711 /**********************************
712 * The info panel.
713 **********************************/
714 mInfoPanel = new QScrollArea;
715
716 QVBoxLayout *infoPanelLayout = new QVBoxLayout;
717 QHBoxLayout *infoHeaderLayout = new QHBoxLayout;
718 QVBoxLayout *infoHeaderTextLayout = new QVBoxLayout;
719 QVBoxLayout *infoCenterLayout = new QVBoxLayout;
720
721 QImage *infoLogoImage = new QImage(":/img/logo.png");
722 QLabel *infoLogo = new QLabel;
723 infoLogo->setBackgroundRole(QPalette::Base);
724 infoLogo->setPixmap(QPixmap::fromImage(*infoLogoImage));
725 QLabel *infoTitle = new QLabel("<h1>" + tr("TrustBridge") + "</h1>");
726 QString infoVersion = tr("Version: ");
727 infoVersion.append(QApplication::applicationVersion());
728 QLabel *appVersion = new QLabel(infoVersion);
729 appVersion->setTextInteractionFlags(
730 Qt::TextSelectableByMouse |
731 Qt::TextSelectableByKeyboard);
732
733 QFrame *infoHeaderSeparator = new QFrame();
734 infoHeaderSeparator->setFrameShape(QFrame::HLine);
735 infoHeaderSeparator->setFrameShadow(QFrame::Sunken);
736
737 infoHeaderTextLayout->addWidget(infoTitle);
738 infoHeaderTextLayout->addWidget(appVersion);
739 infoHeaderLayout->addWidget(infoLogo);
740 infoHeaderLayout->addLayout(infoHeaderTextLayout);
741 infoHeaderLayout->insertStretch(2, 10);
742
743 QLabel *textDesc = new QLabel(tr("TrustBridge is a root certificate"
744 " installer for Windows and Linux."));
745 textDesc->setTextInteractionFlags(
746 Qt::TextSelectableByMouse |
747 Qt::TextSelectableByKeyboard);
748 QLabel *textManage = new QLabel(tr("The root certificate lists are managed"
749 " by the German <a href=\"https://www.bsi.bund.de\">"
750 "Federal Office for Information Security (BSI)</a>.\n\n"));
751 textManage->setTextInteractionFlags(
752 Qt::TextBrowserInteraction |
753 Qt::TextSelectableByKeyboard);
754 QLabel *textDevel = new QLabel(tr("The software was developed by the companies"
755 " <a href=\"http://www.intevation.de\">Intevation GmbH</a> and "
756 " <a href=\"http://www.dn-systems.de\">DN-Systems GmbH</a>, <br>"
757 " contracted by the German Federal Office for Information Security (BSI).\n\n"));
758 textDevel->setTextInteractionFlags(
759 Qt::TextBrowserInteraction |
760 Qt::TextSelectableByKeyboard);
761 QLabel *textLicense = new QLabel(tr("TrustBridge is Free Software licensed"
762 " under GNU GPL v2+.\n\nCopyright (C) 2014 by Bundesamt für Sicherheit"
763 " in der Informationstechnik"));
764 textLicense->setTextInteractionFlags(
765 Qt::TextSelectableByMouse |
766 Qt::TextSelectableByKeyboard);
767
768 infoCenterLayout->addWidget(infoHeaderSeparator);
769 infoCenterLayout->addWidget(textDesc);
770 infoCenterLayout->addWidget(textManage);
771 infoCenterLayout->addWidget(textDevel);
772 infoCenterLayout->addWidget(textLicense);
773 infoCenterLayout->insertSpacing(2, 10);
774 infoCenterLayout->insertSpacing(4, 10);
775 infoCenterLayout->insertSpacing(6, 10);
776 infoCenterLayout->insertStretch(8, 10);
777
778 infoPanelLayout->addLayout(infoHeaderLayout);
779 infoPanelLayout->addLayout(infoCenterLayout);
780 mInfoPanel->setLayout(infoPanelLayout);
781
782 /********************************
783 * The main layout for pages.
784 ********************************/
785 mInstallPanel->hide();
786 mRemovePanel->hide();
787 mInfoPanel->hide();
788 containerLayout->addWidget(mUpdatesPanel);
789 containerLayout->addWidget(mInstallPanel);
790 containerLayout->addWidget(mRemovePanel);
791 containerLayout->addWidget(mInfoPanel);
792
793 centerLayout->addLayout(buttonBarLayout);
794 centerLayout->addLayout(containerLayout);
795
796 mainLayout->addLayout(headerLayout);
797 mainLayout->addLayout(centerLayout);
798 mainLayout->addLayout(bottomLayout);
578 base->setLayout(mainLayout); 799 base->setLayout(mainLayout);
579 setCentralWidget(base); 800 setCentralWidget(base);
580 } 801 }
581 802
803 void MainWindow::listChanged(int selected)
804 {
805 mUpdatesHeader->setText("<h2>" + tr("Updates (%1/%2)")
806 .arg(mUpdatesRemove->selectedCertCount() + mUpdatesNew->selectedCertCount())
807 .arg(mUpdatesRemove->certificates().size() + mUpdatesNew->certificates().size()) +
808 "</h2>");
809 mUpdatesNewCertificates->setText("<h3>" +
810 tr("Install new Certificates (%1/%2)")
811 .arg(mUpdatesNew->selectedCertCount())
812 .arg(mUpdatesNew->certificates().size()) +
813 "</h3>");
814 mUpdatesRemoveCertificates->setText("<h3>" +
815 tr("Remove insecure Certificates (%1/%2)")
816 .arg(mUpdatesRemove->selectedCertCount())
817 .arg(mUpdatesRemove->certificates().size()) +
818 "</h3>");
819 }
820
582 void MainWindow::loadCertificateList() 821 void MainWindow::loadCertificateList()
583 { 822 {
584 mCertListWidget->clear();
585 int i = 0;
586
587 /* TODO: if nothing is available (neither old nor new) add some progress 823 /* TODO: if nothing is available (neither old nor new) add some progress
588 * indication */ 824 * indication */
825 mInstallList->clear();
826 mUpdatesNew->clear();
827 mRemoveList->clear();
828 mUpdatesRemove->clear();
589 QList<Certificate> newInstallCerts; 829 QList<Certificate> newInstallCerts;
590 QList<Certificate> newRemoveCerts; 830 QList<Certificate> newRemoveCerts;
591 QList<Certificate> oldInstallCerts; 831 QList<Certificate> oldInstallCerts;
592 QList<Certificate> oldRemoveCerts; 832 QList<Certificate> oldRemoveCerts;
593 833
594 if (mListToInstall.getCertificates().isEmpty()) { 834 if (mListToInstall.getCertificates().isEmpty()) {
595 // No new list available, add old certificates. 835 // No new list available, add old certificates.
596 foreach (const Certificate &cert, mInstalledList.getCertificates()) { 836 foreach (const Certificate &cert, mInstalledList.getCertificates()) {
837 bool state = !mPreviouslyUnselected.contains(cert.base64Line());
597 if (cert.isInstallCert()) { 838 if (cert.isInstallCert()) {
598 oldInstallCerts.append(cert); 839 oldInstallCerts.append(cert);
840 mInstallList->addCertificate(cert, state);
599 } 841 }
600 else { 842 else {
601 oldRemoveCerts.append(cert); 843 oldRemoveCerts.append(cert);
844 mRemoveList->addCertificate(cert, state, !state);
602 } 845 }
603 } 846 }
604 // Set the date of the old list.
605 mCurrentListDate->setText(tr("Current List Date: %1")
606 .arg(mInstalledList.date().toString()));
607 } 847 }
608 else { 848 else {
609 // Sort and filter both lists. 849 // Sort and filter both lists.
610 foreach (const Certificate &cert, mListToInstall.getCertificates()) { 850 foreach (const Certificate &cert, mListToInstall.getCertificates()) {
851 bool state = !mPreviouslyUnselected.contains(cert.base64Line());
611 if (cert.isInstallCert()) { 852 if (cert.isInstallCert()) {
612 // Certificate with status "install". 853 // Certificate with status "install".
613 if (mInstalledList.getCertificates().contains(cert)) { 854 if (mInstalledList.getCertificates().contains(cert)) {
614 // Was in the old list. 855 // Was in the old list.
615 oldInstallCerts.append(cert); 856 oldInstallCerts.append(cert);
857 mInstallList->addCertificate(cert, state);
616 } 858 }
617 else { 859 else {
618 // Is a brand new certificate 860 // Is a brand new certificate
619 newInstallCerts.append(cert); 861 newInstallCerts.append(cert);
862 mUpdatesNew->addCertificate(cert, state);
620 } 863 }
621 } 864 }
622 else { 865 else {
623 // Certificate with status "remove". 866 // Certificate with status "remove".
624 if (mInstalledList.getCertificates().contains(cert)) { 867 if (mInstalledList.getCertificates().contains(cert)) {
625 // Was in the old list. 868 // Was in the old list.
626 oldRemoveCerts.append(cert); 869 oldRemoveCerts.append(cert);
870 // Is removed, so set editable to false.
871 mRemoveList->addCertificate(cert, state, !state);
627 } 872 }
628 else { 873 else {
629 // Was in the old list with status "install" and now has the 874 // Was in the old list with status "install" and now has the
630 // status "remove". 875 // status "remove".
631 newRemoveCerts.append(cert); 876 newRemoveCerts.append(cert);
877 mUpdatesRemove->addCertificate(cert, state);
632 } 878 }
633 } 879 }
634 } 880 }
635 mCurrentListDate->setText(tr("Current List Date: %1") 881 mUpdatesHeader->setText("<h2>" +
882 tr("Updates (%1/%2)")
883 .arg(mUpdatesNew->selectedCertCount() + mUpdatesRemove->selectedCertCount())
884 .arg(newRemoveCerts.size() + newInstallCerts.size()) + "</h2>");
885 mLastCertUpdate->setText(tr("Last certificate update: %1")
636 .arg(mInstalledList.date().toString())); 886 .arg(mInstalledList.date().toString()));
637 mNewListDate->setText(tr("New List Date: %1").arg(mListToInstall.date().toString())); 887 }
638 } 888 mUpdatesNewCertificates->setText("<h3>" +
639 889 tr("Install new Certificates (%1/%2)")
640 // Add separators and certificates to list widget. 890 .arg(mUpdatesNew->selectedCertCount())
641 if (!newInstallCerts.isEmpty()) { 891 .arg(mUpdatesNew->certificates().size()) +
642 mCertListWidget->addItem(createSeparator(tr("New certificates to install"), i++)); 892 "</h3>");
643 foreach (const Certificate &cert, newInstallCerts) { 893
644 mCertListWidget->addItem(createListItem(cert, Certificate::InstallNew, i++)); 894 mUpdatesRemoveCertificates->setText("<h3>" +
645 } 895 tr("Remove insecure Certificates (%1/%2)")
646 } 896 .arg(mUpdatesRemove->selectedCertCount())
647 897 .arg(mUpdatesRemove->certificates().size()) +
648 if (!newRemoveCerts.isEmpty()) { 898 "</h3>");
649 mCertListWidget->addItem(createSeparator(tr("New certificates to remove"), i++)); 899 mUpdatesManualCertificates->setText("<h3>" +
650 foreach (const Certificate &cert, newRemoveCerts) { 900 tr("Manualy changed Certificates (%1)").arg(0) +
651 mCertListWidget->addItem(createListItem(cert, Certificate::RemoveNew, i++)); 901 "</h3>");
652 }
653 }
654
655 if (!oldInstallCerts.isEmpty()) {
656 mCertListWidget->addItem(createSeparator(tr("Old certificates to install"), i++));
657 foreach (const Certificate &cert, oldInstallCerts) {
658 mCertListWidget->addItem(createListItem(cert, Certificate::InstallOld, i++));
659 }
660 }
661
662 if (!oldRemoveCerts.isEmpty()) {
663 mCertListWidget->addItem(createSeparator(tr("Old certificates to remove"), i++));
664 foreach (const Certificate &cert, oldRemoveCerts) {
665 mCertListWidget->addItem(createListItem(cert, Certificate::RemoveOld, i++));
666 }
667 }
668 }
669
670 QListWidgetItem* MainWindow::createSeparator(const QString &text, int index)
671 {
672 SeparatorItemDelegate *separatorDelegate = new SeparatorItemDelegate();
673 QListWidgetItem *separator = new QListWidgetItem(text);
674 mCertListWidget->setItemDelegateForRow(index, separatorDelegate);
675 separator->setFlags(separator->flags() ^ Qt::ItemIsUserCheckable);
676 return separator;
677 }
678
679 QListWidgetItem* MainWindow::createListItem(const Certificate &certificate,
680 Certificate::Status status, int index)
681 {
682 CertificateItemDelegate *certDelegate = new CertificateItemDelegate();
683 QListWidgetItem* item = new QListWidgetItem(certificate.shortDescription());
684 item->setData(CertificateItemDelegate::DataRole,
685 QVariant::fromValue(certificate));
686 item->setData(CertificateItemDelegate::StatusRole, status);
687 if (!mPreviouslyUnselected.contains(certificate.base64Line()) &&
688 status == Certificate::RemoveOld) {
689 item->setFlags(item->flags() ^ Qt::ItemIsUserCheckable);
690 }
691 else {
692 Qt::CheckState checkedState =
693 mPreviouslyUnselected.contains(certificate.base64Line()) ?
694 Qt::Unchecked : Qt::Checked;
695 item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
696 item->setCheckState(checkedState);
697 }
698 mCertListWidget->setItemDelegateForRow(index, certDelegate);
699 return item;
700 }
701
702 void MainWindow::showHelp()
703 {
704 qDebug() << "show helpdialog";
705 HelpDialog *help = new HelpDialog(this);
706 help->show();
707 }
708
709 void MainWindow::showAbout()
710 {
711 qDebug() << "show aboutdialog";
712 AboutDialog *about = new AboutDialog(this);
713 about->show();
714 }
715
716 void MainWindow::showDetails(QListWidgetItem *item)
717 {
718 if (item == NULL) {
719 return;
720 }
721 Certificate cert = item->data(CertificateItemDelegate::DataRole).value<Certificate>();
722 mSubjectCN->setText(cert.subjectCN());
723 mSubjectO->setText(cert.subjectO());
724 mIssuerCN->setText(cert.issuerCN());
725 mIssuerO->setText(cert.issuerO());
726 mValidFrom->setText(cert.validFrom().toString());
727 mValidTo->setText(cert.validTo().toString());
728 mFingerprint->setText(cert.fingerprint());
729 }
730
731 void MainWindow::resizeButtons()
732 {
733 installButton->setFixedHeight(20);
734 quitButton->setFixedHeight(80);
735 } 902 }
736 903
737 void MainWindow::installerError(const QString& errMsg) { 904 void MainWindow::installerError(const QString& errMsg) {
738 QMessageBox::warning(this, tr("Error executing update"), errMsg); 905 QMessageBox::warning(this, tr("Error executing update"), errMsg);
739 } 906 }
762 loadCertificateList(); 929 loadCertificateList();
763 } 930 }
764 931
765 void MainWindow::installCerts() { 932 void MainWindow::installCerts() {
766 QStringList choices; 933 QStringList choices;
767 934 QStringList unselected;
768 for (int i = 0; i < mCertListWidget->count(); i++) { 935
769 QListWidgetItem *item = mCertListWidget->item(i); 936 choices << mUpdatesNew->selectedCertificates();
770 if (item->checkState() == Qt::Checked) { 937 choices << mUpdatesRemove->selectedCertificates();
771 choices << item->data(CertificateItemDelegate::DataRole).value<Certificate>().base64Line(); 938
772 continue; 939 choices << mUpdatesManual->selectedCertificates();
773 } 940 QStringList unselectedManuals = mUpdatesManual->unselectedCertificates();
774 QString certLine = item->data(CertificateItemDelegate::DataRole).value<Certificate>().base64Line(); 941 for(int i = 0; i < unselectedManuals.size(); i++) {
775 if (certLine.startsWith("I:")) { 942 if (unselectedManuals.at(i).startsWith("I:")) {
943 QString certLine = unselectedManuals.at(i);
776 certLine[0] = 'R'; 944 certLine[0] = 'R';
777 choices << certLine; 945 choices << certLine;
778 } 946 }
779 } 947 }
948
949 unselected << mUpdatesNew->unselectedCertificates();
950 unselected << mUpdatesRemove->unselectedCertificates();
951 unselected << mInstallList->unselectedCertificates();
952 unselected << mRemoveList->unselectedCertificates();
780 953
781 QProgressDialog *progress = new QProgressDialog(this); 954 QProgressDialog *progress = new QProgressDialog(this);
782 progress->setWindowModality(Qt::WindowModal); 955 progress->setWindowModality(Qt::WindowModal);
783 progress->setLabelText(tr("Installing certificates...")); 956 progress->setLabelText(tr("Installing certificates..."));
784 progress->setCancelButton(0); 957 progress->setCancelButton(0);
799 this, SLOT(installerSuccess())); 972 this, SLOT(installerSuccess()));
800 connect(instWrap, SIGNAL(error(const QString &)), 973 connect(instWrap, SIGNAL(error(const QString &)),
801 this, SLOT(installerError(const QString &))); 974 this, SLOT(installerError(const QString &)));
802 instWrap->start(); 975 instWrap->start();
803 976
804 if (!saveUnselectedCertificates()) { 977 if (!saveUnselectedCertificates(unselected)) {
805 qWarning() << "Failed to save previosly unselected certificates."; 978 qWarning() << "Failed to save previosly unselected certificates.";
806 } 979 }
980
807 } 981 }
808 982
809 void MainWindow::loadUnselectedCertificates() 983 void MainWindow::loadUnselectedCertificates()
810 { 984 {
811 mPreviouslyUnselected.clear(); 985 mPreviouslyUnselected.clear();
815 mPreviouslyUnselected << mSettings.value(key, QString()).toString(); 989 mPreviouslyUnselected << mSettings.value(key, QString()).toString();
816 } 990 }
817 mSettings.endGroup(); 991 mSettings.endGroup();
818 } 992 }
819 993
820 bool MainWindow::saveUnselectedCertificates() 994 bool MainWindow::saveUnselectedCertificates(QStringList unselected)
821 { 995 {
822 mPreviouslyUnselected.clear(); 996 mPreviouslyUnselected.clear();
823 mSettings.beginGroup("unselected"); 997 mSettings.beginGroup("unselected");
824 mSettings.remove(""); /* Clears old choices */ 998 mSettings.remove(""); /* Clears old choices */
825 for (int i = 0; i < mCertListWidget->count(); i++) { 999 for (int i = 0; i < unselected.size(); i++) {
826 QListWidgetItem *item = mCertListWidget->item(i); 1000 QString key = QString::fromLatin1("cert%1").arg(i);
827 if (item->checkState() != Qt::Checked && 1001 QString value = unselected.at(i);
828 (item->flags() & Qt::ItemIsUserCheckable)) { 1002 mSettings.setValue(key, value);
829 QString key = QString::fromLatin1("cert%1").arg(i); 1003 mPreviouslyUnselected << value;
830 QString value =
831 item->data(CertificateItemDelegate::DataRole).value<Certificate>().base64Line();
832 mSettings.setValue(key, value);
833 mPreviouslyUnselected << value;
834 }
835 } 1004 }
836 mSettings.endGroup(); 1005 mSettings.endGroup();
837 mSettings.sync(); 1006 mSettings.sync();
838 return mSettings.status() == QSettings::NoError; 1007 return mSettings.status() == QSettings::NoError;
839 } 1008 }
840 1009
841 void MainWindow::saveAutoUpdate(int state) 1010 void MainWindow::toggleInManual(bool state, const Certificate &cert)
842 { 1011 {
843 mSettings.beginGroup("settings"); 1012 if (!mUpdatesManual->contains(cert)) {
844 mSettings.setValue("autoupdate", state != Qt::Unchecked); 1013 mUpdatesManual->addCertificate(cert, state);
845 mSettings.endGroup(); 1014 }
846 } 1015 else {
847 1016 mUpdatesManual->removeCertificate(cert);
848 void MainWindow::saveAutoStart(int state) 1017 }
849 { 1018
850 mSettings.beginGroup("settings"); 1019 mUpdatesManualCertificates->setText("<h3>" +
851 mSettings.setValue("autostart", state != Qt::Unchecked); 1020 tr("Manualy changed Certificates (%1)")
852 mSettings.endGroup(); 1021 .arg(mUpdatesManual->certificates().size()) +
1022 "</h3>");
1023 }
1024
1025 void MainWindow::removeFromManual(bool state, const Certificate &cert)
1026 {
1027 mUpdatesManual->removeCertificate(cert);
1028
1029 mUpdatesManualCertificates->setText("<h3>" +
1030 tr("Manualy changed Certificates (%1)")
1031 .arg(mUpdatesManual->certificates().size()) +
1032 "</h3>");
1033
1034 if (cert.isInstallCert()) {
1035 mInstallList->setCertState(state, cert);
1036 }
1037 else {
1038 mRemoveList->setCertState(state, cert);
1039 }
853 } 1040 }
854 1041
855 void MainWindow::closeApp() 1042 void MainWindow::closeApp()
856 { 1043 {
857 saveUnselectedCertificates();
858 qApp->quit(); 1044 qApp->quit();
859 } 1045 }
860 1046
861 void MainWindow::checkAndInstallCerts() 1047 void MainWindow::checkAndInstallCerts()
862 { 1048 {
876 1062
877 connect(waitDialog, SIGNAL(accepted()), this, SLOT(installCerts())); 1063 connect(waitDialog, SIGNAL(accepted()), this, SLOT(installCerts()));
878 connect(waitDialog, SIGNAL(accepted()), waitDialog, SLOT(deleteLater())); 1064 connect(waitDialog, SIGNAL(accepted()), waitDialog, SLOT(deleteLater()));
879 1065
880 waitDialog->exec(); 1066 waitDialog->exec();
881
882 return; 1067 return;
883 } 1068 }
1069
1070 void MainWindow::togglePages(int button)
1071 {
1072 UpdatesPanel->hide();
1073 mInstallPanel->hide();
1074 mRemovePanel->hide();
1075 mInfoPanel->hide();
1076 switch(button) {
1077 case 0: mUpdatesPanel->show(); break;
1078 case 1: mInstallPanel->show(); break;
1079 case 2: mRemovePanel->show(); break;
1080 case 3: mInfoPanel->show(); break;
1081 default: mUpdatesPanel->show(); break;
1082 }
1083 return;
1084 }
1085
1086 void MainWindow::toggleUpdatesNew() {
1087 if (!mUpdatesNew->isVisible()) {
1088 mUpdatesDetailsNew->setText(tr("Hide Details"));
1089 mUpdatesNew->show();
1090 mUpdatesNew->setSelected(0);
1091 }
1092 else {
1093 mUpdatesNew->hide();
1094 mUpdatesDetailsNew->setText(tr("Show Details"));
1095 QSize old = mUpdatesWidget->size();
1096 mUpdatesWidget->resize(old.width(), old.height() - mUpdatesNew->height());
1097 }
1098 }
1099
1100 void MainWindow::toggleUpdatesRemove() {
1101 if (!mUpdatesRemove->isVisible()) {
1102 mUpdatesDetailsRemove->setText(tr("Hide Details"));
1103 mUpdatesRemove->show();
1104 mUpdatesRemove->setSelected(0);
1105 }
1106 else {
1107 mUpdatesRemove->hide();
1108 mUpdatesDetailsRemove->setText(tr("Show Details"));
1109 QSize old = mUpdatesWidget->size();
1110 mUpdatesWidget->resize(old.width(), old.height() - mUpdatesRemove->height());
1111 }
1112 }
1113
1114 void MainWindow::toggleUpdatesManual() {
1115 if (!mUpdatesManual->isVisible()) {
1116 mUpdatesDetailsManual->setText(tr("Hide Details"));
1117 mUpdatesManual->show();
1118 mUpdatesManual->setSelected(0);
1119 }
1120 else {
1121 mUpdatesDetailsManual->setText(tr("Show Details"));
1122 mUpdatesManual->hide();
1123 QSize old = mUpdatesWidget->size();
1124 mUpdatesWidget->resize(old.width(), old.height() - mUpdatesManual->height());
1125 }
1126 }
1127 >>>>>>> other

http://wald.intevation.org/projects/trustbridge/