New export/import dialog. Rewritten export functionality.

This commit is contained in:
Martin Rotter 2014-08-30 18:24:16 +02:00
parent f033cd27fc
commit 94100ff90a
10 changed files with 796 additions and 126 deletions

View File

@ -349,6 +349,7 @@ set(APP_SOURCES
src/gui/feedstoolbar.cpp
src/gui/toolbareditor.cpp
src/gui/messagessearchlineedit.cpp
src/gui/formimportexport.cpp
# DYNAMIC-SHORTCUTS sources.
src/dynamic-shortcuts/shortcutcatcher.cpp
@ -378,6 +379,7 @@ set(APP_SOURCES
src/core/feedsmodelfeed.cpp
src/core/parsingfactory.cpp
src/core/feeddownloader.cpp
src/core/feedsimportexportmodel.cpp
# NETWORK-WEB sources.
src/network-web/basenetworkaccessmanager.cpp
@ -431,6 +433,7 @@ set(APP_HEADERS
src/gui/feedstoolbar.h
src/gui/toolbareditor.h
src/gui/messagessearchlineedit.h
src/gui/formimportexport.h
# DYNAMIC-SHORTCUTS headers.
src/dynamic-shortcuts/dynamicshortcutswidget.h
@ -452,6 +455,7 @@ set(APP_HEADERS
src/core/feedsmodel.h
src/core/feedsproxymodel.h
src/core/feeddownloader.h
src/core/feedsimportexportmodel.h
# NETWORK-WEB headers.
src/network-web/webpage.h
@ -473,6 +477,7 @@ set(APP_FORMS
src/gui/formcategorydetails.ui
src/gui/formfeeddetails.ui
src/gui/toolbareditor.ui
src/gui/formimportexport.ui
)
# APP translations.

View File

@ -0,0 +1,315 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "core/feedsimportexportmodel.h"
#include "core/feedsmodelfeed.h"
#include "core/feedsmodelcategory.h"
#include "definitions/definitions.h"
#include <QDomDocument>
#include <QDomElement>
#include <QDomAttr>
#include <QStack>
#include <QLocale>
FeedsImportExportModel::FeedsImportExportModel(QObject *parent)
: QAbstractItemModel(parent), m_checkStates(QHash<FeedsModelRootItem*, Qt::CheckState>()), m_recursiveChange(false) {
}
FeedsImportExportModel::~FeedsImportExportModel() {
}
FeedsModelRootItem *FeedsImportExportModel::itemForIndex(const QModelIndex &index) const {
if (index.isValid() && index.model() == this) {
return static_cast<FeedsModelRootItem*>(index.internalPointer());
}
else {
return m_rootItem;
}
}
FeedsModelRootItem *FeedsImportExportModel::rootItem() const {
return m_rootItem;
}
void FeedsImportExportModel::setRootItem(FeedsModelRootItem *rootItem) {
m_rootItem = rootItem;
}
bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) {
QDomDocument opml_document;
QDomProcessingInstruction xml_declaration = opml_document.createProcessingInstruction("xml",
"version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"");
opml_document.appendChild(xml_declaration);
// Adde OPML 2.0 metadata.
opml_document.appendChild(opml_document.createElement("opml"));
opml_document.documentElement().setAttribute("version", "2.0");
QDomElement elem_opml_head = opml_document.createElement("head");
QDomElement elem_opml_title = opml_document.createElement("title");
QDomText text_opml_title = opml_document.createTextNode(QString(APP_NAME));
elem_opml_title.appendChild(text_opml_title);
elem_opml_head.appendChild(elem_opml_title);
QDomElement elem_opml_created = opml_document.createElement("dateCreated");
QDomText text_opml_created = opml_document.createTextNode(QLocale::c().toString(QDateTime::currentDateTimeUtc(),
"ddd, dd MMM yyyy hh:mm:ss") + " GMT");
elem_opml_created.appendChild(text_opml_created);
elem_opml_head.appendChild(elem_opml_created);
opml_document.documentElement().appendChild(elem_opml_head);
QDomElement elem_opml_body = opml_document.createElement("body");
QStack<FeedsModelRootItem*> items_to_process; items_to_process.push(m_rootItem);
QStack<QDomElement> elements_to_use; elements_to_use.push(elem_opml_body);
// Process all unprocessed nodes.
while (!items_to_process.isEmpty()) {
QDomElement active_element = elements_to_use.pop();
FeedsModelRootItem *active_item = items_to_process.pop();
foreach (FeedsModelRootItem *child_item, active_item->childItems()) {
if (!m_checkStates.contains(child_item) || m_checkStates[child_item] != Qt::Checked) {
continue;
}
switch (child_item->kind()) {
case FeedsModelRootItem::Category: {
QDomElement outline_category = opml_document.createElement("outline");
outline_category.setAttribute("text", child_item->title());
active_element.appendChild(outline_category);
items_to_process.push(child_item);
elements_to_use.push(outline_category);
break;
}
case FeedsModelRootItem::Feed: {
FeedsModelFeed *child_feed = static_cast<FeedsModelFeed*>(child_item);
QDomElement outline_feed = opml_document.createElement("outline");
outline_feed.setAttribute("text", child_feed->title());
outline_feed.setAttribute("xmlUrl", child_feed->url());
outline_feed.setAttribute("description", child_feed->description());
outline_feed.setAttribute("encoding", child_feed->encoding());
switch (child_feed->type()) {
case FeedsModelFeed::Rss0X:
case FeedsModelFeed::Rss2X:
outline_feed.setAttribute("version", "RSS");
break;
case FeedsModelFeed::Rdf:
outline_feed.setAttribute("version", "RSS");
break;
case FeedsModelFeed::Atom10:
outline_feed.setAttribute("version", "ATOM");
break;
default:
break;
}
if (child_feed->passwordProtected()) {
outline_feed.setAttribute("username", child_feed->username());
outline_feed.setAttribute("password", child_feed->password());
}
active_element.appendChild(outline_feed);
break;
}
default:
break;
}
}
}
opml_document.documentElement().appendChild(elem_opml_body);
result = opml_document.toByteArray(2);
return true;
}
QModelIndex FeedsImportExportModel::index(int row, int column, const QModelIndex &parent) const {
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
FeedsModelRootItem *parent_item = itemForIndex(parent);
FeedsModelRootItem *child_item = parent_item->child(row);
if (child_item) {
return createIndex(row, column, child_item);
}
else {
return QModelIndex();
}
}
QModelIndex FeedsImportExportModel::indexForItem(FeedsModelRootItem *item) const {
if (item == NULL || item->kind() == FeedsModelRootItem::RootItem) {
// Root item lies on invalid index.
return QModelIndex();
}
QList<QModelIndex> parents;
// Start with root item (which obviously has invalid index).
parents << indexForItem(m_rootItem);
while (!parents.isEmpty()) {
QModelIndex active_index = parents.takeFirst();
int row_count = rowCount(active_index);
if (row_count > 0) {
// This index has children.
// Lets take a look if our target item is among them.
FeedsModelRootItem *active_item = itemForIndex(active_index);
int candidate_index = active_item->childItems().indexOf(item);
if (candidate_index >= 0) {
// We found our item.
return index(candidate_index, 0, active_index);
}
else {
// Item is not found, add all "categories" from active_item.
for (int i = 0; i < row_count; i++) {
FeedsModelRootItem *possible_category = active_item->child(i);
if (possible_category->kind() == FeedsModelRootItem::Category) {
parents << index(i, 0, active_index);
}
}
}
}
}
return QModelIndex();
}
QModelIndex FeedsImportExportModel::parent(const QModelIndex &child) const {
if (!child.isValid()) {
return QModelIndex();
}
FeedsModelRootItem *child_item = itemForIndex(child);
FeedsModelRootItem *parent_item = child_item->parent();
if (parent_item == m_rootItem) {
return QModelIndex();
}
else {
return createIndex(parent_item->row(), 0, parent_item);
}
}
int FeedsImportExportModel::rowCount(const QModelIndex &parent) const {
if (parent.column() > 0) {
return 0;
}
else {
return itemForIndex(parent)->childCount();
}
}
int FeedsImportExportModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent)
return 1;
}
QVariant FeedsImportExportModel::data(const QModelIndex &index, int role) const {
if (index.column() != 0) {
return QVariant();
}
FeedsModelRootItem *item = itemForIndex(index);
if (role == Qt::CheckStateRole) {
if (m_checkStates.contains(item)) {
return m_checkStates.value(item);
}
else {
return static_cast<int>(Qt::Unchecked);
}
}
else {
return item->data(index.column(), role);
}
}
bool FeedsImportExportModel::setData(const QModelIndex &index, const QVariant &value, int role) {
if (index.isValid() && index.column() == 0 && role == Qt::CheckStateRole) {
FeedsModelRootItem *item = itemForIndex(index);
if (item != m_rootItem) {
m_checkStates[item] = static_cast<Qt::CheckState>(value.toInt());
emit dataChanged(index, index);
if (m_recursiveChange) {
return true;
}
foreach(FeedsModelRootItem *child, item->childItems()) {
setData(indexForItem(child), value, Qt::CheckStateRole);
}
QModelIndex parent_index = index;
m_recursiveChange = true;
while ((parent_index = parent_index.parent()).isValid()) {
// We now have parent index.
item = item->parent();
// Check children of this new parent item.
Qt::CheckState parent_state = Qt::Unchecked;
foreach (FeedsModelRootItem *child_of_parent, item->childItems()) {
if (m_checkStates.contains(child_of_parent) && m_checkStates[child_of_parent] == Qt::Checked) {
parent_state = Qt::Checked;
break;
}
}
setData(parent_index, parent_state, Qt::CheckStateRole);
}
m_recursiveChange = false;
return true;
}
}
return false;
}
Qt::ItemFlags FeedsImportExportModel::flags(const QModelIndex &index) const {
if (!index.isValid()) {
return 0;
}
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if ( index.column() == 0 ) {
flags |= Qt::ItemIsUserCheckable;
}
return flags;
}

View File

@ -0,0 +1,61 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef FEEDIMPORTEXPORTMODEL_H
#define FEEDIMPORTEXPORTMODEL_H
#include <QAbstractItemModel>
#include "core/feedsmodelrootitem.h"
class FeedsImportExportModel : public QAbstractItemModel {
Q_OBJECT
public:
explicit FeedsImportExportModel(QObject *parent = 0);
virtual ~FeedsImportExportModel();
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
Qt::ItemFlags flags(const QModelIndex &index) const;
// Returns feed/category which lies at the specified index or
// root item if index is invalid.
FeedsModelRootItem *itemForIndex(const QModelIndex &index) const;
// Returns source QModelIndex on which lies given item.
QModelIndex indexForItem(FeedsModelRootItem *item) const;
FeedsModelRootItem *rootItem() const;
void setRootItem(FeedsModelRootItem *rootItem);
// Exports to OPML 2.0
// NOTE: http://dev.opml.org/spec2.html
bool exportToOMPL20(QByteArray &result);
private:
QHash<FeedsModelRootItem*, Qt::CheckState> m_checkStates;
FeedsModelRootItem *m_rootItem;
bool m_recursiveChange;
};
#endif // FEEDIMPORTEXPORTMODEL_H

View File

@ -28,11 +28,6 @@
#include <QSqlQuery>
#include <QSqlRecord>
#include <QPair>
#include <QDomDocument>
#include <QDomElement>
#include <QDomAttr>
#include <QStack>
#include <QLocale>
#include <algorithm>
@ -144,109 +139,6 @@ int FeedsModel::rowCount(const QModelIndex &parent) const {
}
}
bool FeedsModel::exportToFile(FeedsModel::ExternalFeedsFileType type, QByteArray &result) {
switch (type) {
case OPML20:
return exportToOMPL20(result);
default:
return false;
}
}
bool FeedsModel::exportToOMPL20(QByteArray &result) {
QDomDocument opml_document;
QDomProcessingInstruction xml_declaration = opml_document.createProcessingInstruction("xml",
"version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"");
opml_document.appendChild(xml_declaration);
// Adde OPML 2.0 metadata.
opml_document.appendChild(opml_document.createElement("opml"));
opml_document.documentElement().setAttribute("version", "2.0");
QDomElement elem_opml_head = opml_document.createElement("head");
QDomElement elem_opml_title = opml_document.createElement("title");
QDomText text_opml_title = opml_document.createTextNode(QString(APP_NAME));
elem_opml_title.appendChild(text_opml_title);
elem_opml_head.appendChild(elem_opml_title);
QDomElement elem_opml_created = opml_document.createElement("dateCreated");
QDomText text_opml_created = opml_document.createTextNode(QLocale::c().toString(QDateTime::currentDateTimeUtc(),
"ddd, dd MMM yyyy hh:mm:ss") + " GMT");
elem_opml_created.appendChild(text_opml_created);
elem_opml_head.appendChild(elem_opml_created);
opml_document.documentElement().appendChild(elem_opml_head);
QDomElement elem_opml_body = opml_document.createElement("body");
QStack<FeedsModelRootItem*> items_to_process; items_to_process.push(m_rootItem);
QStack<QDomElement> elements_to_use; elements_to_use.push(elem_opml_body);
// Process all unprocessed nodes.
while (!items_to_process.isEmpty()) {
QDomElement active_element = elements_to_use.pop();
FeedsModelRootItem *active_item = items_to_process.pop();
foreach (FeedsModelRootItem *child_item, active_item->childItems()) {
switch (child_item->kind()) {
case FeedsModelRootItem::Category: {
QDomElement outline_category = opml_document.createElement("outline");
outline_category.setAttribute("text", child_item->title());
active_element.appendChild(outline_category);
items_to_process.push(child_item);
elements_to_use.push(outline_category);
break;
}
case FeedsModelRootItem::Feed: {
FeedsModelFeed *child_feed = static_cast<FeedsModelFeed*>(child_item);
QDomElement outline_feed = opml_document.createElement("outline");
outline_feed.setAttribute("text", child_feed->title());
outline_feed.setAttribute("xmlUrl", child_feed->url());
outline_feed.setAttribute("description", child_feed->description());
outline_feed.setAttribute("encoding", child_feed->encoding());
switch (child_feed->type()) {
case FeedsModelFeed::Rss0X:
case FeedsModelFeed::Rss2X:
outline_feed.setAttribute("version", "RSS");
break;
case FeedsModelFeed::Rdf:
outline_feed.setAttribute("version", "RSS");
break;
case FeedsModelFeed::Atom10:
outline_feed.setAttribute("version", "ATOM");
break;
default:
break;
}
if (child_feed->passwordProtected()) {
outline_feed.setAttribute("username", child_feed->username());
outline_feed.setAttribute("password", child_feed->password());
}
active_element.appendChild(outline_feed);
break;
}
default:
break;
}
}
}
opml_document.documentElement().appendChild(elem_opml_body);
result = opml_document.toByteArray(2);
return true;
}
bool FeedsModel::removeItem(const QModelIndex &index) {
if (index.isValid()) {
QModelIndex parent_index = index.parent();
@ -597,7 +489,6 @@ FeedsModelCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const
}
}
QModelIndex FeedsModel::indexForItem(FeedsModelRootItem *item) const {
if (item == NULL || item->kind() == FeedsModelRootItem::RootItem) {
// Root item lies on invalid index.

View File

@ -39,10 +39,6 @@ class FeedsModel : public QAbstractItemModel {
Q_OBJECT
public:
enum ExternalFeedsFileType {
OPML20 = 0
};
// Constructors and destructors.
explicit FeedsModel(QObject *parent = 0);
virtual ~FeedsModel();
@ -72,13 +68,6 @@ class FeedsModel : public QAbstractItemModel {
return m_rootItem->countOfUnreadMessages();
}
// Import/export.
bool exportToFile(ExternalFeedsFileType type, QByteArray &result);
// Exports to OPML 2.0
// NOTE: http://dev.opml.org/spec2.html
bool exportToOMPL20(QByteArray &result);
// Removes item with given index.
bool removeItem(const QModelIndex &index);

View File

@ -0,0 +1,183 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "gui/formimportexport.h"
#include "core/feedsimportexportmodel.h"
#include "core/feedsmodel.h"
#include "miscellaneous/application.h"
#include "gui/feedmessageviewer.h"
#include "gui/formmain.h"
#include "gui/feedsview.h"
#include <QFileDialog>
#include <QTextStream>
FormImportExport::FormImportExport(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormImportExport), m_mode(Import) {
m_ui->setupUi(this);
m_model = new FeedsImportExportModel(m_ui->m_treeFeeds);
m_ui->m_treeFeeds->setModel(m_model);
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Error, tr("No file is selected."), tr("No file is selected."));
m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->disconnect();
m_ui->m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet."));
connect(m_ui->m_buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(performAction()));
connect(m_ui->m_btnSelectFile, SIGNAL(clicked()), this, SLOT(selectFile()));
}
FormImportExport::~FormImportExport() {
delete m_ui;
}
FormImportExport::Mode FormImportExport::mode() const {
return m_mode;
}
void FormImportExport::setMode(const Mode &mode) {
m_mode = mode;
switch (m_mode) {
case Export: {
m_model->setRootItem(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->rootItem());
m_ui->m_treeFeeds->expandAll();
setWindowTitle(tr("Export feeds"));
setWindowIcon(qApp->icons()->fromTheme("document-export"));
m_ui->m_groupFile->setTitle(tr("Destination file"));
m_ui->m_groupFeeds->setTitle(tr("Source feeds && categories"));
break;
}
case Import: {
m_ui->m_groupFile->setTitle(tr("Source file"));
m_ui->m_groupFeeds->setTitle(tr("Target feeds && categories"));
m_ui->m_treeFeeds->setDisabled(true);
setWindowTitle(tr("Import feeds"));
setWindowIcon(qApp->icons()->fromTheme("document-import"));
break;
}
default:
break;
}
}
void FormImportExport::selectFile() {
switch (m_mode) {
case Import:
selectImportFile();
break;
case Export: {
selectExportFile();
break;
}
default:
break;
}
}
void FormImportExport::selectExportFile() {
QString filter_opml20 = tr("OPML 2.0 files (*.opml)");
QString filter;
QString selected_filter;
// Add more filters here.
filter += filter_opml20;
QString selected_file = QFileDialog::getSaveFileName(this, tr("Select file for feeds export"),
QDir::homePath(), filter, &selected_filter);
if (!selected_file.isEmpty()) {
if (selected_filter == filter_opml20) {
m_conversionType = OPML20;
}
// NOTE: Add other types here.
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected."));
}
else {
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Error, tr("No file is selected."), tr("No file is selected."));
}
m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setDisabled(selected_file.isEmpty());
}
void FormImportExport::selectImportFile() {
// TODO: vyber soubor a kdyz je vybranej, tak rozparsovat a vytvorit dle nej strukturu
// itemů a narvat do modelu.
}
void FormImportExport::performAction() {
switch (m_mode) {
case Import:
importFeeds();
break;
case Export:
exportFeeds();
break;
default:
break;
}
}
void FormImportExport::exportFeeds() {
switch (m_conversionType) {
case OPML20: {
QByteArray result_data;
bool result_export = m_model->exportToOMPL20(result_data);
if (result_export) {
// Save exported data.
QFile output_file(m_ui->m_lblSelectFile->label()->text());
if (output_file.open(QIODevice::Unbuffered | QIODevice::Truncate | QIODevice::WriteOnly)) {
QTextStream stream(&output_file);
stream.setCodec("UTF-8");
stream << QString::fromUtf8(result_data);
output_file.flush();
output_file.close();
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Feeds were exported successfully."),
tr("Feeds were exported successfully."));
}
else {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Cannot write into destination file."),
tr("Cannot write into destination file."));
}
}
else {
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Critical error occurred."), tr("Critical error occurred."));
}
}
default:
break;
}
}
void FormImportExport::importFeeds() {
}

View File

@ -0,0 +1,68 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2014 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// RSS Guard is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef FORMEXPORT_H
#define FORMEXPORT_H
#include <QDialog>
#include "ui_formimportexport.h"
namespace Ui {
class FormExport;
}
class FeedsImportExportModel;
class FormImportExport : public QDialog {
Q_OBJECT
public:
enum ConversionType {
OPML20 = 0
};
enum Mode {
Import,
Export
};
explicit FormImportExport(QWidget *parent = 0);
virtual ~FormImportExport();
Mode mode() const;
void setMode(const Mode &mode);
private slots:
void performAction();
void selectFile();
private:
void selectExportFile();
void selectImportFile();
void exportFeeds();
void importFeeds();
Ui::FormImportExport *m_ui;
Mode m_mode;
ConversionType m_conversionType;
FeedsImportExportModel *m_model;
};
#endif // FORMEXPORT_H

148
src/gui/formimportexport.ui Normal file
View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FormImportExport</class>
<widget class="QDialog" name="FormImportExport">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>478</width>
<height>434</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="m_groupFile">
<property name="title">
<string/>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QPushButton" name="m_btnSelectFile">
<property name="text">
<string>&amp;Select file</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LabelWithStatus" name="m_lblSelectFile" native="true">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_groupFeeds">
<property name="title">
<string/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="m_treeFeeds">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="indentation">
<number>10</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="animated">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>false</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Operation results</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="LabelWithStatus" name="m_lblResult" native="true">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="m_buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LabelWithStatus</class>
<extends>QWidget</extends>
<header>labelwithstatus.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>m_buttonBox</sender>
<signal>accepted()</signal>
<receiver>FormImportExport</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_buttonBox</sender>
<signal>rejected()</signal>
<receiver>FormImportExport</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -34,6 +34,7 @@
#include "gui/statusbar.h"
#include "gui/feedmessageviewer.h"
#include "gui/formupdate.h"
#include "gui/formimportexport.h"
#include <QCloseEvent>
#include <QSessionManager>
@ -436,7 +437,13 @@ void FormMain::loadWebBrowserMenu(int index) {
m_ui->m_actionCloseCurrentTab->setEnabled(m_ui->m_tabWidget->tabBar()->tabType(index) == TabBar::Closable);
}
void FormMain::exportFeeds() {
void FormMain::exportFeeds() {
QPointer<FormImportExport> form = new FormImportExport(this);
form.data()->setMode(FormImportExport::Export);
form.data()->exec();
delete form.data();
/*
QString filter_opml20 = tr("OPML 2.0 files (*.opml)");
QString filter;
@ -476,11 +483,14 @@ void FormMain::exportFeeds() {
output_file.close();
}
}
}
}*/
}
void FormMain::importFeeds() {
QPointer<FormImportExport> form = new FormImportExport(this);
form.data()->setMode(FormImportExport::Import);
form.data()->exec();
delete form.data();
}
void FormMain::changeEvent(QEvent *event) {

View File

@ -17,7 +17,7 @@
<item row="0" column="1">
<widget class="QStackedWidget" name="m_stackedSettings">
<property name="currentIndex">
<number>3</number>
<number>0</number>
</property>
<widget class="QWidget" name="m_pageGeneral">
<layout class="QFormLayout" name="formLayout_5">
@ -241,8 +241,8 @@ Authors of this application are NOT responsible for lost data.</string>
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
<width>588</width>
<height>390</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">