Work on enclosures, only editing of skins remains.

This commit is contained in:
Martin Rotter 2015-04-15 19:47:15 +02:00
parent 21f970d456
commit 8c1414c3df
12 changed files with 109 additions and 81 deletions

View file

@ -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 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
* 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);

View file

@ -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();

View file

@ -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

View file

@ -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();

View file

@ -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."));
}
}

View file

@ -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>

View file

@ -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."));
}
}

View file

@ -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">

View file

@ -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) {

View file

@ -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;
}

View file

@ -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());

View file

@ -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") :