Work on enclosures, only editing of skins remains.
This commit is contained in:
		
							parent
							
								
									21f970d456
								
							
						
					
					
						commit
						8c1414c3df
					
				
					 12 changed files with 109 additions and 81 deletions
				
			
		|  | @ -444,19 +444,6 @@ bool FeedsModelFeed::removeItself() { | |||
|   return query_remove.exec(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * postup zpracování zpráv: | ||||
|  * 1. Kontrola, zda existují již v DB zprávy se stejným NAZVEM, AUTOREM, URL ze stejneho kanalu. | ||||
|  *  a. KONEC: Pokud neexistují, pak se aktuální nová zpráva přidá do DB. | ||||
|  *  b. Pokud existují, jde se na krok 2. | ||||
|  * 2. Pokud má uživatel nastaveno mazání duplicitních zpráv, pak udělej a. Jinak jdi na krok 3. | ||||
|  *  a. Vymaž všechny zprávy, které byly nalezeny ve kroku 1. | ||||
|  *  b. Přidej tuto novou zprávu, nastav ji status přečtena na true. | ||||
|  * 3. Uživatel nemá nastaveno mazani dupl zpráv. Novou zprávu přidáme do DB tehdy když zpráva | ||||
|  * má datum získané z kanálu a zároveň identická zpráva s takovým datumem ještě v DB není. | ||||
|  * */ | ||||
| 
 | ||||
| 
 | ||||
| void FeedsModelFeed::updateMessages(const QList<Message> &messages) { | ||||
|   int feed_id = id(); | ||||
|   QSqlDatabase database = qApp->database()->connection("FeedsModelFeed", DatabaseFactory::FromSettings); | ||||
|  | @ -476,12 +463,12 @@ void FeedsModelFeed::updateMessages(const QList<Message> &messages) { | |||
|   // Used to insert new messages.
 | ||||
|   query_insert.setForwardOnly(true); | ||||
|   query_insert.prepare("INSERT INTO Messages " | ||||
|                        "(feed, title, url, author, date_created, contents) " | ||||
|                        "VALUES (:feed, :title, :url, :author, :date_created, :contents);"); | ||||
|                        "(feed, title, url, author, date_created, contents, enclosures) " | ||||
|                        "VALUES (:feed, :title, :url, :author, :date_created, :contents, :enclosures);"); | ||||
| 
 | ||||
|   if (remove_duplicates) { | ||||
|     query_update.setForwardOnly(true); | ||||
|     query_update.prepare("UPDATE Messages SET contents = :contents WHERE id = :id;"); | ||||
|     query_update.prepare("UPDATE Messages SET contents = :contents enclosures = :enclosures WHERE id = :id;"); | ||||
|   } | ||||
| 
 | ||||
|   if (!database.transaction()) { | ||||
|  | @ -528,6 +515,7 @@ void FeedsModelFeed::updateMessages(const QList<Message> &messages) { | |||
|       query_insert.bindValue(":author", message.m_author); | ||||
|       query_insert.bindValue(":date_created", message.m_created.toMSecsSinceEpoch()); | ||||
|       query_insert.bindValue(":contents", message.m_contents); | ||||
|       query_insert.bindValue(":enclosures", Enclosures::encodeEnclosuresToString(message.m_enclosures)); | ||||
| 
 | ||||
|       if (query_insert.exec() && query_insert.numRowsAffected() == 1) { | ||||
|         setStatus(NewMessages); | ||||
|  | @ -543,6 +531,7 @@ void FeedsModelFeed::updateMessages(const QList<Message> &messages) { | |||
|         // messages and there is exactly ONE existing duplicate.
 | ||||
|         query_update.bindValue(":id", ids.at(0)); | ||||
|         query_update.bindValue(":contents", message.m_contents); | ||||
|         query_update.bindValue(":enclosures", Enclosures::encodeEnclosuresToString(message.m_enclosures)); | ||||
|         query_update.exec(); | ||||
|         query_update.finish(); | ||||
| 
 | ||||
|  | @ -557,6 +546,7 @@ void FeedsModelFeed::updateMessages(const QList<Message> &messages) { | |||
|         query_insert.bindValue(":author", message.m_author); | ||||
|         query_insert.bindValue(":date_created", message.m_created.toMSecsSinceEpoch()); | ||||
|         query_insert.bindValue(":contents", message.m_contents); | ||||
|         query_insert.bindValue(":enclosures", Enclosures::encodeEnclosuresToString(message.m_enclosures)); | ||||
| 
 | ||||
|         if (query_insert.exec() && query_insert.numRowsAffected() == 1) { | ||||
|           setStatus(NewMessages); | ||||
|  |  | |||
|  | @ -132,6 +132,7 @@ Message MessagesModel::messageAt(int row_index) const { | |||
|   // Fill Message object with details.
 | ||||
|   message.m_author = rec.value(MSG_DB_AUTHOR_INDEX).toString(); | ||||
|   message.m_contents = rec.value(MSG_DB_CONTENTS_INDEX).toString(); | ||||
|   message.m_enclosures = Enclosures::decodeEnclosuresFromString(rec.value(MSG_DB_ENCLOSURES_INDEX).toString()); | ||||
|   message.m_title = rec.value(MSG_DB_TITLE_INDEX).toString(); | ||||
|   message.m_url = rec.value(MSG_DB_URL_INDEX).toString(); | ||||
|   message.m_created = TextFactory::parseDateTime(rec.value(MSG_DB_DCREATED_INDEX).value<qint64>()).toLocalTime(); | ||||
|  |  | |||
|  | @ -27,27 +27,27 @@ | |||
| 
 | ||||
| 
 | ||||
| // Represents single enclosure.
 | ||||
| class Enclosure { | ||||
| class Enclosures { | ||||
|   public: | ||||
|     explicit Enclosure() { | ||||
|       m_url = m_title = ""; | ||||
|     } | ||||
| 
 | ||||
|     static QList<Enclosure> decodeEnclosuresFromString(const QString &enclosures_data) { | ||||
|       QList<Enclosure> enclosures; | ||||
|     static QStringList decodeEnclosuresFromString(const QString &enclosures_data) { | ||||
|       QStringList enclosures; | ||||
| 
 | ||||
|       foreach (const QString &single_enclosure, enclosures_data.split(ENCLOSURES_OUTER_SEPARATOR, QString::SkipEmptyParts)) { | ||||
|         Enclosure final_enclosure; | ||||
|         final_enclosure.m_url = QByteArray::fromBase64(single_enclosure.toUtf8()); | ||||
| 
 | ||||
|         enclosures.append(final_enclosure); | ||||
|         enclosures.append(QByteArray::fromBase64(single_enclosure.toLocal8Bit())); | ||||
|       } | ||||
| 
 | ||||
|       return enclosures; | ||||
|     } | ||||
| 
 | ||||
|     QString m_url; | ||||
|     QString m_title; | ||||
|     static QString encodeEnclosuresToString(const QStringList &enclosures) { | ||||
|       QStringList enclosures_str; | ||||
| 
 | ||||
|       foreach (const QString &enclosure, enclosures) { | ||||
|         enclosures_str.append(enclosure.toLocal8Bit().toBase64()); | ||||
|       } | ||||
| 
 | ||||
|       return enclosures_str.join(QString(ENCLOSURES_OUTER_SEPARATOR)); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // Represents single message.
 | ||||
|  | @ -55,7 +55,7 @@ class Message { | |||
|   public: | ||||
|     explicit Message() { | ||||
|       m_title = m_url = m_author = m_contents = ""; | ||||
|       m_enclosures = QList<Enclosure>(); | ||||
|       m_enclosures = QStringList(); | ||||
|     } | ||||
| 
 | ||||
|     QString m_title; | ||||
|  | @ -64,7 +64,7 @@ class Message { | |||
|     QString m_contents; | ||||
|     QDateTime m_created; | ||||
| 
 | ||||
|     QList<Enclosure> m_enclosures; | ||||
|     QStringList m_enclosures; | ||||
| 
 | ||||
|     // Is true if "created" date was obtained directly
 | ||||
|     // from the feed, otherwise is false
 | ||||
|  |  | |||
|  | @ -70,12 +70,21 @@ QList<Message> ParsingFactory::parseAsATOM10(const QString &data) { | |||
|     // Deal with link.
 | ||||
|     QDomNodeList elem_links = message_item.toElement().elementsByTagName("link"); | ||||
| 
 | ||||
|     for (int i = 0; i < elem_links.size(); i++) {     | ||||
|       new_message.m_url = elem_links.at(i).attributes().namedItem("href").toAttr().value(); | ||||
|     for (int i = 0; i < elem_links.size(); i++) { | ||||
|       QDomElement link = elem_links.at(i).toElement(); | ||||
| 
 | ||||
|       if (!new_message.m_url.isNull() && !new_message.m_url.isEmpty()) { | ||||
|         break; | ||||
|       if (link.attribute("rel") == "enclosure") { | ||||
|         new_message.m_enclosures.append(link.attribute("href")); | ||||
| 
 | ||||
|         qDebug("Adding enclosure '%s' for the message.", qPrintable(new_message.m_enclosures.last())); | ||||
|       } | ||||
|       else { | ||||
|         new_message.m_url = link.attribute("href"); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (new_message.m_url.isEmpty() && !new_message.m_enclosures.isEmpty()) { | ||||
|       new_message.m_url = new_message.m_enclosures.first(); | ||||
|     } | ||||
| 
 | ||||
|     // Deal with authors.
 | ||||
|  | @ -193,6 +202,7 @@ QList<Message> ParsingFactory::parseAsRSS20(const QString &data) { | |||
|     // Deal with titles & descriptions.
 | ||||
|     QString elem_title = message_item.namedItem("title").toElement().text().simplified(); | ||||
|     QString elem_description = message_item.namedItem("description").toElement().text(); | ||||
|     QString elem_enclosure = message_item.namedItem("enclosure").toElement().attribute("url"); | ||||
| 
 | ||||
|     if (elem_description.isEmpty()) { | ||||
|       elem_description = message_item.namedItem("encoded").toElement().text(); | ||||
|  | @ -216,6 +226,12 @@ QList<Message> ParsingFactory::parseAsRSS20(const QString &data) { | |||
|       new_message.m_contents = elem_description; | ||||
|     } | ||||
| 
 | ||||
|     if (!elem_enclosure.isEmpty()) { | ||||
|       new_message.m_enclosures.append(elem_enclosure); | ||||
| 
 | ||||
|       qDebug("Adding enclosure '%s' for the message.", qPrintable(elem_enclosure)); | ||||
|     } | ||||
| 
 | ||||
|     // Deal with link and author.
 | ||||
|     new_message.m_url = message_item.namedItem("link").toElement().text(); | ||||
|     new_message.m_author = message_item.namedItem("author").toElement().text(); | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget *parent) : QDialo | |||
|   connect(m_ui->m_txtBackupName->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkOkButton())); | ||||
|   connect(m_ui->m_btnSelectFolder, SIGNAL(clicked()), this, SLOT(selectFolder())); | ||||
| 
 | ||||
|   selectFolder(qApp->documentsFolderPath());   | ||||
|   selectFolder(qApp->documentsFolderPath()); | ||||
|   m_ui->m_txtBackupName->lineEdit()->setText(QString(APP_LOW_NAME) + "_" + QDateTime::currentDateTime().toString("yyyyMMddHHmm")); | ||||
|   m_ui->m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet.")); | ||||
| 
 | ||||
|  | @ -56,19 +56,15 @@ FormBackupDatabaseSettings::~FormBackupDatabaseSettings() { | |||
| } | ||||
| 
 | ||||
| void FormBackupDatabaseSettings::performBackup() { | ||||
|   if (qApp->backupDatabaseSettings(m_ui->m_checkBackupDatabase->isChecked(), | ||||
|                                    m_ui->m_checkBackupSettings->isChecked(), | ||||
|                                    m_ui->m_lblSelectFolder->label()->text(), | ||||
|                                    m_ui->m_txtBackupName->lineEdit()->text())) { | ||||
|   try { | ||||
|     qApp->backupDatabaseSettings(m_ui->m_checkBackupDatabase->isChecked(), m_ui->m_checkBackupSettings->isChecked(), | ||||
|                                  m_ui->m_lblSelectFolder->label()->text(), m_ui->m_txtBackupName->lineEdit()->text()); | ||||
|     m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, | ||||
|                                  tr("Backup was created successfully and stored in target folder."), | ||||
|                                  tr("Backup was created successfully.")); | ||||
|   } | ||||
|   else { | ||||
|     m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, | ||||
|                                  tr("Backup failed, database and/or settings is probably not backed."), | ||||
|                                  tr("Backup failed. Check the output folder if your database\nand/or " | ||||
|                                     "settings were backed or not. Also make sure that target foder is writable.")); | ||||
|   catch (ApplicationException &ex) { | ||||
|     m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, ex.message(), tr("Backup failed.")); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ | |||
|    <item> | ||||
|     <widget class="QGroupBox" name="m_groupFile"> | ||||
|      <property name="title"> | ||||
|       <string/> | ||||
|       <string>Output folder</string> | ||||
|      </property> | ||||
|      <layout class="QFormLayout" name="formLayout"> | ||||
|       <item row="0" column="0"> | ||||
|  | @ -125,18 +125,18 @@ | |||
|   </layout> | ||||
|  </widget> | ||||
|  <customwidgets> | ||||
|   <customwidget> | ||||
|    <class>LabelWithStatus</class> | ||||
|    <extends>QWidget</extends> | ||||
|    <header>labelwithstatus.h</header> | ||||
|    <container>1</container> | ||||
|   </customwidget> | ||||
|   <customwidget> | ||||
|    <class>LineEditWithStatus</class> | ||||
|    <extends>QWidget</extends> | ||||
|    <header>lineeditwithstatus.h</header> | ||||
|    <container>1</container> | ||||
|   </customwidget> | ||||
|   <customwidget> | ||||
|    <class>LabelWithStatus</class> | ||||
|    <extends>QWidget</extends> | ||||
|    <header>labelwithstatus.h</header> | ||||
|    <container>1</container> | ||||
|   </customwidget> | ||||
|  </customwidgets> | ||||
|  <resources/> | ||||
|  <connections> | ||||
|  |  | |||
|  | @ -50,20 +50,21 @@ FormRestoreDatabaseSettings::~FormRestoreDatabaseSettings() { | |||
| void FormRestoreDatabaseSettings::performRestoration() { | ||||
|   m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); | ||||
| 
 | ||||
|   if (qApp->restoreDatabaseSettings(m_ui->m_groupDatabase->isChecked(), | ||||
|                                     m_ui->m_groupSettings->isChecked(), | ||||
|                                     m_ui->m_listDatabase->currentRow() >= 0 ? | ||||
|   try { | ||||
|     qApp->restoreDatabaseSettings(m_ui->m_groupDatabase->isChecked(), | ||||
|                                   m_ui->m_groupSettings->isChecked(), | ||||
|                                   m_ui->m_listDatabase->currentRow() >= 0 ? | ||||
|                                     m_ui->m_listDatabase->currentItem()->data(Qt::UserRole).toString() : | ||||
|                                     QString(), | ||||
|                                     m_ui->m_listSettings->currentRow() >= 0 ? | ||||
|                                   m_ui->m_listSettings->currentRow() >= 0 ? | ||||
|                                     m_ui->m_listSettings->currentItem()->data(Qt::UserRole).toString() : | ||||
|                                     QString())) { | ||||
|                                     QString()); | ||||
|     m_btnRestart->setEnabled(true); | ||||
|     m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Restoration was initiated. Restart to proceed."), | ||||
|                                  tr("You need to restart application for restoration process to finish.")); | ||||
|   } | ||||
|   else { | ||||
|     m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Restoration was not initiated successfully."), | ||||
|   catch (ApplicationException &ex) { | ||||
|     m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, ex.message(), | ||||
|                                  tr("Database and/or settings were not copied to restoration folder successully.")); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -56,7 +56,7 @@ | |||
|    <item row="0" column="0" colspan="2"> | ||||
|     <widget class="QGroupBox" name="m_groupFile"> | ||||
|      <property name="title"> | ||||
|       <string/> | ||||
|       <string>Source folder</string> | ||||
|      </property> | ||||
|      <layout class="QFormLayout" name="formLayout"> | ||||
|       <item row="0" column="0"> | ||||
|  |  | |||
|  | @ -44,8 +44,7 @@ WidgetWithStatus::WidgetWithStatus(QWidget *parent) | |||
| WidgetWithStatus::~WidgetWithStatus() { | ||||
| } | ||||
| 
 | ||||
| void WidgetWithStatus::setStatus(WidgetWithStatus::StatusType status, | ||||
|                                  const QString &tooltip_text) { | ||||
| void WidgetWithStatus::setStatus(WidgetWithStatus::StatusType status, const QString &tooltip_text) { | ||||
|   m_status = status; | ||||
| 
 | ||||
|   switch (status) { | ||||
|  |  | |||
|  | @ -72,18 +72,18 @@ DownloadManager *Application::downloadManager() { | |||
|   return m_downloadManager; | ||||
| } | ||||
| 
 | ||||
| bool Application::backupDatabaseSettings(bool backup_database, bool backup_settings, | ||||
| void Application::backupDatabaseSettings(bool backup_database, bool backup_settings, | ||||
|                                          const QString &target_path, const QString &backup_name) { | ||||
|   if (!QFileInfo(target_path).isWritable()) { | ||||
|     return false; | ||||
|     throw ApplicationException(tr("Output folder is not writable.")); | ||||
|   } | ||||
| 
 | ||||
|   bool final_result = true; | ||||
| 
 | ||||
|   if (backup_settings) { | ||||
|     settings()->sync(); | ||||
|     final_result = final_result && IOFactory::copyFile(settings()->fileName(), | ||||
|                                                        target_path + QDir::separator() + backup_name + BACKUP_SUFFIX_SETTINGS); | ||||
| 
 | ||||
|     if (!IOFactory::copyFile(settings()->fileName(), target_path + QDir::separator() + backup_name + BACKUP_SUFFIX_SETTINGS)) { | ||||
|       throw ApplicationException(tr("Settings file not copied to output folder successfully.")); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (backup_database && | ||||
|  | @ -91,26 +91,26 @@ bool Application::backupDatabaseSettings(bool backup_database, bool backup_setti | |||
|        database()->activeDatabaseDriver() == DatabaseFactory::SQLITE_MEMORY)) { | ||||
|     // We need to save the database first.
 | ||||
|     database()->saveDatabase(); | ||||
|     final_result = final_result && IOFactory::copyFile(database()->sqliteDatabaseFilePath(), | ||||
|                                                        target_path + QDir::separator() + backup_name + BACKUP_SUFFIX_DATABASE); | ||||
|   } | ||||
| 
 | ||||
|   return final_result; | ||||
|     if (!IOFactory::copyFile(database()->sqliteDatabaseFilePath(), target_path + QDir::separator() + backup_name + BACKUP_SUFFIX_DATABASE)) { | ||||
|       throw ApplicationException(tr("Database file not copied to output folder successfully.")); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool Application::restoreDatabaseSettings(bool restore_database, bool restore_settings, | ||||
| void Application::restoreDatabaseSettings(bool restore_database, bool restore_settings, | ||||
|                                           const QString &source_database_file_path, const QString &source_settings_file_path) { | ||||
|   bool result = true; | ||||
| 
 | ||||
|   if (restore_database) { | ||||
|     result &= qApp->database()->initiateRestoration(source_database_file_path); | ||||
|     if (!qApp->database()->initiateRestoration(source_database_file_path)) { | ||||
|       throw ApplicationException(tr("Database restoration was not initiated. Make sure that output folder is writable.")); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   if (restore_settings) { | ||||
|     result &= qApp->settings()->initiateRestoration(source_settings_file_path); | ||||
|     if (!qApp->settings()->initiateRestoration(source_settings_file_path)) { | ||||
|       throw ApplicationException(tr("Settings restoration was not initiated. Make sure that output folder is writable.")); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| void Application::processExecutionMessage(const QString &message) { | ||||
|  | @ -243,3 +243,13 @@ void Application::restart() { | |||
|   m_shouldRestart = true; | ||||
|   quit(); | ||||
| } | ||||
| 
 | ||||
| ApplicationException::ApplicationException(const QString &message) : m_message(message) { | ||||
| } | ||||
| 
 | ||||
| ApplicationException::~ApplicationException() { | ||||
| } | ||||
| 
 | ||||
| QString ApplicationException::message() const { | ||||
|   return m_message; | ||||
| } | ||||
|  |  | |||
|  | @ -45,6 +45,17 @@ class FormMain; | |||
| class IconFactory; | ||||
| class QAction; | ||||
| 
 | ||||
| class ApplicationException { | ||||
|   public: | ||||
|     explicit ApplicationException(const QString &message = QString()); | ||||
|     virtual ~ApplicationException(); | ||||
| 
 | ||||
|     QString message() const; | ||||
| 
 | ||||
|   private: | ||||
|     QString m_message; | ||||
| }; | ||||
| 
 | ||||
| class Application : public QtSingleApplication { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
|  | @ -127,8 +138,8 @@ class Application : public QtSingleApplication { | |||
|       return IOFactory::getSystemFolder(SYSTEM_FOLDER_ENUM::HomeLocation); | ||||
|     } | ||||
| 
 | ||||
|     bool backupDatabaseSettings(bool backup_database, bool backup_settings, const QString &target_path, const QString &backup_name); | ||||
|     bool restoreDatabaseSettings(bool restore_database, bool restore_settings, | ||||
|     void backupDatabaseSettings(bool backup_database, bool backup_settings, const QString &target_path, const QString &backup_name); | ||||
|     void restoreDatabaseSettings(bool restore_database, bool restore_settings, | ||||
|                                  const QString &source_database_file_path = QString(), | ||||
|                                  const QString &source_settings_file_path = QString()); | ||||
| 
 | ||||
|  |  | |||
|  | @ -218,6 +218,10 @@ void WebBrowser::navigateToMessages(const QList<Message> &messages) { | |||
|   QString single_message_layout = factory->currentMarkup(); | ||||
| 
 | ||||
|   foreach (const Message &message, messages) { | ||||
|     QString enclosures = message.m_enclosures.join("</br>"); | ||||
| 
 | ||||
|     // TODO: upravit skiny aby brali další argument
 | ||||
| 
 | ||||
|     messages_layout.append(single_message_layout.arg(message.m_title, | ||||
|                                                      tr("Written by ") + (message.m_author.isEmpty() ? | ||||
|                                                                             tr("uknown author") : | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue