//! \file clippingstation.cpp /************************************************************************ * $Id: clippingstation.cpp 668 2011-05-15 11:08:10Z elzubeir $ * * ------------ * Description: * ------------ * * (C) Copyright 2009-2011 ALLCONTENT. All rights reserved. * * ----------------- * Revision Details: (Updated by Revision Control System) * ----------------- * $Date: 2011-05-15 15:08:10 +0400 (Sun, 15 May 2011) $ * $Author: elzubeir $ * $Revision: 668 $ * $HeadURL: file:///opt/svn/socialhose/trunk/app/ClippingStation/clippingstation.cpp $ * * ************************************************************************/ #include #include #include #include #include #include #include using namespace std; #include "clippingstation.h" #include "ui_clippingstation.h" #include "Importer/importerdialog.h" #include "publication.h" #include "tag.h" #include "pushbuttondelegate.h" #include "tagswrapper.h" #include "imagecutout.h" #include "drawerview.h" #include "systemconfiguration.h" #include "constants.h" #include "pagetextdialog.h" #include "wordcoordinates.h" #include "searchpublicationlistdialog.h" /* TODO: if caching has been canceled by user, or by selecting a different issue while the first one has not completed caching yet! It should be handled, not handled yet! */ QMutex g_clipMutex; QString ClippingStation::m_cacheDir; QString ClippingStation::m_address; QString ClippingStation::m_username; QString ClippingStation::m_password; int ClippingStation::m_port; QString ClippingStation::saveClipImagesToFtpServerErrorMsg; QImage ClippingStation::m_thumbnail; QSqlDatabase ClippingStation::m_ocrDatabase; QSqlDatabase ClippingStation::m_clipDatabase; ClippingStation::ClippingStation(QWidget *parent) : QMainWindow(parent), ui(new Ui::ClippingStation), m_imageCachingDialog(this, m_cachedImages) { if ( !readSettings()) //if you cant read settings, exit exit(0); if( !connectToDatabase() ) //if cant connect to database, exit exit(0); if ( !authenticate() ) //if cant authenticate, exit exit(0); ui->setupUi(this); //else, create the UI if( m_debug.compare("on", Qt::CaseInsensitive) == 0 ) { g_logfile.open("clippingstation.log", ios::app); g_logfile << std::string(80, '=') << std::endl; g_debug = true; } else g_debug = false; //create the actions createActions(); if( m_preclip.compare("on", Qt::CaseInsensitive) == 0 ) { m_preclipContextMenu = new QMenu(this); m_preclipContextMenu->addAction(ui->actionModifyPreclip); m_preclipContextMenu->addSeparator(); m_preclipContextMenu->addAction(ui->actionDeletePreclip); } else { ui->preclipButton->setEnabled(false); ui->cancelModifyPreclipButton->setEnabled(false); } m_clipContextMenu = new QMenu(this); m_clipContextMenu->addAction(ui->actionViewClipText); m_issueContextMenu = new QMenu(this); m_issueContextMenu->addAction(ui->actionSendIssuetoORC); m_issuePageContextMenu = new QMenu(this); m_issuePageContextMenu->addAction(ui->actionSendPagetoORC); m_issuePageContextMenu->addSeparator(); m_issuePageContextMenu->addAction(ui->actionViewPageText); m_keywordsContextMenu = new QMenu(this); m_keywordsContextMenu->addAction(ui->actionViewKeywordsSearchword); m_keywordsContextMenu->addSeparator(); m_keywordsContextMenu->addAction(ui->actionGoToKeywordWikiPage); m_publication.setDatabase(m_masterDatabase); m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); //populate all the publications in the publicaiton/issue drop-down list in the dock widget QStringList list; QSqlQuery query("SELECT id_publication, name_publication_en FROM publication", m_slaveDatabase); while( query.next() ) { int publicationId = query.value(0).toString().toInt(); QString publicationName = query.value(1).toString(); list << publicationName; //populate list with values from the database m_publicationHash[publicationName] = publicationId; //also populate the hash table with name/id values } //load keywords from database and add them to searchPublicationdialog QStringList keywords; query.exec( "SELECT name_company FROM company WHERE date_end > NOW()" ); while( query.next() ) { QString name = query.value(0).toString(); keywords.append(name); } query.exec("SELECT name_searchword FROM company AS cm, searchword AS sw WHERE sw.id_company = cm.id_company AND cm.date_end > NOW() "); while( query.next() ) { QString name = query.value(0).toString(); keywords.append(name); } keywords.sort(); keywords.removeDuplicates(); m_searchPublicationsDlg.setKeywords(keywords); query.exec("SELECT id_country, name_country_en FROM country"); while( query.next() ) { int id = query.value(0).toString().toInt(); QString name = query.value(1).toString(); m_countriesHash[name] = id; //also populate the hash table with name/id values } QList clist = m_countriesHash.keys(); QStringList strlist; for(int i=0; i < clist.count(); i++) strlist.append(clist[i]); m_searchPublicationsDlg.setCountryList( strlist ); QCompleter* completer = new QCompleter(list, this); //createa completer with the list of publication names completer->setCaseSensitivity(Qt::CaseInsensitive); ui->publicationNameLineEdit_2->setCompleter(completer); //use the complete with the publicationLineEdit // should use QDir's homePath to get the path and then use .socialhose/cache as the directory within the homePath QDir homeDir("/home"); #if defined Q_WS_X11 m_cacheDir = homeDir.homePath() + "/.socialhose/cache/"; #elif defined Q_WS_MACX m_cacheDir = homeDir.homePath() + "/.socialhose/cache/"; #else m_cacheDir = QApplication::applicationDirPath(); if(!m_cacheDir.endsWith("/")) m_cacheDir += "/"; m_cacheDir += "cache/"; #endif ui->fullpageView->setClippingStation(this); ui->statusBar->addProgressBarWidget(&m_imageCachingDialog); ImporterDialog *dlg = new ImporterDialog(this, m_masterDatabase, m_slaveDatabase, m_user); //create the importer dialog ui->importerDockWidget->setWidget(dlg); //and insert it to the importer dock widget tabifyDockWidget(ui->importerDockWidget, ui->publicatonIssueDockWidget); ui->importerDockWidget ->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); ui->publicatonIssueDockWidget ->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); ui->importerDockWidget ->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); //ui->importerDockWidget->raise(); SystemConfiguration::retreiveSystemConfiguration(m_slaveDatabase); m_tagsWrapper.set(ui->treeView, ui->treeWidget, ui->keywordLineEdit); ui->stackedDrawerViewWidget->removeWidget(ui->stackedDrawerViewWidget->widget(0) ); //remove the first page from the stak m_currentA4Scale = 1.0; drawerAddPage(true); m_runningMode = NORMAL_MODE; m_filterMode = NO_FILTER; m_currentPreclipId = 0; m_firstPageInClip = ""; //reset it m_imageIndex = m_preclippedImageIndex = m_clippedImageIndex = 0; m_imageModelIndex = m_preclippedImageModelIndex = m_clippedImageModelIndex = QModelIndex(); showMaximized(); ui->cancelModifyPreclipButton->setVisible(false); //install filter to track mouse ui->fullpageView->installEventFilter(this); connect(&m_saveClipImagesToFtpServerWatcher, SIGNAL(finished() ), this, SLOT( saveClipImagesToFtpServerWatcherFinished() ) ); //this signal is used to upload clips to ftp server connect(&m_saveClipImagesToFileServerWatcher, SIGNAL(finished() ), this, SLOT( saveClipImagesToFileServerWatcherFinished() ) ); //this signal is used to upload clips to ftp server connect(&m_addTextToClipWatcher, SIGNAL(finished()), this, SLOT(addTextToClipWatcherFinished())); //set shortcuts setShortcuts(); connect(&m_trackingTimer, SIGNAL(timeout()), this, SLOT(updateTrackLabel())); m_trackingTimer.setInterval(1000); m_trackingSeconds = 0; m_currentPageId = 0; m_isPaused = false; } ClippingStation::~ClippingStation() { //qDebug("~ClippingStation()"); delete ui; unlockImages(); m_trackingTimer.stop(); if(m_currentPageId > 0 && m_trackingSeconds > 0) m_user.updateTrack(m_currentPageId, m_trackingSeconds); m_masterDatabase.close(); m_slaveDatabase.close(); //delete all the files on the tmp directory //QDir dir(m_cacheDir); //recursiveDelete( dir ); //qDebug("end of ~ClippingStation()"); } bool ClippingStation::readSettings() { #ifdef Q_WS_X11 QString config = "/etc/socialhose.ini"; #elif defined (Q_WS_MACX) QString config = "/etc/socialhose.ini"; #else QString config = QApplication::applicationDirPath()+ "/config.ini"; #endif QSettings settings(config, QSettings::IniFormat); m_masterDatabaseHost = settings.value("master database/server").toString(); //read master database's server value from settings m_masterDatabaseName = settings.value("master database/database").toString(); //read master database's database name value from settings m_masterDatabaseUser = settings.value("master database/uid").toString(); //read master database's user id value from settings m_masterDatabasePassword = settings.value("master database/pwd").toString(); //read master database's password value from settings m_masterDatabasePort = settings.value("master database/port").toInt(); //read master database's port value from settings // if any string is empty return false, else return true if(m_masterDatabaseName.isEmpty() || m_masterDatabaseHost.isEmpty() || m_masterDatabaseUser.isEmpty() || m_masterDatabasePassword.isEmpty() || ( m_masterDatabasePort == 0) ) { QMessageBox::critical(this, tr("config error"), tr("Error reading 'config.ini' master database configurations\nMake sure the file exists, and its properly formatted!")); return false; } m_slaveDatabaseHost = settings.value("slave database/server").toString(); m_slaveDatabaseName = settings.value("slave database/database").toString(); m_slaveDatabaseUser = settings.value("slave database/uid").toString(); m_slaveDatabasePassword = settings.value("slave database/pwd").toString(); m_slaveDatabasePort = settings.value("slave database/port").toInt(); // if any string is empty return false, else return true if(m_slaveDatabaseName.isEmpty() || m_slaveDatabaseHost.isEmpty() || m_slaveDatabaseUser.isEmpty() || m_slaveDatabasePassword.isEmpty() || ( m_slaveDatabasePort == 0) ) { QMessageBox::critical(this, tr("config error"), tr("Error reading 'config.ini' slave database configurations\nMake sure the file exists, and its properly formatted!")); return false; } m_ocrDatabaseHost = settings.value("ocr database/server").toString(); m_ocrDatabaseName = settings.value("ocr database/database").toString(); m_ocrDatabaseUser = settings.value("ocr database/uid").toString(); m_ocrDatabasePassword = settings.value("ocr database/pwd").toString(); m_ocrDatabasePort = settings.value("ocr database/port").toInt(); m_useFtp = settings.value("ftp access/useftp").toInt(); //if its set to 0, its false, otherwise it true if(m_useFtp) { m_address = settings.value("ftp access/server").toString(); m_username = settings.value("ftp access/username").toString(); m_password = settings.value("ftp access/password").toString(); m_port = settings.value("ftp access/port").toInt(); if(m_address.isEmpty() || m_username.isEmpty() || m_password.isEmpty() || (m_port == 0)) { QMessageBox::critical(this, tr("config error"), tr("Error reading 'config.ini' Ftp server configurations\nMake sure the file is properly formatted!")); return false; } } //read shortcuts m_clipShortcut = settings.value("shortcuts/Clip").toString(); m_preclipShortcut = settings.value("shortcuts/Preclip").toString(); m_addPageShortcut = settings.value("shortcuts/AddPage").toString(); m_nextPageShortcut = settings.value("shortcuts/NextPage").toString(); m_previousPageShortcut = settings.value("shortcuts/PreviousPage").toString(); m_debug = settings.value("debug mode/debug").toString(); m_preclip = settings.value("preclip mode/preclip", "on").toString(); m_maxTimeLimit = settings.value("time limit/limit").toInt(); return true; } bool ClippingStation::connectToDatabase() { // add a connection to databse based on the mysql driver, and name it master m_masterDatabase = QSqlDatabase::addDatabase("QMYSQL", "master_123"); // initalize the connection m_masterDatabase.setHostName(m_masterDatabaseHost); m_masterDatabase.setPort(m_masterDatabasePort); m_masterDatabase.setDatabaseName(m_masterDatabaseName); m_masterDatabase.setUserName(m_masterDatabaseUser); m_masterDatabase.setPassword(m_masterDatabasePassword); // try to open the connection, if ok returns true, else returns false bool ok = m_masterDatabase.open(); if(!ok) { // if error, get the error from the database text and print it to debug screen QString str = m_masterDatabase.lastError().databaseText(); QMessageBox::critical(this, tr("Database Error"), tr("Error connecting to master database\n") + str); return false; } // add a connection to databse based on the mysql driver, and name it slave m_slaveDatabase = QSqlDatabase::addDatabase("QMYSQL", "slave"); // initalize the connection m_slaveDatabase.setHostName(m_slaveDatabaseHost); m_slaveDatabase.setPort(m_slaveDatabasePort); m_slaveDatabase.setDatabaseName(m_slaveDatabaseName); m_slaveDatabase.setUserName(m_slaveDatabaseUser); m_slaveDatabase.setPassword(m_slaveDatabasePassword); // try to open the connection, if ok returns true, else returns false ok = m_slaveDatabase.open(); if(!ok) { // if error, get the error from the database text and print it to debug screen QString str = m_slaveDatabase.lastError().databaseText(); QMessageBox::critical(this, tr("Database Error"), tr("Error connecting to slave database\n") + str); return false; } m_ocrDatabase = QSqlDatabase::addDatabase("QMYSQL", "ocr"); // initalize the connection m_ocrDatabase.setHostName(m_ocrDatabaseHost); m_ocrDatabase.setPort(m_ocrDatabasePort); m_ocrDatabase.setDatabaseName(m_ocrDatabaseName); m_ocrDatabase.setUserName(m_ocrDatabaseUser); m_ocrDatabase.setPassword(m_ocrDatabasePassword); // try to open the connection, if ok returns true, else returns false ok = m_ocrDatabase.open(); if(!ok) { // if error, get the error from the database text and print it to debug screen QString str = m_ocrDatabase.lastError().databaseText(); QMessageBox::critical(this, tr("Database Error"), tr("Error connecting to ocr database\n") + str); return false; } m_clipDatabase = m_masterDatabase.cloneDatabase(m_masterDatabase, "clip"); m_clipDatabase.open(); if(!m_clipDatabase.isOpen()) { QString str = m_clipDatabase.lastError().text(); QMessageBox::critical(this, tr("Database Error"), tr("Error opening clip database\n") + str); return false; } return true; } bool ClippingStation::authenticate() { //after opening the database connection, we pass it to the user object m_user.setSlaveDatabase(m_slaveDatabase); m_user.setMasterDatabase(m_masterDatabase); return m_user.authenticate(); } void ClippingStation::createActions() { //create actions for the main window connect(ui->actionImporter, SIGNAL(triggered()), this, SLOT(onActionImporter())); connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close())); connect(ui->actionKeyword, SIGNAL(triggered()), this, SLOT(onActionKeyword())); connect(ui->actionPublications, SIGNAL(triggered()), this, SLOT(onActionPublications())); connect(ui->actionClip, SIGNAL(triggered()), this, SLOT(onActionClip())); if( m_preclip.compare("on", Qt::CaseInsensitive) == 0 ) { connect(ui->actionPreclip, SIGNAL(triggered()), this, SLOT(onActionPreclip())); connect(ui->actionModifyPreclip, SIGNAL(triggered()), this, SLOT(onActionModifyePreclip())); connect(ui->actionDeletePreclip, SIGNAL(triggered()), this, SLOT(onActionDeletePreclip())); } //drawer actions connect(ui->actionDrawerAddPage, SIGNAL(triggered()), this, SLOT(drawerAddPage())); connect(ui->actionDrawerRemovePage, SIGNAL(triggered()), this, SLOT(drawerRemovePage())); //page navigation actions connect(ui->actionFirstPage, SIGNAL(triggered()), this, SLOT(firstPage())); connect(ui->actionPreviousPage, SIGNAL(triggered()), this, SLOT(previousPage())); connect(ui->actionNextPage, SIGNAL(triggered()), this, SLOT(nextPage())); connect(ui->actionLastPage, SIGNAL(triggered()), this, SLOT(lastPage())); //zoom in/out connect(ui->actionZoomIn, SIGNAL(triggered()), this, SLOT(zoomIn())); connect(ui->actionZoomOut, SIGNAL(triggered()), this, SLOT(zoomOut())); //auto-arrange connect(ui->actionAutoArrange, SIGNAL(triggered()), this, SLOT(onActionAutoArrange())); connect(ui->actionMarkIssueAsDone, SIGNAL(triggered()), this, SLOT(onActionMarkIssueAsDone())); connect(ui->actionMarkIssueAsUndone,SIGNAL(triggered()), this, SLOT(onActionMarkIssueAsUndone())); connect(ui->actionSendIssuetoORC, SIGNAL(triggered()), this, SLOT(onActionSendIssueToOCR())); connect(ui->actionSendPagetoORC, SIGNAL(triggered()), this, SLOT(onActionSendPageToOCR())); connect(ui->actionViewPageText, SIGNAL(triggered()), this, SLOT(onActionViewPageText())); connect(ui->actionViewClipText, SIGNAL(triggered()), this, SLOT(onActionViewClipText())); connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(onActionAbout())); connect(ui->actionViewKeywordsSearchword, SIGNAL(triggered()), this, SLOT(onActionViewKeywordsSearchword())); connect(ui->actionGoToKeywordWikiPage , SIGNAL(triggered()), this, SLOT(onActionGoToKeywordWikiPage())); } void ClippingStation::onActionImporter() { ui->importerDockWidget->setVisible(ui->actionImporter->isChecked()); } void ClippingStation::onActionKeyword() { ui->keywordDockWidget->setVisible(ui->actionKeyword->isChecked()); } void ClippingStation::onActionPublications() { ui->publicatonIssueDockWidget->setVisible(ui->actionPublications->isChecked()); } void ClippingStation::onActionClip() { clip(); } void ClippingStation::onActionPreclip() { preclip(); } void ClippingStation::onActionModifyePreclip() { QModelIndexList list = ui->clipsTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; articleTreeViewClicked(index); setModifyPreclipButton(true); } void ClippingStation::onActionDeletePreclip() { QModelIndexList list = ui->clipsTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; if(index.isValid()) { //check index to the value QAbstractItemModel *model = ui->clipsTreeView->model(); QModelIndex preclipRootIndex = model->index(0, 0, QModelIndex() ); QModelIndex clipRootIndex = model->index(1, 0, QModelIndex() ); //if the user clicked on top level entries, just return if ( index == preclipRootIndex || index == clipRootIndex ) return; int id; if ( index.parent() == preclipRootIndex || index.parent().parent() == preclipRootIndex ) { m_runningMode = PRECLIPPING_MODE; QModelIndex currentIndex; m_clippedImageModelIndex = QModelIndex(); //if the selection is the Preclip(), then it will contain the id if(index.parent() == preclipRootIndex) id = model->index(index.row(), 1, index.parent() ).data(Qt::DisplayRole).toInt(); else id = model->index(index.parent().row(), 1, index.parent().parent() ).data(Qt::DisplayRole).toInt(); switch( QMessageBox::question( this, tr("Delete Preclip"), tr("This will delete the preclip PERMANENTLY, Are you sure?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ) { case QMessageBox::Yes: break; case QMessageBox::No: return; default: return; } m_publication.currentIssue()->preclip(id).deleteArticle(m_masterDatabase); m_publication.currentIssue()->deleteArticleFromView(ui->clipsTreeView, id); m_publication.addImageCutoutsToIssues(ui->issuesTreeView, false); //m_publication.currentIssue()->loadArticles(m_slaveDatabase, m_filterMode); //m_publication.currentIssue()->showArticles(ui->clipsTreeView); } } } void ClippingStation::onActionAutoArrange() { QList cutouts = ui->fullpageView->imageCutoutsList(); if(cutouts.count() <= 0) return; orderList(cutouts); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->currentWidget() ); QSizeF cellSize = A4CellSize(true); bool isfirstPage = true; bool resetArray = true; for(int i=0; i< cutouts.count(); i++) { QString currentImage; if(m_runningMode == NORMAL_MODE) currentImage = m_localImagesList[m_imageIndex]; else if(m_runningMode == PRECLIPPING_MODE) currentImage = m_preclippedLocalImagesList[m_preclippedImageIndex]; else if(m_runningMode == CLIPPING_MODE) currentImage = m_clippedLocalImagesList[m_clippedImageIndex]; if(cutouts[i]->pageName() != currentImage) { if(m_runningMode == NORMAL_MODE) { int index = m_localImagesList.indexOf(cutouts[i]->pageName()); if(index < 0) return; m_imageIndex = index; } else if(m_runningMode == PRECLIPPING_MODE) { int index = m_preclippedLocalImagesList.indexOf(cutouts[i]->pageName()); if(index < 0) return; m_preclippedImageIndex = index; } else if(m_runningMode == CLIPPING_MODE) { int index = m_clippedLocalImagesList.indexOf(cutouts[i]->pageName()); if(index < 0) return; m_clippedImageIndex = index; } loadImage(); } QImage img = cutouts[i]->createCutout(); int type = cutouts[i]->areaType(); QPointF pos; qreal scale = 1.0; if(calculatePosAndScale(cellSize, img, type, resetArray, pos, scale)) { addMargintoPos(pos, isfirstPage); view->addCutout(img, pos, scale); } else { isfirstPage = false; drawerAddPage(isfirstPage); drawerNextPage(); view = static_cast(ui->stackedDrawerViewWidget->currentWidget() ); cellSize = A4CellSize(isfirstPage); if(calculatePosAndScale(cellSize, img, type, true, pos, scale)) { addMargintoPos(pos, isfirstPage); view->addCutout(img, pos, scale); } else { //error, the cutout is larger than the avaialble space in the A4 page ui->stackedDrawerViewWidget->removeWidget( ui->stackedDrawerViewWidget->currentWidget() ); updateDrawerPageInformation(); QMessageBox::information(this, tr("Large Cutout"), tr("Cutout number %1 does not fit in the available space").arg(i+1)); return; } } resetArray = false; } //iterate thru all the views, and center the images for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { ui->stackedDrawerViewWidget->setCurrentIndex(i); view = static_cast(ui->stackedDrawerViewWidget->widget(i)); bool isArabic = (m_publication.language() == "Arabic"); view->centerCutouts(isArabic); } //return to the first page to create the thumbnail QString currentImage; if(m_runningMode == NORMAL_MODE) currentImage = m_localImagesList[m_imageIndex]; else if(m_runningMode == PRECLIPPING_MODE) currentImage = m_preclippedLocalImagesList[m_preclippedImageIndex]; else if(m_runningMode == CLIPPING_MODE) currentImage = m_clippedLocalImagesList[m_clippedImageIndex]; if(cutouts[0]->pageName() != currentImage) { if(m_runningMode == NORMAL_MODE) { int index = m_localImagesList.indexOf(cutouts[0]->pageName()); if(index < 0) return; m_imageIndex = index; } else if(m_runningMode == PRECLIPPING_MODE) { int index = m_preclippedLocalImagesList.indexOf(cutouts[0]->pageName()); if(index < 0) return; m_preclippedImageIndex = index; } else if(m_runningMode == CLIPPING_MODE) { int index = m_clippedLocalImagesList.indexOf(cutouts[0]->pageName()); if(index < 0) return; m_clippedImageIndex = index; } loadImage(); } createThumbnail(); } void ClippingStation::onActionMarkIssueAsDone() { QModelIndexList list = ui->issuesTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; //QString date = if( !index.isValid() ) return; switch( QMessageBox::question( this, tr("Mark Issue as Done"), tr("This will mark the current issue as Done\nAre you sure?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ) { case QMessageBox::Yes: break; case QMessageBox::No: return; default: return; } QAbstractItemModel *model = ui->issuesTreeView->model(); if(model->parent(index) == QModelIndex() ) index = index; else if(model->parent(index).parent() == QModelIndex() ) index = index.parent(); else if(model->parent(index).parent().parent() == QModelIndex() ) index = index.parent().parent(); else index = index.parent().parent().parent(); QString date = model->data(index, Qt::DisplayRole).toString(); m_publication.issue(date)->markIssueAsDone(m_masterDatabase, true, m_user.id()); model->setData(index, QVariant(QIcon(":/icons/ok.png")) , Qt::DecorationRole); } void ClippingStation::onActionMarkIssueAsUndone() { QModelIndexList list = ui->issuesTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; //QString date = if( !index.isValid() ) return; switch( QMessageBox::question( this, tr("Mark Issue as Undone"), tr("This will mark the current issue as Undone\nAre you sure?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ) { case QMessageBox::Yes: break; case QMessageBox::No: return; default: return; } QAbstractItemModel *model = ui->issuesTreeView->model(); if(model->parent(index) == QModelIndex() ) index = index; else if(model->parent(index).parent() == QModelIndex() ) index = index.parent(); else if(model->parent(index).parent().parent() == QModelIndex() ) index = index.parent().parent(); else index = index.parent().parent().parent(); QString date = model->data(index, Qt::DisplayRole).toString(); m_publication.issue(date)->markIssueAsDone(m_masterDatabase, false, m_user.id()); model->setData(index, QVariant(QIcon(":/icons/cancel.png")) , Qt::DecorationRole); } void ClippingStation::onActionSendPageToOCR() { QAbstractItemModel *model = ui->issuesTreeView->model(); QModelIndexList list = ui->issuesTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; QString pageName = index .data(Qt::DisplayRole).toString(); //convert pageName from Page # to ####.jpg pageName = QString("%1.jpg").arg(pageName.remove(QRegularExpression("[^\\d]")), 4, QChar('0')); QString sectionName = model->parent(index) .data(Qt::DisplayRole).toString(); QString issueDate = model->parent(index).parent().data(Qt::DisplayRole).toString(); //send the page to OCR to be processed again QSqlQuery query(m_slaveDatabase); query.prepare("SELECT id_publication_issue FROM publication_issue " "WHERE id_publication = :id_publication AND id_issue = :id_issue AND issue_date = :issue_date"); query.bindValue(":id_publication", m_publication.id() ); query.bindValue(":id_issue", m_publication.issue(issueDate)->id() ); query.bindValue(":issue_date", issueDate); if(!query.exec()) { //error happened return; } int id_publication_issue = 0; if(query.next()) { id_publication_issue = query.value(0).toInt(); //return id_publication_issue; //break; } query.prepare("SELECT id_issue_sections FROM issue_sections WHERE " "id_publication_issue = :id_publication_issue AND id_section = :id_section"); query.bindValue(":id_publication_issue", id_publication_issue); query.bindValue(":id_section", m_publication.issue(issueDate)->section(sectionName).id() ); if ( !query.exec() ) return; int id_issue_sections = 0; if( query.next() ) { id_issue_sections = query.value(0).toInt(); //break; } //we have the page name, and the id_issue_sections, we can now reset the pages to OCR //query.exec("LOCK TABLES section_pages WRITE, page_text WRITE, page_tag_coordinates WRITE;"); //query.exec("LOCK TABLES section_pages"); //first remove the pre processed values query.prepare("SELECT section_pages FROM section_pages " "WHERE " " id_issue_sections = :id_issue_sections " " AND page_name like :page_name"); query.bindValue(":id_issue_sections" , id_issue_sections); query.bindValue(":page_name", pageName); if (query.exec() ) { int id = 0; if(query.next()) id = query.value(0).toInt(); //delete the previous coordinates query.prepare("DELETE FROM page_tag_coordinates WHERE id_section_pages = :id"); query.bindValue(":id", id); query.exec(); query.prepare("DELETE FROM page_text WHERE id_section_pages = :id"); query.bindValue(":id", id); query.exec(); } query.prepare("UPDATE section_pages SET status = 1 " "WHERE " " section_pages.id_issue_sections = :id_issue_sections " " AND section_pages.page_name like :page_name AND status != 1"); query.bindValue(":id_issue_sections" , id_issue_sections); query.bindValue(":page_name", pageName); query.exec(); //query.exec("UNLOCK TABLES"); model->setData(index, QVariant(QIcon(":/icons/gray_circle.png")) , Qt::DecorationRole); //loadImage(); //no need to re-load the page because it may not by the page that the user is currently looking at } void ClippingStation::onActionSendIssueToOCR() { switch( QMessageBox::question( this, tr("Send issue back to OCR"), tr("This operation will send the entire issue back to OCR\nAre you sure?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ) { case QMessageBox::Yes: break; case QMessageBox::No: return; default: return; } QAbstractItemModel *model = ui->issuesTreeView->model(); QModelIndexList list = ui->issuesTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex issueIndex = list[0]; QString issueDate = model->data(issueIndex, Qt::DisplayRole).toString(); //send the entire issue to OCR to be processed again QSqlQuery query(m_slaveDatabase); query.exec("LOCK TABLES section_pages WRITE, issue_sections READ , publication_issue READ;"); //first remove the pre processed values query.prepare("UPDATE section_pages, issue_sections, publication_issue " " SET status = 1 " " WHERE section_pages.id_issue_sections = issue_sections.id_issue_sections " " AND issue_sections.id_publication_issue = publication_issue.id_publication_issue " " AND id_issue = :id_issue AND publication_issue.id_publication = :id_publication;"); query.bindValue(":id_issue" , m_publication.issue(issueDate)->id() ); query.bindValue(":id_publication", m_publication.id() ); if ( !query.exec() ) { query.exec("UNLOCK TABLES"); return; } query.exec("UNLOCK TABLES"); ////////////////////////////////////////////////////////////// int sectionsCount = model->rowCount(issueIndex); for(int j=0; j < sectionsCount; j++) { QString sectionName = model->index(j, 0, issueIndex).data(Qt::DisplayRole).toString(); QModelIndex sectionIndex = model->index(j, 0, issueIndex); int pagesCount = model->rowCount(sectionIndex); for(int k=0; k< pagesCount; k++) { QModelIndex pageIndex = model->index(k, 0, sectionIndex); model->setData(pageIndex, QVariant(QIcon(":/icons/gray_circle.png")) , Qt::DecorationRole); } } } void ClippingStation::onActionViewClipText() { QAbstractItemModel *model = ui->clipsTreeView->model(); QModelIndexList list = ui->clipsTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; QModelIndex clipRootIndex = model->index(1, 0, QModelIndex() ); //if the user clicked on top level entries, just return int id; if ( index.parent() == clipRootIndex || index.parent().parent() == clipRootIndex ) { //m_clippedImageModelIndex = QModelIndex(); if(index.parent() == clipRootIndex) id = model->index(index.row(), 1, index.parent() ).data(Qt::DisplayRole).toInt(); else id = model->index(index.parent().row(), 1, index.parent().parent() ).data(Qt::DisplayRole).toInt(); //get the text_ocr. QSqlQuery query(m_masterDatabase); query.prepare("SELECT `text_ocr` FROM article WHERE id_article = :id"); query.bindValue(":id", id); if ( !query.exec() ) return; QString text; while(query.next()) text = query.value(0).toString(); PageTextDialog dlg(this, text); dlg.exec(); } } void ClippingStation::onActionViewPageText() { QAbstractItemModel *model = ui->issuesTreeView->model(); QModelIndexList list = ui->issuesTreeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; QString pageName = index .data(Qt::DisplayRole).toString(); pageName = QString("%1.jpg").arg(pageName.remove(QRegularExpression("[^\\d]")), 4, QChar('0')); QString sectionName = model->parent(index) .data(Qt::DisplayRole).toString(); QString issueDate = model->parent(index).parent().data(Qt::DisplayRole).toString(); QSqlQuery query(m_slaveDatabase); query.prepare("SELECT id_publication_issue FROM publication_issue " "WHERE id_publication = :id_publication AND id_issue = :id_issue AND issue_date = :issue_date"); query.bindValue(":id_publication", m_publication.id() ); query.bindValue(":id_issue", m_publication.issue(issueDate)->id() ); query.bindValue(":issue_date", issueDate); if(!query.exec()) { //error happened return; } int id_publication_issue = 0; if(query.next()) id_publication_issue = query.value(0).toInt(); query.prepare("SELECT id_issue_sections FROM issue_sections WHERE " "id_publication_issue = :id_publication_issue AND id_section = :id_section"); query.bindValue(":id_publication_issue", id_publication_issue); query.bindValue(":id_section", m_publication.issue(issueDate)->section(sectionName).id() ); if ( !query.exec() ) return; int id_issue_sections = 0; if( query.next() ) id_issue_sections = query.value(0).toInt(); query.exec("LOCK TABLES section_pages READ"); query.prepare("SELECT section_pages FROM section_pages " "WHERE " " section_pages.id_issue_sections = :id_issue_sections " " AND section_pages.page_name like :page_name"); query.bindValue(":id_issue_sections" , id_issue_sections); query.bindValue(":page_name", pageName); if ( !query.exec() ) { query.exec("UNLOCK TABLES"); return; } int id = 0; while(query.next()) id = query.value(0).toInt(); query.exec("UNLOCK TABLES"); query.prepare("SELECT `text` FROM page_text WHERE id_section_pages = :id"); query.bindValue(":id", id); if ( !query.exec() ) return; QString text; while(query.next()) text = query.value(0).toString(); PageTextDialog dlg(this, text); dlg.exec(); } void ClippingStation::onActionViewKeywordsSearchword() { // QAbstractItemModel *model = ui->treeView->model(); QModelIndexList list = ui->treeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; QString pageName = index .data(Qt::DisplayRole).toString(); //get searchwords for this keywords QString lstring = Tag::loadSearchwords(m_slaveDatabase, pageName); QMessageBox::information(0, "Searchwords", QString("Searchwords are:\n%1").arg(lstring)); } void ClippingStation::onActionGoToKeywordWikiPage() { // QAbstractItemModel *model = ui->treeView->model(); QModelIndexList list = ui->treeView->selectionModel()->selectedIndexes(); if (list.count() == 0) return; QModelIndex index = list[0]; QString keyword = index.data(Qt::DisplayRole).toString(); keyword.replace(QRegularExpression("\\s"), "_"); keyword.replace(' ', '_'); // keyword.replace("'", "_"); // keyword.replace("-", "_"); QUrl url(QString("%1%2").arg(SystemConfiguration::wikiUrl()).arg(keyword)); // QMessageBox::information(this, "test", QString("URL is %1").arg(url.toString())); QDesktopServices::openUrl (url); } void ClippingStation::onActionAbout() { QMessageBox::about(this, tr("About Clipping Station"), "

Clipping Station - $Revision: 668 $

" "

(c) Copyright 2009-2011 ALLCONTENT. All rights reserved.

"); } bool ClippingStation::eventFilter(QObject *obj, QEvent *event) { if (obj == ui->treeWidget) { if(event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); if(keyEvent->key() == Qt::Key_Enter) { selectKeyword(); return true; } } } return QMainWindow::eventFilter(obj, event); } void ClippingStation::loadIssues() { QString name = ui->publicationNameLineEdit_2->text(); int id = m_publicationHash[name]; m_publication.setId(id); m_publication.setName(name); m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); //m_publication.loadIssues(ui->issuesTreeView, m_cacheDir); m_publication.loadIssuesOnly(ui->issuesTreeView); //m_publication.addImageCutoutsToIssues(ui->issuesTreeView, true); m_currentIssueDate = ""; m_currentSectionName=""; } void ClippingStation::loadIssuesWithPreclipsOnly() { clock_t start = clock(); QString name = ui->preclippedPublicationComboBox->currentText(); if ( name.isEmpty() ) return; int id = m_publicationHash[name]; m_publication.setId(id); m_publication.setName(name); m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); m_publication.loadIssuesWithPreclipsOnly(ui->issuesTreeView, m_cacheDir); m_currentIssueDate = ""; m_currentSectionName=""; QAbstractItemModel *model = ui->issuesTreeView->model(); QModelIndex issuesIndex = model->index(0, 0, QModelIndex() ); if( issuesIndex.isValid() ) { issueTreeViewItemClicked(issuesIndex); //load the first pre-clip QAbstractItemModel *model = ui->clipsTreeView->model(); QModelIndex preclipRootIndex = model->index(0, 0, QModelIndex() ); QModelIndex pindex = model->index(0, 0, preclipRootIndex); if(pindex.isValid()) articleTreeViewClicked(pindex); } double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("loadIssuesWithPreclipsOnly() Time: %f", diff); } void ClippingStation::loadFilteredIssues() { clock_t start = clock(); QString name = ui->filteredPublicationComboBox->currentText(); if ( name.isEmpty() ) return; int id = m_publicationHash[name]; m_publication.setId(id); m_publication.setName(name); m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); QString keyword, startDate, endDate, type, country, ocrSearchword, status; bool ischecked; m_searchPublicationsDlg.get(keyword, ischecked, startDate, endDate, type, country, ocrSearchword, status); //now search for the publications that meet those criteria int countryId = -1; if(!country.isEmpty()) countryId = m_countriesHash[country]; int typeId = -1; if(!type.isEmpty()) { if(type.compare("newspaper", Qt::CaseInsensitive) == 0) //NEWSPAPER 1 typeId = 1; else if(type.compare("magazine", Qt::CaseInsensitive) == 0) typeId = 2; } m_publication.loadFilteredIssues(ui->issuesTreeView, m_ocrDatabase, m_cacheDir, startDate, endDate, keyword, ocrSearchword, status); m_currentIssueDate = ""; m_currentSectionName=""; double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("loadIssuesWithPreclipsOnly() Time: %f", diff); } void ClippingStation::loadUndoneIssuesOnly() { clock_t start = clock(); QString name = ui->undonePublicationComboBox->currentText(); if ( name.isEmpty() ) return; int id = m_publicationHash[name]; m_publication.setId(id); m_publication.setName(name); m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); m_publication.loadUndoneIssuesOnly(ui->issuesTreeView); m_currentIssueDate = ""; m_currentSectionName=""; /* QAbstractItemModel *model = ui->issuesTreeView->model(); QModelIndex issuesIndex = model->index(0, 0, QModelIndex() ); if( issuesIndex.isValid() ) { issueTreeViewItemClicked(issuesIndex); //load the first pre-clip QAbstractItemModel *model = ui->clipsTreeView->model(); QModelIndex preclipRootIndex = model->index(0, 0, QModelIndex() ); QModelIndex pindex = model->index(0, 0, preclipRootIndex); if(pindex.isValid()) articleTreeViewClicked(pindex); } */ double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("loadUndoneIssuesOnly() Time: %f", diff); } void ClippingStation::issueTreeViewItemClicked(QModelIndex index) { qDebug("issueTreeViewItemClicked()"); if( index.isValid() ) { QAbstractItemModel *model = ui->issuesTreeView->model(); if(model->parent(index) == QModelIndex() ) { //qDebug("We are at Issue Level"); //we may have not loaded the sections, so we do that, and then do our work // QString issueDate = model->data(index , Qt::DisplayRole).toString(); if( !m_publication.issue(issueDate)->isLoaded() ) { //load the issue, and QStandardItemModel *standardModel = static_cast ( ui->issuesTreeView->model() ); QStandardItem* issueItem = standardModel->itemFromIndex(index); m_publication.loadIssueSections(issueItem, issueDate, m_cacheDir); } QString sectionName = model->data(model->index(0, 0, index), Qt::DisplayRole).toString(); if( m_currentIssueDate != issueDate) ui->fullpageView->removeImageCutouts(); m_currentIssueDate = issueDate; m_publication.setCurrentIssue(issueDate); m_publication.currentIssue()->showArticlesInView(m_masterDatabase, ui->clipsTreeView, m_filterMode); m_publication.currentIssue()->section(sectionName).getLocalAndRemoteFiles(m_localImagesList, m_remoteImagesList); m_publication.addImageCutoutsToIssues(ui->issuesTreeView, false); ui->issuesTreeView->expand(index); updateSectionPagesStatus(); return; } if(model->parent(index).parent() == QModelIndex() ) { //qDebug("We are at Section Level"); QString issueDate = model->data(index.parent(), Qt::DisplayRole).toString(); QString sectionName = model->data(index , Qt::DisplayRole).toString(); if( m_currentIssueDate != issueDate) ui->fullpageView->removeImageCutouts(); m_currentIssueDate = issueDate; m_publication.setCurrentIssue(issueDate); m_publication.currentIssue()->showArticlesInView(m_masterDatabase, ui->clipsTreeView, m_filterMode); m_publication.currentIssue()->section(sectionName).getLocalAndRemoteFiles(m_localImagesList, m_remoteImagesList); m_publication.addImageCutoutsToIssues(ui->issuesTreeView, false); ui->issuesTreeView->expand(index); updateSectionPagesStatus(); return; } bool showArticleSelections; int articleId = 0; if(model->parent(index).parent().parent() == QModelIndex() ) //its the image showArticleSelections = false; else //its a selection in the image { showArticleSelections = true; articleId = index.data(Qt::DisplayRole).toInt(); index = index.parent(); //gotoArticlePage(articleId); } QString sectionName = model->parent(index) .data(Qt::DisplayRole).toString(); QString issueDate = model->parent(index).parent().data(Qt::DisplayRole).toString(); if( m_currentIssueDate != issueDate) { ui->fullpageView->removeImageCutouts(); updateSectionPagesStatus(); } else if(m_currentSectionName != sectionName) ui->fullpageView->hideImageCutouts(); m_currentIssueDate = issueDate; m_currentSectionName = sectionName; m_publication.setCurrentIssue(issueDate); m_publication.currentIssue()->showArticlesInView(m_masterDatabase, ui->clipsTreeView, m_filterMode); m_publication.currentIssue()->section(sectionName).getLocalAndRemoteFiles(m_localImagesList, m_remoteImagesList); m_publication.addImageCutoutsToIssues(ui->issuesTreeView, false); if(m_runningMode != NORMAL_MODE && ui->preclipButton->text() == tr("Preclip") ) { ui->fullpageView->removeImageCutouts(); m_tagsWrapper.clearTags(); m_tagsWrapper.showModel(); if(m_runningMode == CLIPPING_MODE) drawerResetPages(); } if ( ui->fullpageView->preselectedImageCutoutsCount() > 0 ) { ui->fullpageView->removePreselectedImageCutouts(); m_tagsWrapper.clearTags(); m_tagsWrapper.showModel(); } if(showArticleSelections) { ui->fullpageView->setPreselectedImageCutouts( m_publication.currentIssue()->getImageCutouts(articleId) ); m_tagsWrapper.setOcrTags(m_publication.currentIssue()->articleTags(articleId)); m_tagsWrapper.showModel(); } m_imageModelIndex = index; m_imageIndex = index.row(); m_clippedImageModelIndex = m_preclippedImageModelIndex = QModelIndex(); loadImage(); enableDrawerButtons(true); setModifyClipButton(false); m_runningMode = NORMAL_MODE; ui->gotoPageLineEdit->setText(QString("%1").arg(m_imageIndex+1) ); } } void ClippingStation::articleTreeViewClicked(QModelIndex index) { qDebug("articleTreeViewClicked()"); static int clipid, preclipid; if( !index.isValid() ) return; QAbstractItemModel *model = ui->clipsTreeView->model(); QModelIndex preclipRootIndex = model->index(0, 0, QModelIndex() ); QModelIndex clipRootIndex = model->index(1, 0, QModelIndex() ); //if the user clicked on top level entries, just return if ( index == preclipRootIndex || index == clipRootIndex ) { ui->clipsTreeView->expand(index); return; } int id; if ( index.parent() == preclipRootIndex || index.parent().parent() == preclipRootIndex ) { QModelIndex currentIndex; m_clippedImageModelIndex = QModelIndex(); //if the selection is the Preclip(), then it will contain the id if(index.parent() == preclipRootIndex) { id = model->index(index.row(), 1, index.parent() ).data(Qt::DisplayRole).toInt(); currentIndex = model->index(0, 0, index); } else { id = model->index(index.parent().row(), 1, index.parent().parent() ).data(Qt::DisplayRole).toInt(); currentIndex = index; } if (currentIndex == m_preclippedImageModelIndex ) return; //if its the same selection, do nothing if ( preclipid != id || m_currentPreclipId == 0 ) { if(m_runningMode == CLIPPING_MODE) drawerResetPages(); clipid = 0; m_currentClipId = 0; preclipid = id; m_currentPreclipId = id; m_firstPageInClip = ""; } if (ui->preclipButton->text() != tr("Preclip")) { QList tags = m_tagsWrapper.ocrTags(); m_tagsWrapper.setOcrTags( tags ); QList cutoutsList = ui->fullpageView->imageCutoutsList(); m_publication.currentIssue()->preclip(id).setImageCutouts(cutoutsList); } else m_tagsWrapper.setOcrTags( m_publication.currentIssue()->preclip(id).tags() ); ui->fullpageView->hideImageCutouts(); ui->fullpageView->removePreselectedImageCutouts(); ui->fullpageView->setImageCutouts(m_publication.currentIssue()->preclip(id).imageCutoutsList()); m_tagsWrapper.showModel(); //m_cachedImages.clear(); m_publication.currentIssue()->preclip(id).getImagesLocalAndRemoateFiles(m_preclippedLocalImagesList, m_preclippedRemoteImagesList); m_preclippedImageIndex = currentIndex.row(); m_preclippedImageModelIndex = currentIndex; QString section = model->data(currentIndex, Qt::DisplayRole).toString(); section = section.left(section.indexOf("/")); m_currentSectionName = section; QString fname = m_preclippedRemoteImagesList[0]; //its int the format of /ClippingStation/cach/2009/10/17/162/16/0001.jpg QStringList list = fname.split("/"); m_currentIssueDate = list[list.count()-6] + "-" + list[list.count()-5]+ "-" + list[list.count()-4]; m_publication.setCurrentIssue(m_currentIssueDate); m_publication.currentIssue()->section(m_currentSectionName).getLocalAndRemoteFiles(m_localImagesList, m_remoteImagesList); ui->clipsTreeView->selectionModel()->clearSelection(); ui->clipsTreeView->selectionModel()->setCurrentIndex(m_preclippedImageModelIndex, QItemSelectionModel::Select); //ui->clipsTreeView->expand(m_preclippedImageModelIndex.parent().parent() ); //ui->clipsTreeView->expand(m_preclippedImageModelIndex.parent() ); ui->clipsTreeView->expand(m_preclippedImageModelIndex ); enableDrawerButtons(true); setModifyClipButton(false); m_runningMode = PRECLIPPING_MODE; } else if ( index.parent() == clipRootIndex || index.parent().parent() == clipRootIndex ) { m_runningMode = CLIPPING_MODE; QModelIndex currentIndex; m_preclippedImageModelIndex = QModelIndex(); //qDebug("Columns count is %d", model->columnCount(index.parent()) ); if(index.parent() == clipRootIndex) { id = model->index(index.row(), 1, index.parent() ).data(Qt::DisplayRole).toInt(); currentIndex = model->index(0, 0, index); } else { id = model->index(index.parent().row(), 1, index.parent().parent() ).data(Qt::DisplayRole).toInt(); currentIndex = index; } if (currentIndex == m_clippedImageModelIndex ) return; //if its the same selection, do nothing if(clipid != id || m_currentClipId == 0) { drawerResetPages(); clipid = id; m_currentClipId = id; preclipid = 0; m_currentPreclipId = 0; m_firstPageInClip = ""; } ui->fullpageView->hideImageCutouts(); ui->fullpageView->removePreselectedImageCutouts(); ui->fullpageView->setImageCutouts(m_publication.currentIssue()->clip(id).imageCutoutsList()); //m_cachedImages.clear(); m_publication.currentIssue()->clip(id).getImagesLocalAndRemoateFiles(m_clippedLocalImagesList, m_clippedRemoteImagesList); m_tagsWrapper.setOcrTags( m_publication.currentIssue()->clip(id).tags() ); m_tagsWrapper.showModel(); m_clippedImageIndex = currentIndex.row(); m_clippedImageModelIndex = currentIndex; //ui->clipsTreeView->expand(m_clippedImageModelIndex.parent().parent() ); //ui->clipsTreeView->expand(m_clippedImageModelIndex.parent() ); ui->clipsTreeView->expand(m_clippedImageModelIndex ); ui->clipsTreeView->selectionModel()->clearSelection(); ui->clipsTreeView->selectionModel()->setCurrentIndex(m_clippedImageModelIndex, QItemSelectionModel::Select); QString section = model->data(currentIndex, Qt::DisplayRole).toString(); section = section.left(section.indexOf("/")); m_currentSectionName = section; QString fname = m_clippedRemoteImagesList[0]; //its int the format of G:/socialhose/app/ClippingStation/debug/cach/2009/10/17/162/16/0001.jpg QStringList list = fname.split("/"); m_currentIssueDate = list[list.count()-6] + "-" + list[list.count()-5]+ "-" + list[list.count()-4]; m_publication.setCurrentIssue(m_currentIssueDate); m_publication.currentIssue()->section(m_currentSectionName).getLocalAndRemoteFiles(m_localImagesList, m_remoteImagesList); loadClippingImages(id); } loadImage(); gotoClipPage(); } void ClippingStation::clearStatusMessage() { ui->statusBar->clearMessage(); } void ClippingStation::displayStatusMessage(const QString & status) { ui->statusBar->showMessage(status); } void ClippingStation::displayCoordinatesStatus(qreal x, qreal y, qreal width, qreal height) { ui->statusBar->displayCoordinates(x, y, width, height); } void ClippingStation::displayRotationAngleStatus(qreal angle) { ui->statusBar->displayRotationAngle(angle); } void ClippingStation::updateDrawerPageInformation() { ui->pageInformation->setText(QString("Page %1 of %2") .arg(ui->stackedDrawerViewWidget->currentIndex() +1) .arg(ui->stackedDrawerViewWidget->count())); } void ClippingStation::displayZoomStatus(qreal zoom) { ui->statusBar->displayZoom(zoom); } void ClippingStation::firstPage() { if ( m_imageModelIndex.isValid() ) { int oldindex = m_imageIndex; m_imageIndex = 0; if (!loadImage()) { m_imageIndex = oldindex; return; } m_imageModelIndex = ui->issuesTreeView->model()->index(0, 0, ui->issuesTreeView->model()->parent(m_imageModelIndex) ); ui->issuesTreeView->selectionModel()->clearSelection(); ui->issuesTreeView->selectionModel()->setCurrentIndex(m_imageModelIndex, QItemSelectionModel::Select); ui->gotoPageLineEdit->setText(QString("%1").arg(m_imageIndex+1) ); } } void ClippingStation::previousPage() { if ( m_imageIndex > 0 && m_imageModelIndex.isValid() ) { --m_imageIndex; if (!loadImage()) { ++m_imageIndex; return; } m_imageModelIndex = ui->issuesTreeView->model()->index(m_imageModelIndex.row()-1, 0, ui->issuesTreeView->model()->parent(m_imageModelIndex) ); ui->issuesTreeView->selectionModel()->clearSelection(); ui->issuesTreeView->selectionModel()->setCurrentIndex(m_imageModelIndex, QItemSelectionModel::Select); ui->gotoPageLineEdit->setText(QString("%1").arg(m_imageIndex+1) ); } } void ClippingStation::nextPage() { if( m_imageIndex < m_localImagesList.count()-1 ) { m_imageIndex++; if (!loadImage()) { --m_imageIndex; return; } m_imageModelIndex = ui->issuesTreeView->model()->index(m_imageModelIndex.row()+1, 0, ui->issuesTreeView->model()->parent(m_imageModelIndex) ); ui->issuesTreeView->selectionModel()->clearSelection(); ui->issuesTreeView->selectionModel()->setCurrentIndex(m_imageModelIndex, QItemSelectionModel::Select); ui->gotoPageLineEdit->setText(QString("%1").arg(m_imageIndex+1) ); } } void ClippingStation::lastPage() { if ( m_imageModelIndex.isValid() ) { int oldindex = m_imageIndex; m_imageIndex = m_localImagesList.count() -1; if (!loadImage()) { m_imageIndex = oldindex; return; } m_imageModelIndex = ui->issuesTreeView->model()->index(m_imageIndex, 0,ui->issuesTreeView->model()->parent(m_imageModelIndex) ); ui->issuesTreeView->selectionModel()->clearSelection(); ui->issuesTreeView->selectionModel()->setCurrentIndex(m_imageModelIndex, QItemSelectionModel::Select); ui->gotoPageLineEdit->setText(QString("%1").arg(m_imageIndex+1) ); } } void ClippingStation::gotoPage() { bool ok; int pagenum = ui->gotoPageLineEdit->text().toInt(&ok); if(!ok) return; if( m_imageModelIndex.isValid() ) { if ( pagenum < 1 || pagenum > m_localImagesList.count() ) return; int oldindex = m_imageIndex; m_imageIndex = pagenum -1 ; if(!loadImage()) { m_imageIndex = oldindex; return; } m_imageModelIndex = ui->issuesTreeView->model()->index(m_imageIndex, 0, ui->issuesTreeView->model()->parent(m_imageModelIndex) ); ui->issuesTreeView->selectionModel()->clearSelection(); ui->issuesTreeView->selectionModel()->setCurrentIndex(m_imageModelIndex, QItemSelectionModel::Select); } } void ClippingStation::gotoClipPage() { //qDebug("gotoClipPage()"); QAbstractItemModel* model = ui->issuesTreeView->model(); int issuesCount = model->rowCount( QModelIndex() ); QString article; if(m_runningMode == PRECLIPPING_MODE) article = ui->clipsTreeView->model()->data(m_preclippedImageModelIndex, Qt::DisplayRole).toString(); else if(m_runningMode == CLIPPING_MODE) article = ui->clipsTreeView->model()->data(m_clippedImageModelIndex , Qt::DisplayRole).toString(); for(int i=0; i< issuesCount; i++) { QString issue = model->index(i, 0, QModelIndex() ).data(Qt::DisplayRole).toString(); if(issue != m_currentIssueDate) continue; QModelIndex issueIndex = model->index(i, 0, QModelIndex() ); int sectionsCount = model->rowCount(issueIndex); for(int j=0; j < sectionsCount; j++) { QString section = model->index(j, 0, issueIndex).data(Qt::DisplayRole).toString(); if( article.split("/").at(0) != section )// != m_currentSectionName) continue; QModelIndex sectionIndex = model->index(j, 0, issueIndex); int pagesCount = model->rowCount(sectionIndex); for(int k=0; k< pagesCount; k++) { QString page = model->index(k, 0, sectionIndex).data(Qt::DisplayRole).toString(); if( !article.endsWith(page) ) continue; m_imageModelIndex = model->index(k, 0, sectionIndex); ui->issuesTreeView->selectionModel()->clearSelection(); ui->issuesTreeView->selectionModel()->setCurrentIndex(m_imageModelIndex, QItemSelectionModel::Select); ui->issuesTreeView->expand(m_imageModelIndex.parent().parent()); ui->issuesTreeView->expand(m_imageModelIndex.parent()); //ui->issuesTreeView->expand(m_imageModelIndex); } return; } return; } } void ClippingStation::rotate(double i) { ui->fullpageView->rotate(i); if(i == 0) ui->saveRotateButton->setEnabled(false); else ui->saveRotateButton->setEnabled(true); } void ClippingStation::saveImageRotation() { //we first get the ORIGINAL image from the file server //we get its name/path QString localeImage, remoteImage; if(m_runningMode == NORMAL_MODE) { localeImage = m_localImagesList[m_imageIndex]; remoteImage = m_remoteImagesList[m_imageIndex]; } else if (m_runningMode == PRECLIPPING_MODE) { localeImage = m_preclippedLocalImagesList[m_preclippedImageIndex]; remoteImage = m_preclippedRemoteImagesList[m_preclippedImageIndex]; } else if (m_runningMode == CLIPPING_MODE ) { localeImage = m_clippedLocalImagesList[m_clippedImageIndex]; remoteImage = m_clippedRemoteImagesList[m_clippedImageIndex]; } QImage image(remoteImage); //do the roation double rotate = ui->rotateSpinBox->value(); QTransform mx; mx = mx.rotate(rotate); image = image.transformed(mx, Qt::SmoothTransformation); //now we delete the original image, and save this back to that location if (QFile::remove(remoteImage) ) { image.save(remoteImage, "jpg", JPG_SAVE_QUALITY); //also remove the file from the local cache QFile::remove(localeImage); //reset the rotate spin box ui->rotateSpinBox->setValue(0); //and re open the new image after it has been saved m_cachedImages[ localeImage ] = false; //to force to reload the new image from server loadImage(); } //also, load the 300dpi image, and rotate it as well QFileInfo inf(remoteImage); QString img300dpi= inf.absolutePath() + "/" + HIGH_RES_IMAGE_DIR + inf.fileName(); if(!QFile::exists(img300dpi)) return; QImage image300(img300dpi); image300 = image300.transformed(mx, Qt::SmoothTransformation); //now we delete the original image, and save this back to that location if (QFile::remove(img300dpi) ) image300.save(img300dpi, "jpg", JPG_SAVE_QUALITY); } qreal ClippingStation::zoomOut() { ui->bestFitButton->setChecked(false); ui->widthFitButton->setChecked(false); ui->fullpageView->setPageLayout(ACTUAL_SIZE); return ui->fullpageView->zoom(false); } qreal ClippingStation::zoomIn() { ui->bestFitButton->setChecked(false); ui->widthFitButton->setChecked(false); ui->fullpageView->setPageLayout(ACTUAL_SIZE); return ui->fullpageView->zoom(true); } qreal ClippingStation::actualSize() { ui->bestFitButton->setChecked(false); ui->widthFitButton->setChecked(false); ui->fullpageView->setPageLayout(ACTUAL_SIZE); return ui->fullpageView->actualSize(); } void ClippingStation::bestFit() { ui->bestFitButton->setChecked(true); ui->widthFitButton->setChecked(false); ui->fullpageView->setPageLayout(BEST_FIT); } void ClippingStation::widthFit() { ui->bestFitButton->setChecked(false); ui->widthFitButton->setChecked(true); ui->fullpageView->setPageLayout(WIDTH_FIT); } qreal ClippingStation::drawerZoomOut() { ui->drawerBestFitButton->setChecked(false); ui->drawerWidthFitButton->setChecked(false); int index = ui->stackedDrawerViewWidget->currentIndex(); //ui->stackedDrawerViewWidget->setCurrentIndex(0); qreal scale = 1.0; for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { ui->stackedDrawerViewWidget->setCurrentIndex(i); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); scale = view->zoom(false); m_currentA4Scale = view->currentScale(); } ui->stackedDrawerViewWidget->setCurrentIndex(index); return scale; } qreal ClippingStation::drawerZoomIn() { ui->drawerBestFitButton->setChecked(false); ui->drawerWidthFitButton->setChecked(false); int index = ui->stackedDrawerViewWidget->currentIndex(); //ui->stackedDrawerViewWidget->setCurrentIndex(0); qreal scale = 1.0; for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { ui->stackedDrawerViewWidget->setCurrentIndex(i); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); scale = view->zoom(true); m_currentA4Scale = view->currentScale(); } ui->stackedDrawerViewWidget->setCurrentIndex(index); return scale; } qreal ClippingStation::drawerActualSize() { ui->drawerBestFitButton->setChecked(false); ui->drawerWidthFitButton->setChecked(false); int index = ui->stackedDrawerViewWidget->currentIndex(); ui->stackedDrawerViewWidget->setCurrentIndex(0); qreal scale = 1.0; for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); view->setPageLayout(ACTUAL_SIZE); scale = view->actualSize(); m_currentA4Scale = view->currentScale(); } ui->stackedDrawerViewWidget->setCurrentIndex(index); return scale; } void ClippingStation::drawerBestFit() { ui->drawerBestFitButton->setChecked(true); ui->drawerWidthFitButton->setChecked(false); int index = ui->stackedDrawerViewWidget->currentIndex(); ui->stackedDrawerViewWidget->setCurrentIndex(0); for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); view->setPageLayout(BEST_FIT); m_currentA4Scale = view->currentScale(); } ui->stackedDrawerViewWidget->setCurrentIndex(index); } void ClippingStation::drawerWidthFit() { ui->drawerBestFitButton ->setChecked(false); ui->drawerWidthFitButton->setChecked(true); int index = ui->stackedDrawerViewWidget->currentIndex(); ui->stackedDrawerViewWidget->setCurrentIndex(0); for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); view->setPageLayout(WIDTH_FIT); m_currentA4Scale = view->currentScale(); } ui->stackedDrawerViewWidget->setCurrentIndex(index); } bool ClippingStation::loadImage() { // qDebug("loadImage()"); // clock_t start = clock(); static bool firstPage = true; m_trackingTimer.stop(); /* ------------------------ | id_user_page_track | | id_users | | id_section_pages | | last_modified | | first_access | | last_access | | issue_created | | id_publication | | id_publication_type | | publication_language | | publication_market | | issue_date | | seconds | ------------------------ */ if(!firstPage && m_trackingSeconds > 0) { QString language = "en"; if(m_publication.language() == "Arabic") language = "ar"; m_user.updateTrack(m_currentPageId, m_trackingSeconds); } bool ret = true; QString localeImage, remoteImage; if (m_runningMode == NORMAL_MODE) { qDebug() << "\tImage: "<< m_remoteImagesList[m_imageIndex]; localeImage = m_localImagesList[m_imageIndex]; remoteImage = m_remoteImagesList[m_imageIndex]; } else if (m_runningMode == PRECLIPPING_MODE) { qDebug() << "\tPreclipping Image: "<< m_preclippedRemoteImagesList[m_preclippedImageIndex]; localeImage = m_preclippedLocalImagesList[m_preclippedImageIndex]; remoteImage = m_preclippedRemoteImagesList[m_preclippedImageIndex]; } else if (m_runningMode == CLIPPING_MODE ) { qDebug() << "\tClipping Image: "<< m_clippedRemoteImagesList[m_clippedImageIndex]; localeImage = m_clippedLocalImagesList[m_clippedImageIndex]; remoteImage = m_clippedRemoteImagesList[m_clippedImageIndex]; } /*int lockedBy; if( isImageLocked(localeImage, lockedBy) ) { QString username = User::username(m_slaveDatabase, lockedBy); QMessageBox::warning(this, tr("Page Locked"), tr("You cant load this page because its locked by user (%1)").arg(username) ); return false; } lockImage(localeImage);*/ if( !m_cachedImages[ localeImage ] ) { if ( !m_imageCachingDialog.cachingThreadStarted() ) { ret = cacheOnePage(remoteImage, localeImage); } else { m_imageCachingDialog.pause(); ret = cacheOnePage(remoteImage, localeImage); } } if(ret) ret = ui->fullpageView->load(localeImage); if(ret) { QStringList parts = localeImage.split("/"); QString image = parts[parts.count()-1]; m_currentPageId = getImageId(image); loadImageHighlights(m_currentPageId);//load the highlights } // double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; // qDebug("loadImage() Time: %f", diff); cache(); if(m_isPaused) //if in pause state, change it to resume. pauseTracking(); m_trackingSeconds = 0; m_trackingTimer.start(1000); int pubIssueId = publicationIssueId(m_publication.id(), m_publication.currentIssue()->date()); int issueSecId = issueSectionsId(pubIssueId, m_publication.currentIssue()->section(m_currentSectionName).id()); m_user.track(m_currentPageId, m_publication.id(), pubIssueId, issueSecId, m_publication.type(), m_publication.country().toInt(), m_publication.language(), m_publication.currentIssue()->date(), m_publication.currentIssue()->created()); firstPage = false; return ret; } void ClippingStation::cache() { //qDebug("cache()"); clock_t start = clock(); if(m_runningMode == NORMAL_MODE) m_imageCachingDialog.setValues(m_remoteImagesList, m_localImagesList); else if(m_runningMode == CLIPPING_MODE ) m_imageCachingDialog.setValues(m_clippedRemoteImagesList, m_clippedLocalImagesList); else if(m_runningMode == PRECLIPPING_MODE ) m_imageCachingDialog.setValues(m_preclippedRemoteImagesList, m_preclippedLocalImagesList); m_imageCachingDialog.startCaching(); m_imageCachingDialog.show(); //m_imageCachingDialog.exec(); double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("cache() Time: %f", diff); } bool ClippingStation::cacheOnePage(QString srcPage, QString dstPage) { clock_t start = clock(); m_imageCachingDialog.pause(); return m_imageCachingDialog.cacheOnePage(srcPage, dstPage); double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("cacheOnePage() Time: %f", diff); } bool ClippingStation::recursiveDelete(const QDir &dir) { QList infLst = dir.entryInfoList(); foreach(QFileInfo finfo, infLst ) { if(finfo.fileName() == "." || finfo.fileName() == ".." ) continue; if(finfo.isDir() ) { QDir subDir(finfo.absoluteFilePath()); qDebug() << "SubDir: " << subDir.absolutePath().toLocal8Bit(); QDir dir1 = dir; if ( recursiveDelete(subDir) ) { dir1.cdUp(); if ( !dir1.rmdir(finfo.absoluteFilePath() ) ) { qDebug() << "Error deleting directory: " << finfo.absoluteFilePath().toLocal8Bit(); } } } else { //file QDir dir1; if( !dir1.remove(finfo.absoluteFilePath()) ) qDebug() << "Error deleting file: " << finfo.absoluteFilePath(); } } return true; } void ClippingStation::searchKeyword() { QString search = ui->keywordLineEdit->text(); if( search.isEmpty() || search.isNull() ) return; m_tagsWrapper.searchKeyword(m_masterDatabase, search); } void ClippingStation::checkAllKeywords() { m_tagsWrapper.checkAllKeywords(); } void ClippingStation::uncheckAllKeywords() { m_tagsWrapper.uncheckAllKeywords(); } void ClippingStation::selectKeyword() { m_tagsWrapper.selectKeyword(); } void ClippingStation::clipsTreeContextMenu(QPoint point) { QModelIndex index = ui->clipsTreeView->indexAt(point); if( index.isValid() ) { point.setY(point.y() + 25); QAbstractItemModel *model = ui->clipsTreeView->model(); QModelIndex preclipRootIndex = model->index(0, 0, QModelIndex() ); QModelIndex clipRootIndex = model->index(1, 0, QModelIndex() ); //if the user clicked on top level entries, just return if ( index == preclipRootIndex || index == clipRootIndex ) return; int id; if ( index.parent() == preclipRootIndex || index.parent().parent() == preclipRootIndex ) { m_runningMode = PRECLIPPING_MODE; QModelIndex currentIndex; m_clippedImageModelIndex = QModelIndex(); //if the selection is the Preclip(), then it will contain the id if(index.parent() == preclipRootIndex) { id = model->index(index.row(), 1, index.parent() ).data(Qt::DisplayRole).toInt(); //currentIndex = index.child(0, 0); } else { id = model->index(index.parent().row(), 1, index.parent().parent() ).data(Qt::DisplayRole).toInt(); //currentIndex = index; } m_preclipContextMenu->exec( ui->clipsTreeView->mapToGlobal(point)); } else { m_clipContextMenu->exec( ui->clipsTreeView->mapToGlobal(point)); } } } void ClippingStation::issueTreeContextMenu(QPoint point) { QModelIndex index = ui->issuesTreeView->indexAt(point); if( index.isValid() ) { point.setY(point.y() + 25); QAbstractItemModel *model = ui->issuesTreeView->model(); if(index == QModelIndex() ) return; if(model->parent(index) == QModelIndex() ) { m_issueContextMenu->exec(ui->issuesTreeView->mapToGlobal(point)); return; } if(model->parent(index).parent() == QModelIndex() ) return; if(model->parent(index).parent().parent() == QModelIndex() ) //its the image m_issuePageContextMenu->exec( ui->issuesTreeView->mapToGlobal(point)); else qDebug() << "not an image selection"; } } void ClippingStation::keywordsTreeContextMenu(QPoint point) { QModelIndex index = ui->treeView->indexAt(point); if(!index.isValid()) return; point.setY(point.y()+25); // QAbstractItemModel *model = ui->treeView->model(); m_keywordsContextMenu->exec( ui->treeView->mapToGlobal(point)); } void ClippingStation::preclip() { qDebug("preclip()"); QList cutoutsList = ui->fullpageView->imageCutoutsList(); if(cutoutsList.count() == 0) { QMessageBox::information(this, "No selections", "Please select at least one cutout to be able to clip"); return; } QList tags = m_tagsWrapper.ocrTags(); if( tags.count() == 0 ) { QMessageBox::information(this, "No Tags", "Please add the associated tags to be able to clip"); return; } qreal image_size = ui->fullpageView->pageSize(); if(ui->preclipButton->text() == tr("Modify")) { m_publication.currentIssue()->preclip(m_currentPreclipId).updateArticle(m_masterDatabase, m_publication, tags, cutoutsList, image_size); m_publication.currentIssue()->addArticleToView(m_masterDatabase, ui->clipsTreeView, m_currentPreclipId, false, true); } else { int articleId = Article::clip(m_masterDatabase, m_publication, m_user.id(), tags, cutoutsList, m_currentSectionName, image_size, 0, 1, ""); m_publication.currentIssue()->addArticleToView(m_masterDatabase, ui->clipsTreeView, articleId, false, false); } drawerResetPages(); m_firstPageInClip = ""; //reset pages for clipping m_currentPreclipId = 0; //reset the preclip id; m_currentClipId = 0; //loadIssuesWithPreclipsOnly(); m_tagsWrapper.clearTags(); ui->fullpageView->removeImageCutouts(); m_publication.addImageCutoutsToIssues(ui->issuesTreeView, false); setModifyPreclipButton(false); m_runningMode = NORMAL_MODE; ui->statusBar->showMessage("Preclipping successfull"); qDebug("end of preclip()"); } void ClippingStation::clip() { qDebug("clip()"); qDebug("before cutoutList()"); QList cutoutsList = ui->fullpageView->imageCutoutsList(); if(cutoutsList.count() == 0) { QMessageBox::information(this, "No selections", "Please select at least one area to be able to clip"); return; } qDebug("before ocrTags()"); QList tags = m_tagsWrapper.ocrTags(); if( tags.count() == 0 ) { QMessageBox::information(this, "No Tags", "Please add the associated tags to be able to clip"); return; } static QSqlDatabase db = m_masterDatabase.cloneDatabase(m_masterDatabase, "master2222"); db.open(); if (m_runningMode != CLIPPING_MODE) { int cutoutsCount = totalNumberOfCutoutsInDrawer(); if( cutoutsCount <= 0 ) { QMessageBox::information(this, "Blank clipping", "Please add the cut outs be able to clip"); return; } QStringList pages = emptyDrawerPages(); if(pages.count() > 0) { QString page; if(pages.count() == 1) page = QString("Page (%1) in drawer is empty, please remove it before clipping").arg(pages[0]); else page = QString("Pages (%1) in drawer are empty, please remove them before clipping").arg(pages.join(",")); QMessageBox::information(this, "Empty pages", page); return; } if( cutoutsList.count() > cutoutsCount ) { switch( QMessageBox::question( this, tr("Warning"), tr("You only copied %1/%2 cutouts from left pane, Do you want to CONTINUE the clipping process?").arg( cutoutsCount ).arg( cutoutsList.count() ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ) { case QMessageBox::Yes: break; case QMessageBox::No: return; default: return; } } } if (m_runningMode == PRECLIPPING_MODE) { int images_number = ui->stackedDrawerViewWidget->count(); //the count of image QString text = ui->fullpageView->text(); bool isArabic = (m_publication.language() == "Arabic"); m_publication.currentIssue()->preclip(m_currentPreclipId).updateTags(m_masterDatabase, tags, isArabic); m_publication.currentIssue()->preclip(m_currentPreclipId).updateImagesNumber(m_masterDatabase, images_number); m_publication.currentIssue()->preclip(m_currentPreclipId).updateProminence(m_masterDatabase, m_publication, tags, m_user.id()); QList list = createClipImages(); bool ret = true; if(m_useFtp) { QFuture future = QtConcurrent::run([=]() mutable { return saveClipImagesToFtpServer(m_currentIssueDate, m_currentPreclipId, list, true, m_masterDatabase); }); m_saveClipImagesToFtpServerWatcher.setFuture(future); } else { QFuture future = QtConcurrent::run([=]() mutable { return saveClipImagesToFileServer(m_currentIssueDate, m_currentPreclipId, list); }); m_saveClipImagesToFileServerWatcher.setFuture(future); //ret = saveClipImagesToFileServer(m_currentPreclipId, list); //save the clip images in the clip directories //ret = saveClipImagesToFileServer(m_currentIssueDate, m_currentPreclipId, list, true, m_masterDatabase); } if(!m_publication.skipOcr()) { qDebug() << m_publication.name() << " not skip OCR, Insert to db"; bool isArabic = (m_publication.language() == "Arabic"); QFuture future2 = QtConcurrent::run([=]() mutable { return addTextToClip(m_currentPreclipId, cutoutsList, db, isArabic); }); m_addTextToClipWatcher.setFuture(future2); } else qDebug() << m_publication.name() << " has skip OCR set, wont insert text to db"; if(!ret) { m_publication.currentIssue()->preclip(m_currentPreclipId).updateStatus(m_masterDatabase, 1); ui->statusBar->showMessage("Clipping Error"); } else { m_publication.currentIssue()->addArticleToView(m_masterDatabase, ui->clipsTreeView, m_currentPreclipId, true, true); ui->statusBar->showMessage("Clipping successfull"); } } else if (m_runningMode == CLIPPING_MODE) { bool isArabic = (m_publication.language() == "Arabic"); m_publication.currentIssue()->clip(m_currentClipId).updateTags(m_masterDatabase, tags, isArabic); m_publication.currentIssue()->clip(m_currentClipId).updateProminence(m_masterDatabase, m_publication, tags, m_user.id()); ui->statusBar->showMessage("Clip modified successfully"); } else //fresh clip { qreal image_size = ui->fullpageView->pageSize(); int images_number = ui->stackedDrawerViewWidget->count(); //the cound of image QString text = ui->fullpageView->text(); int id_article = Article::clip(m_masterDatabase, m_publication, m_user.id(), tags, cutoutsList, m_currentSectionName, image_size, images_number, 1); //create the images QList list = createClipImages(); bool ret = true; if(m_useFtp) { QFuture future = QtConcurrent::run([=]() mutable { return saveClipImagesToFtpServer(m_currentIssueDate, id_article, list, false, m_masterDatabase); }); m_saveClipImagesToFtpServerWatcher.setFuture(future); } else { QFuture future = QtConcurrent::run([=]() mutable { return saveClipImagesToFileServer(m_currentIssueDate, id_article, list); }); m_saveClipImagesToFileServerWatcher.setFuture(future); //ret = saveClipImagesToFileServer(m_currentPreclipId, list); //save the clip images in the clip directories //ret = saveClipImagesToFileServer(m_currentIssueDate, id_article, list, true, m_masterDatabase); } if(!m_publication.skipOcr()) { qDebug() << m_publication.name() << " No skip OCR set, insert text to db"; //QSqlDatabase db = m_masterDatabase.cloneDatabase(m_masterDatabase, "master2222"); //db.open(); bool isArabic = (m_publication.language() == "Arabic"); QFuture future2 = QtConcurrent::run([=]() mutable { return addTextToClip(id_article, cutoutsList, db, isArabic); }); m_addTextToClipWatcher.setFuture(future2); } else qDebug() << m_publication.name() << " has skip OCR set, wont insert text to db"; if(!ret) { Article::deleteArticle(m_masterDatabase, id_article); ui->statusBar->showMessage("Clipping Error"); } else { m_publication.currentIssue()->addArticleToView(m_masterDatabase, ui->clipsTreeView, id_article, true, false); ui->statusBar->showMessage("Clipping successfull"); } } drawerResetPages(); m_firstPageInClip = ""; //reset pages for clipping m_currentPreclipId = 0; //reset the preclip id; m_currentClipId = 0; //if (m_filterMode == PRECLIPSONLY_FILTER) //loadIssuesWithPreclipsOnly(); ui->fullpageView->removeImageCutouts(); m_publication.addImageCutoutsToIssues(ui->issuesTreeView, false); m_tagsWrapper.clearTags(); //m_tagsWrapper.showModel(); m_runningMode = NORMAL_MODE; if (m_filterMode == PRECLIPSONLY_FILTER) { //go to the next preclip QAbstractItemModel *model = ui->clipsTreeView->model(); QModelIndex preclipRootIndex = model->index(0, 0, QModelIndex() ); //if(preclipRootIndex.model()->children().count() > 0) { QModelIndex pindex = model->index(0, 0, preclipRootIndex); if(pindex.isValid()) articleTreeViewClicked(pindex); else { //we have reached the end of this issues preclip, so, remove the issue from list. m_publication.removeIssueFromIssues(ui->issuesTreeView, m_currentIssueDate); m_currentIssueDate = ""; //now go to the next issue QAbstractItemModel *model = ui->issuesTreeView->model(); QModelIndex issuesIndex = model->index(0, 0, QModelIndex() ); if( issuesIndex.isValid() ) issueTreeViewItemClicked(issuesIndex); else { //remove the publication from the drop-down list ui->preclippedPublicationComboBox->removeItem(ui->preclippedPublicationComboBox->currentIndex()); } } } } qDebug("end of clip()"); } void ClippingStation::drawerResetPages() { qDebug("drawerResetPages()"); int count = ui->stackedDrawerViewWidget->count(); for(int i=count -1 ; i >= 0; i--) { ui->stackedDrawerViewWidget->setCurrentIndex(i); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); ui->stackedDrawerViewWidget->removeWidget( ui->stackedDrawerViewWidget->widget(i) ); delete view; } drawerAddPage(true); } void ClippingStation::drawerAddPage(bool isfirst) { DrawerView * newview = new DrawerView(isfirst, ui->page); qreal oldscale = 1.0; //for the first page insertion //first we restore all the current pages to actual size, add the new page, and then restore them back to current size; for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); oldscale = view->actualSize(); } ui->stackedDrawerViewWidget->addWidget(newview); //restore to old scale value for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); view->setScale(oldscale); } ui->stackedDrawerViewWidget->setCurrentIndex(ui->stackedDrawerViewWidget->count() - 1); if(isfirst) drawerBestFit(); //best fit mod // else // newview->setPageLayout(ACTUAL_SIZE); m_currentA4Scale = newview->currentScale(); //qDebug("Add Page scale %.2f", m_currentA4Scale); updateDrawerPageInformation(); connect(newview, SIGNAL(createThumbnail()), this, SLOT(createThumbnail())); } void ClippingStation::drawerRemovePage() { int i = ui->stackedDrawerViewWidget->currentIndex(); if (i == 0) //first page { QMessageBox::critical(this, "Error", "You cant remove the first page in drawer"); return; } switch( QMessageBox::question( this, tr("Delete Page"), tr("Delete page from the Drawer, are you sure?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ) { case QMessageBox::Yes: break; case QMessageBox::No: return; default: return; } //DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); //view->removeEventFilter(this); ui->stackedDrawerViewWidget->removeWidget( ui->stackedDrawerViewWidget->widget(i) ); updateDrawerPageInformation(); } void ClippingStation::drawerPreviousPage() { int currentIndex = ui->stackedDrawerViewWidget->currentIndex(); if (currentIndex != 0) { A4Scale(); ui->stackedDrawerViewWidget->setCurrentIndex(currentIndex-1); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->currentWidget()); view->setScale(m_currentA4Scale); updateDrawerPageInformation(); } } void ClippingStation::drawerNextPage() { int currentIndex = ui->stackedDrawerViewWidget->currentIndex(); if (currentIndex != ui->stackedDrawerViewWidget->count() - 1) { A4Scale(); ui->stackedDrawerViewWidget->setCurrentIndex(currentIndex+1); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->currentWidget()); view->setScale(m_currentA4Scale); updateDrawerPageInformation(); } } QList ClippingStation::createClipImages() { QList list; for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); ui->stackedDrawerViewWidget->setCurrentIndex(i); if(view->cutoutsCount() > 0) { QImage img = view->screenShot(); list.append(img); } } return list; } int ClippingStation::saveClipImagesToFileServer(QString currentIssue, int id_article, QList &list) { g_clipMutex.lock(); qDebug("saveClipImages() for article %d", id_article); //we save the images on this format ClippingsPath/YYYY/MM/DD/ID_ARTICLE-X QString path = SystemConfiguration::clippingsPath(); QStringList dateSplit = currentIssue.split("-"); path = path + QString("%1/%2/%3/").arg(dateSplit[0], 4, QChar('0')).arg(dateSplit[1], 2, QChar('0')).arg(dateSplit[2], 2, QChar('0')); #ifdef Q_WS_WIN path = SystemConfiguration::clippingsWindowsDriveLetter() + path; //if we are under Windows, add Windows drive letter #endif QDir dir; qDebug("saveClipImages() for article %d: create the directory structure", id_article); if( !dir.exists(path) ) { if( !dir.mkpath(path) ) { QMessageBox::critical(0, tr("saveClipImagesToFileServer() Error"), tr("Error creating directory structure for clippings!")); qDebug("saveClipImagesToFileServer(): Error creating directory "); g_clipMutex.unlock(); return 0; } } bool ret = true; int i = 0; //first save the file locally, and then move it the file server qDebug("saveClipImages(): create clippings directory in cache"); QString localpath = m_cacheDir + "clippings/"; QDir dir2; if( !dir2.exists(localpath) ) { if( !dir2.mkpath(localpath) ) { QMessageBox::critical(0, tr("saveClipImagesToFileServer() Error"), tr("Error creating directory structure for local clippings!")); qDebug("saveClipImagesToFileServer(): Error creating directory "); g_clipMutex.unlock(); return 0; } } qDebug("saveClipImages(): trying to save %d images", list.count() ); QFile file; for(i=0; i< list.count(); i++) { QString fname = QString("%1-%2.jpg").arg(id_article).arg(i+1); //if( file.exists(localpath + fname) || file.exists(path + fname) ) //try to remove the files if they exist { file.remove(localpath+ fname); //remove the file from cache if it already exist (from previous un-successful clip) file.remove(path + fname); //and from the file server } ret = list[i].save(localpath + fname, "jpg", 100); if(ret) { qDebug() << "saveClipImages(): saving image " << localpath+fname << " Successfull"; if (file.copy(localpath + fname, path + fname)) qDebug() << "saveClipImages(): copying image to " << path + fname << " Successfull"; else { qDebug() << "saveClipImages(): copying image to " << path + fname << " Unsuccessfull: reason: " << file.errorString(); ret = false; break; } } else { qDebug() << "saveClipImages(): Saving image " << fname << " Unsuccessfull"; ret = false; break; } } if(!ret) { //error happend in the complete set of images, so we delete what is already created qDebug() << "saveClipImages(): Error happened while saving, remove the saved images!"; for(int j=0; j< i; j++) { QString fname = QString("%1-%2.jpg").arg(id_article).arg(j+1); file.remove(localpath +fname); //remove it locally file.remove(path +fname); //and from file server } g_clipMutex.unlock(); return 0; } //we also check to see if the image does REALLY exist on that folder qDebug() << "saveClipImages(): Checking if the images exist on the server and the images sizes is larger than 30kb"; for(int i=0; i< list.count(); i++) { QString fname = path + QString("%1-%2.jpg").arg(id_article).arg(i+1); QFileInfo fi(fname); if( !fi.exists() || (fi.size() < 20 * 1024)) { qDebug() << "saveClipImages(): Image " << fname << " DOES not exist, or size less than 30 kb: " << file.errorString(); ret= false; break; } else qDebug() << "saveClipImages(): Image " << fname << " exist on the server"; } //now save the thumbnail to server qDebug() << "saveClipImages(): save the thumbnail"; QString thumbnailName = QString("%1_thumb.jpg").arg(id_article); if(file.exists(localpath+ thumbnailName)) { file.remove(localpath + thumbnailName); file.remove(path + thumbnailName); } m_thumbnail.save(localpath + thumbnailName, "jpg", 100); file.copy(localpath + thumbnailName, path + thumbnailName); qDebug() << "saveClipImages(): save the thumbnail DONE"; /* qDebug() << "saveClipImages(): Trying to open the saved images"; for(int i=0; i< list.count(); i++) { QString fname = path + QString("%1-%2.jpg").arg(id_article).arg(i+1); QFile file(fname); if( !file.open(QFile::ReadOnly) ) { qDebug() << "saveClipImages(): Image " << fname << " DOES not open, reason: " << file.errorString(); ret= false; break; } else qDebug() << "saveClipImages(): Image " << fname << " opens OK"; file.close(); } */ if(ret) { Article::updateImagesNumber(m_clipDatabase, id_article, list.count()); Article::updateStatus(m_clipDatabase, id_article, 2); qDebug("saveClipImages(): Everything is OK for article %d, updating the status =2 and images number = %d", id_article, list.count()); g_clipMutex.unlock(); return id_article; } //if error happens, return to preclip, if pre-clip, or delete it from clipping Article::updateImagesNumber(m_clipDatabase, id_article, 0); qDebug("saveClipImages(): Error happend for article %d. roll back to original values", id_article); g_clipMutex.unlock(); return 0; } bool ClippingStation::saveClipImagesToFtpServer (QString ¤tIssue, int &id_article, QList &list, bool fromPreclip, QSqlDatabase &database) { QString path = SystemConfiguration::clippingsPath(); QStringList dateSplit = currentIssue.split("-"); path = path + QString("%1/%2/%3/").arg(dateSplit[0], 4, QChar('0')).arg(dateSplit[1], 2, QChar('0')).arg(dateSplit[2], 2, QChar('0')); CURL *curlhandle = NULL; //the libcurl easy handle path = QString("ftp://%1:%2@%3/").arg(m_username).arg(m_password).arg(m_address) + path; curl_global_init(CURL_GLOBAL_ALL); //initate it curlhandle = curl_easy_init(); bool ret = true; char str[255]; saveClipImagesToFtpServerErrorMsg = ""; for(int i=0; i< list.count(); i++) { QString tmpfilename = QString("%1-%2.jpg").arg(id_article).arg(i+1); QString filename = path + tmpfilename; if( list[i].save(tmpfilename, "jpg", 100) ) { ret = upload(curlhandle, filename.toLocal8Bit(), tmpfilename.toLocal8Bit(), 0, 3, str); if(!ret) { qDebug() << "saveClipImagesToFtpServer(): Error uploading image " << filename.toLocal8Bit() << ": " << str; QFile::remove(tmpfilename); saveClipImagesToFtpServerErrorMsg = str; ret = false; break; } QFile::remove(tmpfilename); } else { ret = false; break; } } //now save the thumbnail image as well { QString tmpfilename = QString("%1_thumb.jpg").arg(id_article); QString filename = path + tmpfilename; if( m_thumbnail.save(tmpfilename, "jpg", 100) ) { ret = upload(curlhandle, filename.toLocal8Bit(), tmpfilename.toLocal8Bit(), 0, 3, str); if(!ret) { qDebug() << "saveClipImagesToFtpServer(): Error uploading image " << filename.toLocal8Bit() << ": " << str; QFile::remove(tmpfilename); saveClipImagesToFtpServerErrorMsg = str; //ret = false; //break; } QFile::remove(tmpfilename); } } if(ret) return true; if(fromPreclip) Article::updateStatus(database, id_article, 1); else Article::deleteArticle(database, id_article); return false; } bool ClippingStation::addTextToClip(int id_article, QList &list, QSqlDatabase &database, bool isArabic) { //first, get the words from database, and then get the text and add it to database. qDebug() << "addTextToClip()"; QStringList pages = ImageCutout::fullPages(list); QHash > wcHash; for(int i=0; i< pages.count(); i++) { QList wc = loadImageText(pages[i], database); qDebug("word counts = %d", wc.count()); wcHash.insert(pages[i], wc); } QString headline = ""; //now get coordinates of the text QString text = ""; for(int i=0; i< list.count(); i++) { QString pagename = list[i]->pageName(); QString t = getTextFromCutout( list[i]->boundingRect().toRect(), wcHash.value(pagename) ); text+= t + " "; if(list[i]->areaType() == TITLE) headline += t + " "; } qDebug() << "addTextToClip() headline is : " << headline; qDebug() << "addTextToClip() Text is : " << text; //now add the text to clip. Article::updateText(database, id_article, text); if(headline.trimmed().isEmpty()) { int index = text.indexOf("\n"); if(index > -1 && index < text.length()) headline = text.left(index); else headline = text.left(100).trimmed(); qDebug() << "addTextToClip() new headline is : " << headline; } if(!headline.trimmed().isEmpty()) Article::updateHeadline(database, id_article, headline, isArabic); qDebug() << "end of addTextToClip()"; return true; } QString ClippingStation::getTextFromCutout( QRect rect, QList wc ) { QStringList words; for(int i=0; ideleteArticleFromView(ui->clipsTreeView, m_currentClipId, false); drawerResetPages(); //remove the cutouts ui->fullpageView->removeImageCutouts(); } } void ClippingStation::thumbnail() { //first restore the page to its original size, then take the screenshot if ( m_firstPageInClip.isEmpty() ) { if (m_runningMode == PRECLIPPING_MODE ) m_firstPageInClip = m_preclippedLocalImagesList [m_preclippedImageIndex]; else if (m_runningMode == NORMAL_MODE ) m_firstPageInClip = m_localImagesList [m_imageIndex ]; else if (m_runningMode == CLIPPING_MODE ) m_firstPageInClip = m_clippedLocalImagesList [m_clippedImageIndex ]; } QString currentPage; if (m_runningMode == PRECLIPPING_MODE ) currentPage = m_preclippedLocalImagesList [m_preclippedImageIndex]; else if (m_runningMode == NORMAL_MODE ) currentPage = m_localImagesList [m_imageIndex ]; else if (m_runningMode == CLIPPING_MODE ) currentPage = m_clippedLocalImagesList [m_clippedImageIndex ]; if ( m_firstPageInClip == currentPage) { qreal oldscale = ui->fullpageView->actualSize(); QImage img = ui->fullpageView->screenShot(); ui->fullpageView->setScale(oldscale); img = img.scaledToWidth(THUMBNAIL_WIDTH, Qt::SmoothTransformation); m_thumbnail = img; DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(0)); view->addThumbnail(img); } } void ClippingStation::createThumbnail() { thumbnail(); } qreal ClippingStation::A4Scale() { int i = ui->stackedDrawerViewWidget->currentIndex(); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); m_currentA4Scale = view->currentScale(); return m_currentA4Scale; } void ClippingStation::enableDrawerButtons(bool enable) { ui->addPageButton ->setEnabled(enable); ui->removePageButton ->setEnabled(enable); ui->clipButton ->setEnabled(enable); ui->rejectButton ->setEnabled(!enable); } void ClippingStation::setModifyClipButton(bool modify) { ui->clipButton->setEnabled(true); if(modify) ui->clipButton->setText(tr("Modify")); else ui->clipButton->setText(tr("Clip")); } void ClippingStation::setModifyPreclipButton(bool modify) { if(modify) { ui->preclipButton->setText(tr("Modify")); ui->cancelModifyPreclipButton->setVisible(true); } else { ui->preclipButton->setText(tr("Preclip")); ui->cancelModifyPreclipButton->setVisible(false); } } void ClippingStation::cancelModifyPreclip() { qDebug("cancelModifyPreclip()"); setModifyPreclipButton(false); loadImage(); } void ClippingStation::loadFilteredPublication(int index) { if( index == 0 ) { m_filterMode = NO_FILTER; m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); return; } else if( index == 1) { m_filterMode = PRECLIPSONLY_FILTER; m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); QStringList list = Publication::publicationsWithPreclips(m_slaveDatabase); list.insert(0, ""); ui->preclippedPublicationComboBox->clear(); ui->preclippedPublicationComboBox->addItems(list); } else if(index == 2) { m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); } else if(index == 3) { m_filterMode = NO_FILTER; m_publication.initalizeViews(ui->issuesTreeView, ui->clipsTreeView); QStringList list = Publication::publicationsWithUndoneIssues(m_slaveDatabase); list.insert(0, ""); ui->undonePublicationComboBox->clear(); ui->undonePublicationComboBox->addItems(list); } } void ClippingStation::loadClippingImages(int clipid) { qDebug("loadClippingImages()"); //get the number of a4 images for this clip, in addition to the path QString path = SystemConfiguration::clippingsPath(); QStringList dateSplit = m_currentIssueDate.split("-"); path = path + QString("%1/%2/%3/").arg(dateSplit[0], 4, QChar('0')).arg(dateSplit[1], 2, QChar('0')).arg(dateSplit[2], 2, QChar('0')); CURL *curlhandle = NULL; //the libcurl easy handle if( m_useFtp) { path = QString("ftp://%1:%2@%3/").arg(m_username).arg(m_password).arg(m_address) + path; curl_global_init(CURL_GLOBAL_ALL); //initate it curlhandle = curl_easy_init(); } else { #ifdef Q_WS_WIN path = SystemConfiguration::clippingsWindowsDriveLetter() + path; #endif } drawerResetPages(); int count = m_publication.currentIssue()->clip(clipid).imagesNumber(); //get number of clipped images char str[255]; for(int i=0; i< count -1 ; i++) //add pages drawerAddPage(false); for(int i=0; i< count; i++) { QString tmpfilename = QString("%1-%2.jpg").arg(clipid).arg(i+1); DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); if(m_useFtp) { QString file = path+ tmpfilename; if (!download(curlhandle, file.toLocal8Bit(), tmpfilename.toLocal8Bit(), 0, 3, str)) { qDebug() << "loadClippingImages(): Error loading image " << file.toLocal8Bit() << ": " << str; QMessageBox::critical(this, "error loading clip", QString("Ftp Error (%1) : %2").arg(file).arg(str) ); } else { view->setPixmap(QPixmap(tmpfilename)); QFile::remove(tmpfilename); } } else { QString fname = path+ tmpfilename; view->setPixmap(QPixmap(fname)); } } ui->stackedDrawerViewWidget->setCurrentIndex(0); updateDrawerPageInformation(); enableDrawerButtons(false); setModifyClipButton(true); } int ClippingStation::totalNumberOfCutoutsInDrawer() { int count = 0; for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); count += view->cutoutsCount(); } return count; } QStringList ClippingStation::emptyDrawerPages() { QStringList pages; for (int i=0; i < ui->stackedDrawerViewWidget->count(); i++) { DrawerView* view = static_cast(ui->stackedDrawerViewWidget->widget(i)); int count = view->cutoutsCount(); if(count == 0) pages.append( QString("%1").arg(i+1) ); } return pages; } void ClippingStation::orderCutoutsSelections() { ui->fullpageView->setOrderMode( ui->orderButton->isChecked() ); ui->preclipButton->setEnabled( !ui->orderButton->isChecked() ); ui->autoArrangeButton->setEnabled(!ui->orderButton->isChecked() ); } void ClippingStation::addMargintoPos(QPointF &pos, bool isfirst) { int dpi = QApplication::primaryScreen()->logicalDotsPerInchX(); MarginValues mv; if(isfirst) mv = SystemConfiguration::firstPageMargin(); else mv = SystemConfiguration::otherPagesMargin(); qreal left = mv.left * dpi / 2.54; qreal top = mv.top * dpi / 2.54; pos.setX( pos.x() + left ); pos.setY( pos.y() + top ); } void ClippingStation::orderList(QList &cutouts) { for(int i=0; i< cutouts.count() -1 ; i++) { int min = i; for(int j=i+1 ; j< cutouts.count(); j++) { if(cutouts[min]->order() > cutouts[j]->order()) min = j; } if(min != i) cutouts.swapItemsAt(i, min); } } QSizeF ClippingStation::A4CellSize(bool isfirst) { // we compute pixels dimensions for the page. int dpi = QApplication::primaryScreen()->logicalDotsPerInchX(); qreal pageWidth = dpi * A4_WIDTH; qreal pageHeight = dpi * A4_HEIGHT; MarginValues mv ; if(isfirst) mv = SystemConfiguration::firstPageMargin(); else mv = SystemConfiguration::otherPagesMargin(); qreal m_top = mv.top * dpi / 2.54; qreal m_bottom = mv.bottom * dpi / 2.54; qreal m_left = mv.left * dpi / 2.54; qreal m_right = mv.right * dpi / 2.54; qreal w = pageWidth - (m_left + m_right); qreal h = pageHeight - (m_top + m_bottom); w /= 100.0; h /= 100.0; return QSizeF(w, h); } bool ClippingStation::calculatePosAndScale(QSizeF cellSize, QImage &img, int type, bool resetarray, QPointF &pos, qreal &scale) { #define CELLROWS 100 #define CELLCOLS 100 scale = 1.0; static int cells[CELLROWS][CELLCOLS] = {0}; if(resetarray) { for(int j=0; j< CELLROWS; j++) for(int i=0; i= minScale) { qreal width = img.width() * scale; qreal height= img.height()* scale; qreal hw = width / cellSize.width(); qreal hl = height / cellSize.height(); qreal horizentalCells = ceil(hw); qreal verticalCells = ceil(hl); bool isArabic = (m_publication.language() == "Arabic"); if(isArabic) { for(int row =CELLROWS-1; row >=0; row--) { for(int col=0; col = CELLCOLS) { valid = false; break; } if(cells[row][col+i] == 0) continue; valid = false; break; } if(!valid) continue; for(int i=0; i < horizentalCells; i++) { if(row+i >= CELLROWS) { valid = false; break; } if(cells[row+i][col] == 0) continue; valid = false; break; } if(!valid) continue; //now check the internal cells for(int i=0; i= CELLCOLS) { valid = false; break; } if(cells[row][col+i] == 0) continue; valid = false; break; } if(!valid) continue; for(int i=0; i < horizentalCells; i++) { if(row+i >= CELLROWS) { valid = false; break; } if(cells[row+i][col] == 0) continue; valid = false; break; } if(!valid) continue; //now check the internal cells for(int i=0; iid(); int id_section = m_publication.currentIssue()->section(m_currentSectionName).id(); QFileInfo fi(image); QString page_name = fi.fileName(); QSqlQuery query(m_slaveDatabase); bool ret = query.exec("LOCK TABLES publication_issue as pub issue_sections as iss section_pages as sec READ"); query.prepare("SELECT locked_by FROM publication_issue as pub, issue_sections as iss, section_pages as sec WHERE " " pub.id_publication_issue = iss.id_publication_issue AND " " iss.id_issue_sections = sec.id_issue_sections AND " " pub.id_publication = :id_publication AND " " pub.id_issue = :id_issue AND " " iss.id_section = :id_section AND " " sec.page_name = :page_name"); query.bindValue(":id_publication", id_publication); query.bindValue(":id_issue", id_issue); query.bindValue(":id_section", id_section); query.bindValue(":page_name", page_name); if ( !query.exec() ) { qDebug() << "isImageLocked() SQL query Error :" << query.lastError().databaseText().toLocal8Bit(); qDebug("%d\t%d\t%d", id_publication, id_issue, id_section); qDebug() << page_name; ret = query.exec("UNLOCK TABLES"); return false; } int user_id = 0; if( query.next() ) user_id = query.value(0).toInt(); query.exec("UNLOCK TABLES"); double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("isImageLocked() Time: %f", diff); if(user_id != 0 && user_id != m_user.id() ) { lockedBy = user_id; return true; } return false; } bool ClippingStation::lockImage(QString image) { clock_t start = clock(); unlockImages(); int id_publication = m_publication.id(); int id_issue = m_publication.currentIssue()->id(); int id_section = m_publication.currentIssue()->section(m_currentSectionName).id(); int id_user = m_user.id(); QFileInfo fi(image); QString page_name = fi.fileName(); QSqlQuery query(m_slaveDatabase); bool ret = query.exec("LOCK TABLES publication_issue AS pub READ, section_pages AS sec WRITE, issue_sections AS iss READ"); query.prepare("UPDATE publication_issue as pub, issue_sections as iss, section_pages as sec " " SET locked_by = :id_user " " WHERE " " pub.id_publication_issue = iss.id_publication_issue AND " " iss.id_issue_sections = sec.id_issue_sections AND " " pub.id_publication = :id_publication AND " " pub.id_issue = :id_issue AND " " iss.id_section = :id_section AND " " sec.page_name = :page_name"); query.bindValue(":id_publication", id_publication); query.bindValue(":id_issue", id_issue); query.bindValue(":id_section", id_section); query.bindValue(":page_name", page_name); query.bindValue(":id_user", id_user); ret = query.exec(); query.exec("UNLOCK TABLES"); double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("lockImage() Time: %f", diff); return ret; } bool ClippingStation::unlockImages() { clock_t start = clock(); int id_user = m_user.id(); QSqlQuery query(m_slaveDatabase); query.exec("LOCK TABLE section_pages as sec WRITE"); query.prepare("UPDATE section_pages as sec " " SET locked_by = 0 " " WHERE " " sec.locked_by = :id_user "); query.bindValue(":id_user", id_user); bool ret = query.exec(); query.exec("UNLOCK TABLES"); double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("unlockImages() Time: %f", diff); return ret; } int ClippingStation::getImageId(const QString name) { QSqlQuery query2(m_slaveDatabase); query2.prepare("SELECT section_pages FROM " " publication_issue as pub, issue_sections as iss, section_pages as sec " " WHERE " " pub.id_publication_issue = iss.id_publication_issue AND " " iss.id_issue_sections = sec.id_issue_sections AND " " pub.id_publication = :id_publication AND " " pub.id_issue = :id_issue AND " " iss.id_section = :id_section AND " " sec.page_name = :page_name"); query2.bindValue(":id_publication", m_publication.id()); query2.bindValue(":id_issue", m_publication.currentIssue()->id() ); query2.bindValue(":id_section", m_publication.currentIssue()->section(m_currentSectionName).id() ); query2.bindValue(":page_name", name); if ( !query2.exec() ) { qDebug() << "Error in slave db query " << query2.lastQuery().toLocal8Bit(); qDebug() << "Error is " << query2.lastError().text(); return -1; } int id = 0; while(query2.next() ) id = query2.value(0).toInt(); return id; } void ClippingStation::loadImageHighlights(int imageId) { clock_t start = clock(); QSqlQuery query(m_ocrDatabase); query.prepare("SELECT id_company, coordinates, tag FROM " " page_tag_coordinates " " WHERE " " id_section_pages = :id "); query.bindValue(":id", imageId); if ( !query.exec() ) { qDebug() << "Error in ocr db query " << query.lastQuery().toLocal8Bit(); qDebug() << "Error is " << query.lastError().text(); return; } QList tagH; qDebug() << "retreive the results of page_tag_coordiantes"; while( query.next() ) { int tagId = query.value(0).toInt(); QStringList coor = query.value(1).toString().split(":"); QStringList crd = coor[0].split(","); int top = crd[0].toInt(); int left = crd[1].toInt(); int bottom =crd[2].toInt(); int right =crd[3].toInt(); QString tag = query.value(2).toString(); TagCoordinates t(tagId, top, left, bottom, right, tag); for(int i=1; i< coor.count(); i++) { QStringList crd = coor[i].split(","); int top = crd[0].toInt(); int left = crd[1].toInt(); int bottom =crd[2].toInt(); int right =crd[3].toInt(); //QRectF rec(QPointF(left, top), QPointF(right, bottom) ); //QPolygonF ply(rec); //ui->fullpageView->createTagsHighlightes(ply); t.AddCoordinates(top, left, bottom, right); } tagH.append(t); } qDebug() << "End get info from page_tag_coordinates" << Qt::endl; //QTimer::singleShot(100, this, SLOT(addRelatedKeywordsToTag(tagH))); //we add the name to the tags /*QSqlQuery query2(m_slaveDatabase); query2.prepare("SELECT name_company FROM company AS cm, searchword AS sw " " WHERE name_searchword LIKE :name1 AND sw.id_company = cm.id_company AND cm.date_end > NOW() " " UNION SELECT name_company FROM company WHERE name_company LIKE :name2 AND date_end > NOW()"); for(int i=0; i< tagH.count(); i++) { qDebug() << "Searching for tag: " << tagH[i].tag(); query2.bindValue(":name1", tagH[i].tag() ); query2.bindValue(":name2", tagH[i].tag() ); if(query2.exec()) { QStringList keywords; while(query2.next()) { QString name = query2.value(0).toString(); qDebug() << "related tag: " << name; keywords.append(name); } qDebug() << "for tag " << tagH[i].tag() << ", the number of related keyword is " << keywords.count(); tagH[i].setRelatedKeywords(keywords); } }*/ ui->fullpageView->addTagCoordinates(tagH); double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("loadImageHighlights() Time: %f", diff); } void ClippingStation::addRelatedKeywordsToTag(QList &tagH) { qDebug() << "addRelatedKeywordsToTag()"; QSqlQuery query2(m_slaveDatabase); query2.prepare("SELECT name_company FROM company AS cm, searchword AS sw " " WHERE name_searchword LIKE :name1 AND sw.id_company = cm.id_company AND cm.date_end > NOW() " " UNION SELECT name_company FROM company WHERE name_company LIKE :name2 AND date_end > NOW()"); for(int i=0; i< tagH.count(); i++) { qDebug() << "Searching for tag: " << tagH[i].tag(); query2.bindValue(":name1", tagH[i].tag() ); query2.bindValue(":name2", tagH[i].tag() ); if(query2.exec()) { QStringList keywords; while(query2.next()) { QString name = query2.value(0).toString(); qDebug() << "related tag: " << name; keywords.append(name); } qDebug() << "for tag " << tagH[i].tag() << ", the number of related keyword is " << keywords.count(); tagH[i].setRelatedKeywords(keywords); } } ui->fullpageView->addTagCoordinates(tagH); qDebug() << "end of addRelatedKeywordsToTag()"; } QList ClippingStation::loadImageText(QString page, QSqlDatabase &database) { qDebug() << "loadImageText(QString page, QSqlDatabase &database)"; clock_t start = clock(); QStringList list = page.split("/"); QString id_issue = list[list.count()-6] + list[list.count()-5]+ list[list.count()-4]; QString page_name = list[list.count()-1]; int id_section = list[list.count()-2].toInt(); int id_publication = list[list.count()-3].toInt(); QSqlQuery query(database); query.prepare("SELECT section_pages FROM " " publication_issue as pub, issue_sections as iss, section_pages as sec " " WHERE " " pub.id_publication_issue = iss.id_publication_issue AND " " iss.id_issue_sections = sec.id_issue_sections AND " " pub.id_publication = :id_publication AND " " pub.id_issue = :id_issue AND " " iss.id_section = :id_section AND " " sec.page_name = :page_name"); query.bindValue(":id_publication", id_publication); query.bindValue(":id_issue", id_issue ); query.bindValue(":id_section", id_section ); query.bindValue(":page_name", page_name); int section_pages = 0; QList tagW; if (!query.exec()) { qDebug() << query.lastError().text().toLocal8Bit(); return tagW; } if(query.next()) section_pages = query.value(0).toInt(); QSqlQuery query2(m_ocrDatabase); query2.prepare("SELECT word, coordinates FROM " " page_word_coordinates" " WHERE " " id_section_pages = :id " " order by id_page_word_coordinates"); query2.bindValue(":id", section_pages); if ( !query2.exec() ) { qDebug() << query2.lastError().text().toLocal8Bit(); return tagW; } while( query2.next() ) { QString word = query2.value(0).toString(); qDebug() << "word is " << word; QStringList coor = query2.value(1).toString().split(":"); QStringList crd = coor[0].split(","); int top = crd[0].toInt(); int left = crd[1].toInt(); int bottom =crd[2].toInt(); int right =crd[3].toInt(); WordCoordinates t(word, top, left, bottom, right); tagW.append(t); } //ui->fullpageView->addWordCoordinates(tagW); double diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; qDebug("loadImageText() Time: %f", diff); return tagW; } void ClippingStation::addTagsToTagWrapper(QList &tagIds, QStringList tagCoord, bool removedAndThenAdd) { QList tags = Tag::searchTags(m_slaveDatabase, tagIds); for(int i=0; i< tags.count(); i++) { if(tags[i].id() == tagIds[i]) tags[i].setCoordinates(tagCoord[i]); } if(removedAndThenAdd) m_tagsWrapper.removedOcrTags(tags); else m_tagsWrapper.appenedOcrTags(tags); m_tagsWrapper.showModel(); } void ClippingStation::updateSectionPagesStatus() { QAbstractItemModel* model = ui->issuesTreeView->model(); int issuesCount = model->rowCount( QModelIndex() ); for(int i=0; i< issuesCount; i++) { if(m_currentIssueDate.isEmpty()) return; QString issue = model->index(i, 0, QModelIndex() ).data(Qt::DisplayRole).toString(); if(issue != m_currentIssueDate) //get current issue continue; QModelIndex issueIndex = model->index(i, 0, QModelIndex() ); int sectionsCount = model->rowCount(issueIndex); for(int j=0; j < sectionsCount; j++) { //get pages status for this particular section from database. //the data is returned as mab (name, status); QString section = model->index(j, 0, issueIndex).data(Qt::DisplayRole).toString(); int sectionId = m_publication.currentIssue()->section(section).id(); QHash hash = currentSectionPagesStatus(sectionId); QModelIndex sectionIndex = model->index(j, 0, issueIndex); int pagesCount = model->rowCount(sectionIndex); for(int k=0; k< pagesCount; k++) { QString pageName = model->index(k, 0, sectionIndex).data(Qt::DisplayRole).toString(); pageName = QString("%1.jpg").arg(pageName.remove(QRegularExpression("[^\\d]")), 4, QChar('0')); QModelIndex pageIndex = model->index(k, 0, sectionIndex); if( hash.find(pageName) != hash.end() ) model->setData(pageIndex, QVariant(hash[pageName]) , Qt::DecorationRole); } } } } QHash ClippingStation::currentSectionPagesStatus(int sectionId) { QHash hash; QSqlQuery query(m_masterDatabase); query.prepare("SELECT id_issue_sections FROM issue_sections, publication_issue " "WHERE publication_issue.id_publication_issue = issue_sections.id_publication_issue AND " "id_publication = :id_publication AND issue_date = :issue_date AND id_section = :id_section"); query.bindValue(":id_publication", m_publication.id() ); query.bindValue(":issue_date", m_publication.currentIssue()->date() ); query.bindValue(":id_section", sectionId); if(! query.exec() ) return hash; int id_issue_sections = 0; if( query.next()) id_issue_sections = query.value(0).toInt(); query.exec("LOCK TABLE section_pages READ"); query.prepare("SELECT page_name, status FROM section_pages " "WHERE id_issue_sections = :id_issue_sections ORDER BY page_name"); query.bindValue(":id_issue_sections", id_issue_sections); if ( !query.exec() ) { query.exec("UNLOCK TABLES"); return hash; } while ( query.next() ) { QString filename = query.value(0).toString(); int status = query.value(1).toInt(); QIcon icon; if(status < 1) //not processed icon.addFile(":/icons/no_icon.png"); else if (status == 1 ) //waiting to be processed icon.addFile(":/icons/gray_circle.png"); else if (status == 2 ) //being procssed icon.addFile(":/icons/yellow_circle.png"); else //finished processing icon.addFile(":/icons/green_circle.png"); hash.insert(filename, icon); } query.exec("UNLOCK TABLES"); return hash; } void ClippingStation::filterPublications() { if(m_searchPublicationsDlg.exec() == QDialog::Accepted ) { //get the values from the QString keyword, startDate, endDate, type, country, ocrSearchword, status; bool ischecked; m_searchPublicationsDlg.get(keyword, ischecked, startDate, endDate, type, country, ocrSearchword, status); //now search for the publications that meet those criteria int countryId = -1; if(!country.isEmpty()) countryId = m_countriesHash[country]; int typeId = -1; if(!type.isEmpty()) { if(type.compare("newspaper", Qt::CaseInsensitive) == 0) //NEWSPAPER 1 typeId = 1; else if(type.compare("magazine", Qt::CaseInsensitive) == 0) typeId = 2; } QStringList list = m_publication.publicationsFiltered(m_slaveDatabase, m_ocrDatabase, keyword, startDate, endDate, typeId, countryId, ocrSearchword, status); list.insert(0, ""); ui->filteredPublicationComboBox->clear(); ui->filteredPublicationComboBox->addItems(list); } } void ClippingStation::setShortcuts() { if( !m_clipShortcut.isEmpty() ) ui->actionClip->setShortcut(m_clipShortcut); if( !m_preclipShortcut.isEmpty() ) ui->actionPreclip->setShortcut(m_preclipShortcut); if( !m_addPageShortcut.isEmpty() ) ui->actionDrawerAddPage->setShortcut(m_addPageShortcut); if( !m_nextPageShortcut.isEmpty() ) ui->actionNextPage->setShortcut(m_nextPageShortcut); if( !m_previousPageShortcut.isEmpty() ) ui->actionPreviousPage->setShortcut(m_previousPageShortcut); } void ClippingStation::pauseTracking() { if(m_currentPageId <= 0) return; if(m_isPaused) { //resume ui->fullpageView->setImageVisibility(true); m_trackingTimer.start(1000); ui->pauseTrackButton->setText(tr("Pause Tracking")); m_isPaused = false; } else { ui->fullpageView->setImageVisibility(false); m_trackingTimer.stop(); ui->pauseTrackButton->setText(tr("Resume Tracking")); m_isPaused = true; } } void ClippingStation::updateTrackLabel() { ui->lcdCounter->showTime(++m_trackingSeconds); if((m_trackingSeconds % m_maxTimeLimit) == 0) { if(!m_isPaused) pauseTracking(); } } int ClippingStation::publicationIssueId(int id_publication, QString issue_date) { QSqlQuery query(m_slaveDatabase); query.prepare("SELECT id_publication_issue FROM publication_issue " "WHERE id_publication = :id_publication AND issue_date = :issue_date"); query.bindValue(":id_publication", id_publication); query.bindValue(":issue_date", issue_date); if(!query.exec()) { qDebug() << "select id_publication_issue query error: " << query.lastError().text(); qDebug() << "returning 0"; return 0; } int id_publication_issue = 0; if(query.next()) { id_publication_issue = query.value(0).toInt(); return id_publication_issue; } return id_publication_issue; } int ClippingStation::issueSectionsId(int id_publication_issue, int id_section) { QSqlQuery query(m_slaveDatabase); query.prepare("SELECT id_issue_sections FROM issue_sections WHERE " "id_publication_issue = :id_publication_issue AND id_section = :id_section"); query.bindValue(":id_publication_issue", id_publication_issue); query.bindValue(":id_section", id_section); if ( !query.exec() ) { qDebug() << "select id_issue_sections query error: " << query.lastError().text(); qDebug() << "returning 0"; return 0; } int id_issue_sections = 0; if( query.next() ) id_issue_sections = query.value(0).toInt(); return id_issue_sections; } QStringList ClippingStation::getRelatedKeywords(QString tag) { QSqlQuery query2(m_slaveDatabase); query2.prepare("SELECT name_company FROM company AS cm, searchword AS sw " " WHERE name_searchword LIKE :name1 AND sw.id_company = cm.id_company AND cm.date_end > NOW() " " UNION SELECT name_company FROM company WHERE name_company LIKE :name2 AND date_end > NOW()"); qDebug() << "Searching for tag: " << tag; query2.bindValue(":name1", tag ); query2.bindValue(":name2", tag ); QStringList keywords; if(query2.exec()) { while(query2.next()) { QString name = query2.value(0).toString(); qDebug() << "related tag: " << name; keywords.append(name); } qDebug() << "for tag " << tag << ", the number of related keyword is " << keywords.count(); } return keywords; } void ClippingStation::onAppFocusChanged() { if(m_currentPageId <= 0) //no pages has been opened yet return; if(QApplication::focusWidget()) { if(m_isPaused) //if its pause, return without doing anything return; ui->fullpageView->setImageVisibility(true); m_trackingTimer.start(1000); } else { ui->fullpageView->setImageVisibility(false); m_trackingTimer.stop(); } }