Exemple #1
0
void MainWindow::createMenus()
{
   QAction* action;
   QString  name;
   QMenu*   menu;
   QMenu*   subMenu;

   // ----- File Menu -----
   menu = menuBar()->addMenu("File");

      name = "About";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(showAbout()));

      name = "New Molecule";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(newMoleculeMenu()));
      action->setShortcut(QKeySequence::New);

      name = "New Viewer";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(newViewer()));

      name = "Open";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(openFile()));
      action->setShortcut(QKeySequence::Open);

      name = "Open Recent";
      m_recentFilesMenu = menu->addMenu(name);
      updateRecentFilesMenu();

      menu->addSeparator();

/*
      name = "Parse Test File";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(parseFile()));

      menu->addSeparator();
*/

      name = "Close Viewer";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(close()));
      action->setShortcut(QKeySequence::Close);

      name = "Save";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(saveAll()));
      action->setShortcut(QKeySequence::Save);

      name = "Save As";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(saveAs()));
      action->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_S);

      menu->addSeparator();

      name = "Save Picture";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewer, SLOT(saveSnapshot()));
      action->setShortcut(Qt::CTRL + Qt::Key_P);

      name = "Record Animation";
      action = menu->addAction(name);
      action->setCheckable(true);
      action->setChecked(false);
      connect(action, SIGNAL(triggered()), this, SLOT(toggleRecordingActive()));
      action->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_P);
      m_recordAnimationAction = action;

      name = "Show Message Log";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(showLogMessages()));
      action->setShortcut(Qt::CTRL + Qt::Key_L);

      name = "Quit";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(quit()));
      action->setShortcut(Qt::CTRL + Qt::Key_Q);


   // ----- Edit Menu -----
   menu = menuBar()->addMenu("Edit");
  
      name = "Undo";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_undoStack, SLOT(undo()));
      action->setShortcut(QKeySequence::Undo);
      connect(&m_undoStack, SIGNAL(canUndoChanged(bool)), action, SLOT(setEnabled(bool)));

      name = "Redo";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_undoStack, SLOT(redo()));
      action->setShortcut(QKeySequence::Redo);
      connect(&m_undoStack, SIGNAL(canRedoChanged(bool)), action, SLOT(setEnabled(bool)));

      menu->addSeparator();

      name = "Cut";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(cutSelection()));
      action->setShortcut(Qt::CTRL + Qt::Key_X);

      name = "Copy";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(copySelectionToClipboard()));
      action->setShortcut(Qt::CTRL + Qt::Key_C);

      name = "Paste";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(pasteSelectionFromClipboard()));
      action->setShortcut(Qt::CTRL + Qt::Key_V);

      menu->addSeparator();

      name = "Select All";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(selectAll()));
      action->setShortcut(Qt::CTRL + Qt::Key_A);

      name = "Select None";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SIGNAL(clearSelection()));
      action->setShortcut(Qt::SHIFT + Qt::CTRL + Qt::Key_A);

      name = "Invert Selection";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(invertSelection()));
      action->setShortcut(Qt::CTRL + Qt::Key_I);

      menu->addSeparator();

      name = "Reindex Atoms";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(reindexAtoms()));


      menu->addSeparator();

      name = "Preferences";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(showPreferences()));


   // ----- Display Menu -----
   menu = menuBar()->addMenu("Display");

      name = "Full Screen";
      action = menu->addAction(name);
      action->setCheckable(true);
      action->setChecked(false);
      connect(action, SIGNAL(triggered()), this, SLOT(fullScreen()));
      action->setShortcut(Qt::CTRL + Qt::Key_0);
      m_fullScreenAction = action;

      name = "Reset View";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewer, SLOT(resetView()));
      action->setShortcut(Qt::CTRL + Qt::Key_R);

      name = "Show Axes";
      action = menu->addAction(name);
      action->setCheckable(true);
      action->setChecked(false);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(toggleAxes()));
      connect(&m_viewerModel, SIGNAL(axesOn(bool)), action, SLOT(setChecked(bool)));
      action->setShortcut(Qt::Key_A);


      menu->addSeparator();

      name = "Atom Labels";
      subMenu = menu->addMenu(name);

         name = "Element";
         action = subMenu->addAction(name);
         connect(action, SIGNAL(triggered()), this, SLOT(setLabel()));
         action->setData(Layer::Atom::Element);
         action->setShortcut(Qt::Key_E);
         action->setCheckable(true);
         m_labelActions << action;

         name = "Index";
         action = subMenu->addAction(name);
         connect(action, SIGNAL(triggered()), this, SLOT(setLabel()));
         action->setData(Layer::Atom::Index);
         action->setShortcut(Qt::Key_I);
         action->setCheckable(true);
         m_labelActions << action;
   
         name = "Mass";
         action = subMenu->addAction(name);
         connect(action, SIGNAL(triggered()), this, SLOT(setLabel()));
         action->setData(Layer::Atom::Mass);
         action->setShortcut(Qt::Key_M);
         action->setCheckable(true);
         m_labelActions << action;

/*
         name = "NMR Shifts";
         action = subMenu->addAction(name);
         connect(action, SIGNAL(triggered()), this, SLOT(setLabel()));
         action->setData(Layer::Atom::NmrShifts);
         action->setShortcut(Qt::Key_N);
         action->setCheckable(true);
         m_labelActions << action;
*/

         name = "Partial Charge";
         action = subMenu->addAction(name);
         connect(action, SIGNAL(triggered()), this, SLOT(setLabel()));
         action->setData(Layer::Atom::Charge);
         action->setShortcut(Qt::Key_Q);
         action->setCheckable(true);
         m_labelActions << action;

         name = "Spin Densities";
         action = subMenu->addAction(name);
         connect(action, SIGNAL(triggered()), this, SLOT(setLabel()));
         action->setData(Layer::Atom::Spin);
         action->setShortcut(Qt::Key_S);
         action->setCheckable(true);
         m_labelActions << action;

   menu->addSeparator();

   name = "Configure Appearance";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(configureAppearance()));


      // These are not working correctly at the moment.
/*
      name = "Partial Charge Type";
      QActionGroup* partialChargeGroup = new QActionGroup(this);
      subMenu = menu->addMenu(name);

         QString pc("Gasteiger");
         action = subMenu->addAction(pc);
         action->setCheckable(true);
         action->setChecked(true);
         action->setData(pc);
         partialChargeGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setPartialChargeType()));

         pc = "Sanderson";
         action = subMenu->addAction(pc);
         action->setCheckable(true);
         action->setData(pc);
         partialChargeGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setPartialChargeType()));

         pc = "Mulliken";
         action = subMenu->addAction(pc);
         action->setCheckable(true);
         action->setData(pc);
         partialChargeGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setPartialChargeType()));
*/



   // ----- Build Menu -----
   menu = menuBar()->addMenu("Build");

      name = "Fill Valencies With Hydrogens";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(addHydrogens()));
      action->setShortcut(Qt::CTRL + Qt::Key_F);

      name = "Reperceive Bonds";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(reperceiveBonds()));

      menu->addSeparator();

      name = "Set Constraint";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(setConstraint()));
      action->setShortcut(Qt::CTRL + Qt::Key_K);

      name = "Minimize Structure";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(minimizeEnergy()));
      action->setShortcut(Qt::CTRL + Qt::Key_M);

      name = "Select Force Field";

      QActionGroup* forceFieldGroup = new QActionGroup(this);
      subMenu = menu->addMenu(name);

         QString ff("MMFF94");
         action = subMenu->addAction(ff);
         action->setCheckable(true);
         action->setData(ff);
         forceFieldGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setForceField()));
         if (Preferences::DefaultForceField() == ff) action->setChecked(true);

         ff = "MMFF94s";
         action = subMenu->addAction(ff);
         action->setCheckable(true);
         action->setData(ff);
         forceFieldGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setForceField()));
         if (Preferences::DefaultForceField() == ff) action->setChecked(true);

         ff = "UFF";
         action = subMenu->addAction(ff);
         action->setCheckable(true);
         action->setData(ff);
         forceFieldGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setForceField()));
         if (Preferences::DefaultForceField() == ff) action->setChecked(true);

         ff = "Ghemical";
         action = subMenu->addAction(ff);
         action->setCheckable(true);
         action->setData(ff);
         forceFieldGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setForceField()));
         if (Preferences::DefaultForceField() == ff) action->setChecked(true);

         ff = "Gaff";
         action = subMenu->addAction(ff);
         action->setCheckable(true);
         action->setData(ff);
         forceFieldGroup->addAction(action);
         connect(action, SIGNAL(triggered()), this, SLOT(setForceField()));
         if (Preferences::DefaultForceField() == ff) action->setChecked(true);

      menu->addSeparator();

      name = "Translate To Center";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(translateToCenter()));
      action->setShortcut(Qt::CTRL + Qt::Key_T );

      name = "Symmetrize Molecule";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(symmetrize()));
      action->setShortcut(Qt::CTRL + Qt::Key_Y );

      name = "Set Symmetry Tolerance";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(adjustSymmetryTolerance()));

      name = "Auto-detect Symmetry";
      action = menu->addAction(name);
      action->setCheckable(true);
      action->setChecked(false);
      connect(action, SIGNAL(triggered()), &m_viewerModel, SLOT(toggleAutoDetectSymmetry()));



   // ----- Calculation Menu -----
   menu = menuBar()->addMenu("Calculation");

      name = "Q-Chem Setup";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(openQChemUI()));
      action->setShortcut(Qt::CTRL + Qt::Key_U );
      m_qchemSetupAction = action;

      name = "Job Monitor";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(showProcessMonitor()));
      action->setShortcut(Qt::CTRL + Qt::Key_J );

      menu->addSeparator();

      name = "Edit Servers";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(editServers()));

      name = "Remove All Processes";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), 
         &(ProcessMonitor::instance()), SLOT(clearProcessList()));

      name = "Reset Password Vault Key";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(setVaultPassword()));



   // ----- Help Menu -----
   menu = menuBar()->addMenu("Help");

      name = "Show Help";
      action = menu->addAction(name);
      connect(action, SIGNAL(triggered()), this, SLOT(showHelp()));
}
Exemple #2
0
void KisDuplicateOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()) return;

    if (!m_duplicateStartIsSet) {
        m_duplicateStartIsSet = true;
        m_duplicateStart = info.pos();
    }

    bool heal = settings->healing();

    if (!source()) return;

    KisBrushSP brush = m_brush;
    if (!brush) return;
    if (! brush->canPaintFor(info))
        return;

    double scale = KisPaintOp::scaleForPressure(info.pressure());
    QPointF hotSpot = brush->hotSpot(scale, scale);
    QPointF pt = info.pos() - hotSpot;

    // Split the coordinates into integer plus fractional parts. The integer
    // is where the dab will be positioned and the fractional part determines
    // the sub-pixel positioning.
    qint32 x;
    double xFraction;
    qint32 y;
    double yFraction;

    splitCoordinate(pt.x(), &x, &xFraction);
    splitCoordinate(pt.y(), &y, &yFraction);
    xFraction = yFraction = 0.0;

    QPointF srcPointF = pt - settings->offset();
    QPoint srcPoint = QPoint(x - static_cast<qint32>(settings->offset().x()),
                             y - static_cast<qint32>(settings->offset().y()));


    qint32 sw = brush->maskWidth(scale, 0.0);
    qint32 sh = brush->maskHeight(scale, 0.0);

    if (srcPoint.x() < 0)
        srcPoint.setX(0);

    if (srcPoint.y() < 0)
        srcPoint.setY(0);
    if (!(m_srcdev && !(*m_srcdev->colorSpace() == *source()->colorSpace()))) {
        m_srcdev = new KisPaintDevice(source()->colorSpace());
    }
    Q_CHECK_PTR(m_srcdev);

    // Perspective correction ?
    KisPainter copyPainter(m_srcdev);
    KisImageSP image = settings->m_image;
    if (settings->perspectiveCorrection() && image && image->perspectiveGrid()->countSubGrids() == 1) {
        Matrix3qreal startM = Matrix3qreal::Identity();
        Matrix3qreal endM = Matrix3qreal::Identity();

        // First look for the grid corresponding to the start point
        KisSubPerspectiveGrid* subGridStart = *image->perspectiveGrid()->begin();
        QRect r = QRect(0, 0, image->width(), image->height());

#if 1
        if (subGridStart) {
            startM = KisPerspectiveMath::computeMatrixTransfoFromPerspective(r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight());
        }
#endif
#if 1
        // Second look for the grid corresponding to the end point
        KisSubPerspectiveGrid* subGridEnd = *image->perspectiveGrid()->begin();
        if (subGridEnd) {
            endM = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r);
        }
#endif

        // Compute the translation in the perspective transformation space:
        QPointF positionStartPaintingT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart));
        QPointF duplicateStartPositionT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart) - QPointF(settings->offset()));
        QPointF translat = duplicateStartPositionT - positionStartPaintingT;
        KisRectIteratorPixel dstIt = m_srcdev->createRectIterator(0, 0, sw, sh);
        KisRandomSubAccessorPixel srcAcc = source()->createRandomSubAccessor();
        //Action
        while (!dstIt.isDone()) {
            if (dstIt.isSelected()) {
                QPointF p =  KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt.x() + x, dstIt.y() + y)) + translat);
                srcAcc.moveTo(p);
                srcAcc.sampledOldRawData(dstIt.rawData());
            }
            ++dstIt;
        }


    } else {
        // Or, copy the source data on the temporary device:
        copyPainter.setCompositeOp(COMPOSITE_COPY);
        copyPainter.bitBlt(0, 0, source(), srcPoint.x(), srcPoint.y(), sw, sh);
        copyPainter.end();
    }

    // heal ?

    if (heal) {
        quint16 dataDevice[4];
        quint16 dataSrcDev[4];
        double* matrix = new double[ 3 * sw * sh ];
        // First divide
        const KoColorSpace* deviceCs = source()->colorSpace();
        KisHLineConstIteratorPixel deviceIt = source()->createHLineConstIterator(x, y, sw);
        KisHLineIteratorPixel srcDevIt = m_srcdev->createHLineIterator(0, 0, sw);
        double* matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; !srcDevIt.isDone(); i++) {
                deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1);
                deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1);
                // Division
                for (int k = 0; k < 3; k++) {
                    matrixIt[k] = dataDevice[k] / (double)qMax((int)dataSrcDev [k], 1);
                }
                ++deviceIt;
                ++srcDevIt;
                matrixIt += 3;
            }
            deviceIt.nextRow();
            srcDevIt.nextRow();
        }
        // Minimize energy
        {
            int iter = 0;
            double err;
            double* solution = new double [ 3 * sw * sh ];
            do {
                err = minimizeEnergy(&matrix[0], &solution[0], sw, sh);
                memcpy(&matrix[0], &solution[0], sw * sh * 3 * sizeof(double));
                iter++;
            } while (err < 0.00001 && iter < 100);
            delete [] solution;
        }

        // Finaly multiply
        deviceIt = source()->createHLineIterator(x, y, sw);
        srcDevIt = m_srcdev->createHLineIterator(0, 0, sw);
        matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; !srcDevIt.isDone(); i++) {
                deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1);
                deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1);
                // Multiplication
                for (int k = 0; k < 3; k++) {
                    dataSrcDev[k] = (int)CLAMP(matrixIt[k] * qMax((int) dataSrcDev[k], 1), 0, 65535);
                }
                deviceCs->fromLabA16((quint8*)dataSrcDev, srcDevIt.rawData(), 1);
                ++deviceIt;
                ++srcDevIt;
                matrixIt += 3;
            }
            deviceIt.nextRow();
            srcDevIt.nextRow();
        }
        delete [] matrix;
    }

    KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(m_srcdev->colorSpace());
    fixedDab->setRect(QRect(0, 0, sw, sh));
    fixedDab->initialize();

    m_srcdev->readBytes(fixedDab->data(), fixedDab->bounds());
    brush->mask(fixedDab, scale, scale, 0.0, info, xFraction, yFraction);
    m_srcdev->writeBytes(fixedDab->data(), fixedDab->bounds());

    QRect dabRect = QRect(0, 0, brush->maskWidth(scale, 0.0), brush->maskHeight(scale, 0.0));
    QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height());

    if (painter()->bounds().isValid()) {
        dstRect &= painter()->bounds();
    }

    if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return;

    qint32 sx = dstRect.x() - x;
    qint32 sy = dstRect.y() - y;
    sw = dstRect.width();
    sh = dstRect.height();

    painter()->bitBlt(dstRect.x(), dstRect.y(), m_srcdev, sx, sy, sw, sh);


}
Exemple #3
0
void MainWindow::createConnections()
{
   connect(&m_toolBar, SIGNAL(newMolecule()), 
      &m_viewerModel, SLOT(newMoleculeMenu()));

   connect(&m_toolBar, SIGNAL(open()), 
      this, SLOT(openFile()));

   connect(&m_toolBar, SIGNAL(save()), 
      &m_viewerModel, SLOT(saveAll()));

   connect(&m_toolBar, SIGNAL(addHydrogens()), 
      &m_viewerModel, SLOT(addHydrogens()));

   connect(&m_toolBar, SIGNAL(minimizeEnergy()), 
      &m_viewerModel, SLOT(minimizeEnergy()));

   connect(&m_toolBar, SIGNAL(deleteSelection()), 
      &m_viewerModel, SLOT(deleteSelection()));

   connect(&m_toolBar, SIGNAL(takeSnapshot()), 
      &m_viewer, SLOT(saveSnapshot()));

   connect(&m_toolBar, SIGNAL(record(bool)), 
      this, SLOT(setRecordingActive(bool)));
         
   connect(this, SIGNAL(recordingActive(bool)), 
      &m_toolBar, SLOT(setRecordAnimationButtonChecked(bool)));
         
   connect(this, SIGNAL(recordingActive(bool)), 
      &m_viewer, SLOT(setRecordingActive(bool)));

   connect(&m_viewer, SIGNAL(recordingCancelled()), 
      this, SLOT(recordingCancelled()));
         
   connect(&m_toolBar, SIGNAL(fullScreen()), 
      this, SLOT(fullScreen()));

   connect(&m_toolBar, SIGNAL(showHelp()), 
      this, SLOT(showHelp()));
         
   connect(&m_toolBar, SIGNAL(viewerModeChanged(Viewer::Mode const)), 
      &m_viewer, SLOT(setActiveViewerMode(Viewer::Mode const)));

   connect(&m_toolBar, SIGNAL(buildElementSelected(unsigned int)), 
      &m_viewer, SLOT(setDefaultBuildElement(unsigned int)));

   connect(&m_toolBar, 
      SIGNAL(buildFragmentSelected(QString const&, Viewer::Mode const)), 
      &m_viewer,
      SLOT(setDefaultBuildFragment(QString const&, Viewer::Mode const)));

   // ViewerModel 
   connect(&m_viewerModel, SIGNAL(updated()), 
      &m_viewer, SLOT(updateGL()));

   connect(&m_viewerView, SIGNAL(doubleClicked(QModelIndex const&)),
      &m_viewerModel, SLOT(itemDoubleClicked(QModelIndex const&))); 

   connect(&m_viewerView, SIGNAL(expanded(QModelIndex const&)),
      &m_viewerModel, SLOT(itemExpanded(QModelIndex const&))); 

   connect(&m_viewerModel, SIGNAL(sceneRadiusChanged(double const)), 
      &m_viewer, SLOT(setSceneRadius(double const)));

   connect(&m_viewerModel, SIGNAL(changeActiveViewerMode(Viewer::Mode const)), 
      &m_viewer, SLOT(setActiveViewerMode(Viewer::Mode const)));

   connect(&m_viewerModel, SIGNAL(displayMessage(QString const&)),
       &m_viewer, SLOT(displayMessage(QString const&)));

   connect(&m_viewerModel, SIGNAL(postCommand(QUndoCommand*)),
       this, SLOT(addCommand(QUndoCommand*)));

   connect(&m_viewerModel, SIGNAL(foregroundColorChanged(QColor const&)),
       &m_viewer, SLOT(setForegroundColor(QColor const&)));

   connect(&(ProcessMonitor::instance()), SIGNAL(resultsAvailable(JobInfo*)),
       &m_viewerModel, SLOT(openCalculationResults(JobInfo*)));

   // Viewer
   connect(&m_viewer, SIGNAL(enableUpdate(bool const)), 
      &m_viewerModel, SLOT(enableUpdate(bool const)));

   connect(&m_viewerModel, SIGNAL(pushAnimators(AnimatorList const&)),
      &m_viewer, SLOT(pushAnimators(AnimatorList const&)));

   connect(&m_viewerModel, SIGNAL(popAnimators(AnimatorList const&)),
      &m_viewer, SLOT(popAnimators(AnimatorList const&)));

   connect(&m_viewer, SIGNAL(postCommand(QUndoCommand*)),
      this, SLOT(addCommand(QUndoCommand*)));

   connect(&m_viewer, SIGNAL(openFileFromDrop(QString const&)),
      this, SLOT(openFile(QString const&)));

   connect(&m_viewer, SIGNAL(activeViewerModeChanged(Viewer::Mode const)),
      &m_toolBar, SLOT(setToolBarMode(Viewer::Mode const)));

   connect(&m_viewer, SIGNAL(escapeFullScreen()), 
      this, SLOT(fullScreen()));

   connect(&m_viewer, SIGNAL(animationStep()), 
      &m_viewerModel, SLOT(reperceiveBondsForAnimation()));

   // Selection
   connect(&m_viewerSelectionModel, 
      SIGNAL(selectionChanged(QItemSelection const&, QItemSelection const&)),
      &m_viewerModel, SLOT(selectionChanged(QItemSelection const&, QItemSelection const&)) );

   connect(&m_viewerModel, 
      SIGNAL(selectionChanged(QItemSelection const&, QItemSelectionModel::SelectionFlags)),
      &m_viewerSelectionModel, 
      SLOT(select(QItemSelection const&, QItemSelectionModel::SelectionFlags)) );

   connect(&m_viewerModel, SIGNAL(clearSelection()),
      &m_viewerSelectionModel, SLOT(clearSelection()));

   connect(&m_viewer, SIGNAL(clearSelection()),
      &m_viewerSelectionModel, SLOT(clearSelection()));

   connect(&m_viewer, 
      SIGNAL(select(QModelIndex const&, QItemSelectionModel::SelectionFlags)),
      &m_viewerSelectionModel, 
      SLOT(select(QModelIndex const&, QItemSelectionModel::SelectionFlags)));

   connect(&m_viewerModel, 
      SIGNAL(select(QModelIndex const&, QItemSelectionModel::SelectionFlags)),
      &m_viewerSelectionModel, 
      SLOT(select(QModelIndex const&, QItemSelectionModel::SelectionFlags)));
}
KisSpacingInformation KisDuplicateOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()->device()) return 1.0;

    KisBrushSP brush = m_brush;
    if (!brush)
        return 1.0;

    if (!brush->canPaintFor(info))
        return 1.0;

    if (!m_duplicateStartIsSet) {
        m_duplicateStartIsSet = true;
        m_duplicateStart = info.pos();
    }

    KisPaintDeviceSP realSourceDevice = settings->node()->paintDevice();

    qreal scale = m_sizeOption.apply(info);
    if (checkSizeTooSmall(scale)) return KisSpacingInformation();

    QPointF hotSpot = brush->hotSpot(scale, scale, 0, info);
    QPointF pt = info.pos() - hotSpot;

    setCurrentScale(scale);

    // Split the coordinates into integer plus fractional parts. The integer
    // is where the dab will be positioned and the fractional part determines
    // the sub-pixel positioning.
    qint32 x, y;
    qreal xFraction, yFraction; // will not be used
    splitCoordinate(pt.x(), &x, &xFraction);
    splitCoordinate(pt.y(), &y, &yFraction);

    QPoint srcPoint;

    if(m_moveSourcePoint)
    {
        srcPoint = QPoint(x - static_cast<qint32>(settings->offset().x()),
                          y - static_cast<qint32>(settings->offset().y()));
    } else {
        srcPoint = QPoint(static_cast<qint32>(settings->position().x() - hotSpot.x()),
                          static_cast<qint32>(settings->position().y() - hotSpot.y()));
    }

    qint32 sw = brush->maskWidth(scale, 0.0, xFraction, yFraction, info);
    qint32 sh = brush->maskHeight(scale, 0.0, xFraction, yFraction, info);

    if (srcPoint.x() < 0)
        srcPoint.setX(0);

    if (srcPoint.y() < 0)
        srcPoint.setY(0);

    // Perspective correction ?
    KisImageWSP image = settings->m_image;
    if (m_perspectiveCorrection && image && image->perspectiveGrid()->countSubGrids() == 1) {
        Matrix3qreal startM = Matrix3qreal::Identity();
        Matrix3qreal endM = Matrix3qreal::Identity();

        // First look for the grid corresponding to the start point
        KisSubPerspectiveGrid* subGridStart = *image->perspectiveGrid()->begin();
        QRect r = QRect(0, 0, image->width(), image->height());

#if 1
        if (subGridStart) {
            startM = KisPerspectiveMath::computeMatrixTransfoFromPerspective(r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight());
        }
#endif
#if 1
        // Second look for the grid corresponding to the end point
        KisSubPerspectiveGrid* subGridEnd = *image->perspectiveGrid()->begin();
        if (subGridEnd) {
            endM = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r);
        }
#endif

        // Compute the translation in the perspective transformation space:
        QPointF positionStartPaintingT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart));
        QPointF duplicateStartPositionT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart) - QPointF(settings->offset()));
        QPointF translat = duplicateStartPositionT - positionStartPaintingT;

        KisRectIteratorSP dstIt = m_srcdev->createRectIteratorNG(0, 0, sw, sh);
        KisRandomSubAccessorSP srcAcc = realSourceDevice->createRandomSubAccessor();
        //Action
        do {
            QPointF p =  KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt->x() + x, dstIt->y() + y)) + translat);
            srcAcc->moveTo(p);
            srcAcc->sampledOldRawData(dstIt->rawData());
        } while (dstIt->nextPixel());


    } else {
        KisPainter copyPainter(m_srcdev);
        copyPainter.setCompositeOp(COMPOSITE_COPY);
        copyPainter.bitBltOldData(0, 0, realSourceDevice, srcPoint.x(), srcPoint.y(), sw, sh);
        copyPainter.end();
    }

    // heal ?

    if (m_healing) {
        quint16 srcData[4];
        quint16 tmpData[4];
        qreal* matrix = new qreal[ 3 * sw * sh ];
        // First divide
        const KoColorSpace* srcCs = realSourceDevice->colorSpace();
        const KoColorSpace* tmpCs = m_srcdev->colorSpace();
        KisHLineConstIteratorSP srcIt = realSourceDevice->createHLineConstIteratorNG(x, y, sw);
        KisHLineIteratorSP tmpIt = m_srcdev->createHLineIteratorNG(0, 0, sw);
        qreal* matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; i < sw; i++) {
                srcCs->toLabA16(srcIt->oldRawData(), (quint8*)srcData, 1);
                tmpCs->toLabA16(tmpIt->rawData(), (quint8*)tmpData, 1);
                // Division
                for (int k = 0; k < 3; k++) {
                    matrixIt[k] = srcData[k] / (qreal)qMax((int)tmpData [k], 1);
                }
                srcIt->nextPixel();
                tmpIt->nextPixel();
                matrixIt += 3;
            }
            srcIt->nextRow();
            tmpIt->nextRow();
        }
        // Minimize energy
        {
            int iter = 0;
            qreal err;
            qreal* solution = new qreal [ 3 * sw * sh ];
            do {
                err = minimizeEnergy(&matrix[0], &solution[0], sw, sh);

                // swap pointers
                qreal *tmp = matrix;
                matrix = solution;
                solution = tmp;

                iter++;
            } while (err > 0.00001 && iter < 100);
            delete [] solution;
        }

        // Finaly multiply
        KisHLineIteratorSP srcIt2 = realSourceDevice->createHLineIteratorNG(x, y, sw);
        KisHLineIteratorSP tmpIt2 = m_srcdev->createHLineIteratorNG(0, 0, sw);
        matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; i < sw; i++) {
                srcCs->toLabA16(srcIt2->rawData(), (quint8*)srcData, 1);
                tmpCs->toLabA16(tmpIt2->rawData(), (quint8*)tmpData, 1);
                // Multiplication
                for (int k = 0; k < 3; k++) {
                    tmpData[k] = (int)CLAMP(matrixIt[k] * qMax((int) tmpData[k], 1), 0, 65535);
                }
                tmpCs->fromLabA16((quint8*)tmpData, tmpIt2->rawData(), 1);
                srcIt2->nextPixel();
                tmpIt2->nextPixel();
                matrixIt += 3;
            }
            srcIt2->nextRow();
            tmpIt2->nextRow();
        }
        delete [] matrix;
    }

    static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
    static KoColor color(Qt::black, cs);

    KisFixedPaintDeviceSP dab =
        m_dabCache->fetchDab(cs, color, scale, scale,
                             0.0, info);

    QRect dstRect = QRect(x, y, dab->bounds().width(), dab->bounds().height());
    if (dstRect.isEmpty()) return 1.0;

    painter()->bitBltWithFixedSelection(dstRect.x(), dstRect.y(),
                                        m_srcdev, dab,
                                        dstRect.width(),
                                        dstRect.height());

    painter()->renderMirrorMaskSafe(dstRect, m_srcdev, 0, 0, dab,
                                    !m_dabCache->needSeparateOriginal());

    return effectiveSpacing(dstRect.width(), dstRect.height());
}