mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-26 15:28:28 -05:00
FeedReader:
- Added error handling to xml functions - Added xslt transformation - Added retransform of existing messages - Redesigned preview dialog - Enabled embed images for forum feeds - Changed config format, switching back to an older version results in a loss of all data of the FeedReader Added new base class RSPlainTextEdit with placeholder text. New library libxslt needed git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6081 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
919fb3f62d
commit
ef49000b9a
@ -229,14 +229,11 @@ static int vasprintf(char **sptr, const char *fmt, va_list argv)
|
||||
//}
|
||||
#endif
|
||||
|
||||
int rs_sprintf(std::string &str, const char *fmt, ...)
|
||||
int rs_sprintf_args(std::string &str, const char *fmt, va_list ap)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
int retval = vasprintf(&buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
int retval = vasprintf(&buffer, fmt, (va_list) ap);
|
||||
|
||||
if (retval >= 0) {
|
||||
if (buffer) {
|
||||
@ -252,15 +249,23 @@ int rs_sprintf(std::string &str, const char *fmt, ...)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int rs_sprintf_append(std::string &str, const char *fmt, ...)
|
||||
int rs_sprintf(std::string &str, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *buffer = NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
int retval = vasprintf(&buffer, fmt, ap);
|
||||
int retval = rs_sprintf_args(str, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int rs_sprintf_append_args(std::string &str, const char *fmt, va_list ap)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
|
||||
int retval = vasprintf(&buffer, fmt, (va_list) ap);
|
||||
|
||||
if (retval >= 0) {
|
||||
if (buffer) {
|
||||
str.append(buffer);
|
||||
@ -271,6 +276,17 @@ int rs_sprintf_append(std::string &str, const char *fmt, ...)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int rs_sprintf_append(std::string &str, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
int retval = rs_sprintf_append_args(str, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void stringToUpperCase(const std::string& s, std::string &upper)
|
||||
{
|
||||
upper = s ;
|
||||
|
@ -15,7 +15,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#define RSSTRING_H_
|
||||
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace librs { namespace util {
|
||||
|
||||
@ -39,7 +40,9 @@ bool ConvertUtf16ToUtf8(const std::wstring& source, std::string& dest);
|
||||
#define UINT64FMT "%llu"
|
||||
#endif
|
||||
|
||||
int rs_sprintf_args(std::string &str, const char *fmt, va_list ap);
|
||||
int rs_sprintf(std::string &str, const char *fmt, ...);
|
||||
int rs_sprintf_append_args(std::string &str, const char *fmt, va_list ap);
|
||||
int rs_sprintf_append(std::string &str, const char *fmt, ...);
|
||||
|
||||
void stringToUpperCase(const std::string& s, std::string &upper);
|
||||
|
@ -51,8 +51,8 @@ FORMS = gui/FeedReaderDialog.ui \
|
||||
TARGET = FeedReader
|
||||
|
||||
RESOURCES = gui/FeedReader_images.qrc \
|
||||
lang/FeedReader_lang.qrc
|
||||
|
||||
lang/FeedReader_lang.qrc
|
||||
|
||||
TRANSLATIONS += \
|
||||
lang/FeedReader_cs.ts \
|
||||
lang/FeedReader_da.ts \
|
||||
@ -76,17 +76,17 @@ linux-* {
|
||||
|
||||
INCLUDEPATH += $${LIBXML2_DIR}
|
||||
|
||||
LIBS += -lcurl -lxml2
|
||||
LIBS += -lcurl -lxml2 -lxslt
|
||||
}
|
||||
|
||||
win32 {
|
||||
DEFINES += CURL_STATICLIB LIBXML_STATIC
|
||||
DEFINES += CURL_STATICLIB LIBXML_STATIC LIBXSLT_STATIC LIBEXSLT_STATIC
|
||||
|
||||
CURL_DIR = ../../../curl-7.26.0
|
||||
LIBXML2_DIR = ../../../libxml2-2.8.0
|
||||
LIBICONV_DIR = ../../../libiconv-1.14
|
||||
LIBXSLT_DIR = ../../../libxslt-1.1.28
|
||||
|
||||
INCLUDEPATH += $${CURL_DIR}/include $${LIBXML2_DIR}/include $${LIBICONV_DIR}/include
|
||||
INCLUDEPATH += $${CURL_DIR}/include $${LIBXML2_DIR}/include $${LIBXSLT_DIR} $${LIBICONV_DIR}/include
|
||||
|
||||
LIBS += -lcurl -lxml2 -lws2_32 -lwldap32
|
||||
LIBS += -lcurl -lxml2 -lxslt -lws2_32 -lwldap32
|
||||
}
|
||||
|
@ -53,7 +53,6 @@ AddFeedDialog::AddFeedDialog(RsFeedReader *feedReader, FeedReaderNotify *notify,
|
||||
|
||||
/* currently only for loacl feeds */
|
||||
connect(ui->saveCompletePageCheckBox, SIGNAL(toggled(bool)), this, SLOT(denyForumToggled()));
|
||||
connect(ui->embedImagesCheckBox, SIGNAL(toggled(bool)), this, SLOT(denyForumToggled()));
|
||||
|
||||
connect(ui->urlLineEdit, SIGNAL(textChanged(QString)), this, SLOT(validate()));
|
||||
connect(ui->nameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(validate()));
|
||||
@ -78,6 +77,9 @@ AddFeedDialog::AddFeedDialog(RsFeedReader *feedReader, FeedReaderNotify *notify,
|
||||
/* not yet supported */
|
||||
ui->authenticationGroupBox->setEnabled(false);
|
||||
|
||||
mTransformationType = RS_FEED_TRANSFORMATION_TYPE_NONE;
|
||||
ui->transformationTypeLabel->setText(FeedReaderStringDefs::transforationTypeString(mTransformationType));
|
||||
|
||||
/* fill own forums */
|
||||
std::list<ForumInfo> forumList;
|
||||
if (rsForums->getForumList(forumList)) {
|
||||
@ -163,7 +165,7 @@ void AddFeedDialog::typeForumToggled()
|
||||
|
||||
void AddFeedDialog::denyForumToggled()
|
||||
{
|
||||
if (ui->saveCompletePageCheckBox->isChecked() || ui->embedImagesCheckBox->isChecked()) {
|
||||
if (ui->saveCompletePageCheckBox->isChecked()) {
|
||||
ui->typeForumRadio->setEnabled(false);
|
||||
ui->typeLocalRadio->setChecked(true);
|
||||
} else {
|
||||
@ -230,7 +232,6 @@ bool AddFeedDialog::fillFeed(const std::string &feedId)
|
||||
if (feedInfo.flag.forum) {
|
||||
ui->typeForumRadio->setChecked(true);
|
||||
ui->saveCompletePageCheckBox->setEnabled(false);
|
||||
ui->embedImagesCheckBox->setEnabled(false);
|
||||
|
||||
if (feedInfo.forumId.empty()) {
|
||||
ui->forumNameLabel->setText(tr("Not yet created"));
|
||||
@ -263,8 +264,12 @@ bool AddFeedDialog::fillFeed(const std::string &feedId)
|
||||
ui->useStandardStorageTimeCheckBox->setChecked(feedInfo.flag.standardStorageTime);
|
||||
ui->storageTimeSpinBox->setValue(feedInfo.storageTime / (60 * 60 *24));
|
||||
|
||||
mTransformationType = feedInfo.transformationType;
|
||||
mXPathsToUse = feedInfo.xpathsToUse;
|
||||
mXPathsToRemove = feedInfo.xpathsToRemove;
|
||||
mXslt = feedInfo.xslt;
|
||||
|
||||
ui->transformationTypeLabel->setText(FeedReaderStringDefs::transforationTypeString(mTransformationType));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -306,8 +311,10 @@ void AddFeedDialog::getFeedInfo(FeedInfo &feedInfo)
|
||||
feedInfo.flag.standardStorageTime = ui->useStandardStorageTimeCheckBox->isChecked();
|
||||
feedInfo.storageTime = ui->storageTimeSpinBox->value() * 60 *60 * 24;
|
||||
|
||||
feedInfo.transformationType = mTransformationType;
|
||||
feedInfo.xpathsToUse = mXPathsToUse;
|
||||
feedInfo.xpathsToRemove = mXPathsToRemove;
|
||||
feedInfo.xslt = mXslt;
|
||||
}
|
||||
|
||||
void AddFeedDialog::createFeed()
|
||||
@ -345,6 +352,7 @@ void AddFeedDialog::preview()
|
||||
|
||||
PreviewFeedDialog dialog(mFeedReader, mNotify, feedInfo, this);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
dialog.getXPaths(mXPathsToUse, mXPathsToRemove);
|
||||
mTransformationType = dialog.getData(mXPathsToUse, mXPathsToRemove, mXslt);
|
||||
ui->transformationTypeLabel->setText(FeedReaderStringDefs::transforationTypeString(mTransformationType));
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +63,10 @@ private:
|
||||
std::string mFeedId;
|
||||
std::string mParentId;
|
||||
|
||||
RsFeedTransformationType mTransformationType;
|
||||
std::list<std::string> mXPathsToUse;
|
||||
std::list<std::string> mXPathsToRemove;
|
||||
std::string mXslt;
|
||||
|
||||
Ui::AddFeedDialog *ui;
|
||||
};
|
||||
|
@ -21,7 +21,16 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
@ -36,6 +45,61 @@
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="typeGroupBox">
|
||||
<property name="title">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="typeForumRadio">
|
||||
<property name="text">
|
||||
<string>Forum</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="forumComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="forumNameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Forum name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="typeLocalRadio">
|
||||
<property name="text">
|
||||
<string>Local Feed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QGroupBox" name="authenticationGroupBox">
|
||||
<property name="title">
|
||||
@ -76,63 +140,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QGroupBox" name="updateInteralGroupBox">
|
||||
<property name="title">
|
||||
<string>Update interval</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="useStandardUpdateInterval">
|
||||
<property name="text">
|
||||
<string>Use standard update interval</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="updateIntervalLabel">
|
||||
<property name="text">
|
||||
<string>Interval in minutes (0 = manual)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="updateIntervalSpinBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="lastUpdateLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lastUpdateLabel">
|
||||
<property name="text">
|
||||
<string>Last update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lastUpdate">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Never</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QGroupBox" name="storageTimeGroupBox">
|
||||
<property name="title">
|
||||
@ -209,47 +216,47 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="previewButton">
|
||||
<property name="text">
|
||||
<string>Preview</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="typeGroupBox">
|
||||
<item row="8" column="0">
|
||||
<widget class="QGroupBox" name="updateInteralGroupBox">
|
||||
<property name="title">
|
||||
<string>Type</string>
|
||||
<string>Update interval</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="margin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="useStandardUpdateInterval">
|
||||
<property name="text">
|
||||
<string>Use standard update interval</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="updateIntervalLabel">
|
||||
<property name="text">
|
||||
<string>Interval in minutes (0 = manual)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="updateIntervalSpinBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="lastUpdateLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="typeForumRadio">
|
||||
<widget class="QLabel" name="lastUpdateLabel">
|
||||
<property name="text">
|
||||
<string>Forum</string>
|
||||
<string>Last update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="forumComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="forumNameLabel">
|
||||
<widget class="QLabel" name="lastUpdate">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@ -257,78 +264,25 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Forum name</string>
|
||||
<string>Never</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="typeLocalRadio">
|
||||
<property name="text">
|
||||
<string>Local Feed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QGroupBox" name="flagGroupBox">
|
||||
<property name="title">
|
||||
<string>Misc</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="activatedCheckBox">
|
||||
<property name="text">
|
||||
<string>Activated</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useInfoFromFeedCheckBox">
|
||||
<property name="text">
|
||||
<string>Use name and description from feed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="updateForumInfoCheckBox">
|
||||
<property name="text">
|
||||
<string>Update forum information</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="embedImagesCheckBox">
|
||||
<property name="text">
|
||||
<string>Embed images (experimental for local feeds)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="saveCompletePageCheckBox">
|
||||
<property name="text">
|
||||
<string>Save complete web page (experimental for local feeds)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<item row="11" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="buttonLayout">
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QVBoxLayout" name="descriptionLayout">
|
||||
@ -368,6 +322,83 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Transformation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="transformationTypeLabel">
|
||||
<property name="text">
|
||||
<string>Transformation type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="previewButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Preview && Transformation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" rowspan="2">
|
||||
<widget class="QGroupBox" name="flagGroupBox">
|
||||
<property name="title">
|
||||
<string>Misc</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="activatedCheckBox">
|
||||
<property name="text">
|
||||
<string>Activated</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useInfoFromFeedCheckBox">
|
||||
<property name="text">
|
||||
<string>Use name and description from feed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="updateForumInfoCheckBox">
|
||||
<property name="text">
|
||||
<string>Update forum information</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="embedImagesCheckBox">
|
||||
<property name="text">
|
||||
<string>Embed images</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="saveCompletePageCheckBox">
|
||||
<property name="text">
|
||||
<string>Save complete web page (experimental for local feeds)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -67,7 +67,7 @@ FeedReaderFeedItem::FeedReaderFeedItem(RsFeedReader *feedReader, FeedReaderNotif
|
||||
|
||||
ui->titleLabel->setText(QString::fromUtf8(feedInfo.name.c_str()));
|
||||
ui->msgTitleLabel->setText(QString::fromUtf8(msgInfo.title.c_str()));
|
||||
ui->descriptionLabel->setText(QString::fromUtf8(msgInfo.description.c_str()));
|
||||
ui->descriptionLabel->setText(QString::fromUtf8((msgInfo.descriptionTransformed.empty() ? msgInfo.description : msgInfo.descriptionTransformed).c_str()));
|
||||
|
||||
ui->dateTimeLabel->setText(DateTime::formatLongDateTime(msgInfo.pubDate));
|
||||
|
||||
|
@ -219,7 +219,16 @@ void FeedReaderMessageWidget::setFeedId(const std::string &feedId)
|
||||
mFeedInfo = FeedInfo();
|
||||
}
|
||||
|
||||
ui->msgReadAllButton->setEnabled(!mFeedId.empty());
|
||||
if (mFeedId.empty()) {
|
||||
ui->msgReadAllButton->setEnabled(false);
|
||||
ui->msgTreeWidget->setPlaceholderText("");
|
||||
} else {
|
||||
if (mFeedInfo.flag.forum) {
|
||||
ui->msgTreeWidget->setPlaceholderText(tr("The messages will be added to the forum"));
|
||||
} else {
|
||||
ui->msgTreeWidget->setPlaceholderText("");
|
||||
}
|
||||
}
|
||||
|
||||
updateMsgs();
|
||||
updateCurrentMessage();
|
||||
@ -307,6 +316,11 @@ void FeedReaderMessageWidget::msgTreeCustomPopupMenu(QPoint /*point*/)
|
||||
action = contextMnu.addAction(QIcon(""), tr("Remove"), this, SLOT(removeMsg()));
|
||||
action->setEnabled(!selectedItems.empty());
|
||||
|
||||
contextMnu.addSeparator();
|
||||
|
||||
action = contextMnu.addAction(QIcon(""), tr("Retransform"), this, SLOT(retransformMsg()));
|
||||
action->setEnabled((mFeedInfo.transformationType != RS_FEED_TRANSFORMATION_TYPE_NONE) && !selectedItems.empty());
|
||||
|
||||
contextMnu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
@ -495,6 +509,12 @@ void FeedReaderMessageWidget::msgChanged(const QString &feedId, const QString &m
|
||||
}
|
||||
}
|
||||
|
||||
if (type == NOTIFY_TYPE_MOD) {
|
||||
if (msgId.toStdString() == currentMsgId()) {
|
||||
updateCurrentMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if (type == NOTIFY_TYPE_ADD) {
|
||||
QTreeWidgetItem *item = new RSTreeWidgetItem(mMsgCompareRole);
|
||||
updateMsgItem(item, msgInfo);
|
||||
@ -591,7 +611,7 @@ void FeedReaderMessageWidget::updateCurrentMessage()
|
||||
setMsgAsReadUnread(row, setToReadOnActive);
|
||||
}
|
||||
|
||||
QString msgTxt = RsHtml().formatText(ui->msgText->document(), QString::fromUtf8(msgInfo.description.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
|
||||
QString msgTxt = RsHtml().formatText(ui->msgText->document(), QString::fromUtf8((msgInfo.descriptionTransformed.empty() ? msgInfo.description : msgInfo.descriptionTransformed).c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
|
||||
|
||||
ui->msgText->setHtml(msgTxt);
|
||||
ui->msgTitle->setText(QString::fromUtf8(msgInfo.title.c_str()));
|
||||
@ -744,6 +764,20 @@ void FeedReaderMessageWidget::removeMsg()
|
||||
mFeedReader->removeMsgs(mFeedId, msgIds);
|
||||
}
|
||||
|
||||
void FeedReaderMessageWidget::retransformMsg()
|
||||
{
|
||||
if (mFeedId.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
||||
QList<QTreeWidgetItem*>::iterator it;
|
||||
|
||||
for (it = selectedItems.begin(); it != selectedItems.end(); ++it) {
|
||||
mFeedReader->retransformMsg(mFeedId, (*it)->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
void FeedReaderMessageWidget::processFeed()
|
||||
{
|
||||
if (mFeedId.empty()) {
|
||||
|
@ -52,6 +52,7 @@ private slots:
|
||||
void processFeed();
|
||||
void openLinkMsg();
|
||||
void copyLinkMsg();
|
||||
void retransformMsg();
|
||||
|
||||
/* FeedReaderNotify */
|
||||
void feedChanged(const QString &feedId, int type);
|
||||
|
@ -17,7 +17,16 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
@ -36,7 +45,16 @@
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
@ -138,7 +156,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QTreeWidget" name="msgTreeWidget">
|
||||
<widget class="RSTreeWidget" name="msgTreeWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>9</pointsize>
|
||||
@ -278,6 +296,11 @@
|
||||
<extends>QLineEdit</extends>
|
||||
<header location="global">gui/common/LineEditClear.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>RSTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>gui/common/RSTreeWidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="FeedReader_images.qrc"/>
|
||||
|
@ -71,7 +71,7 @@ QString FeedReaderStringDefs::workState(FeedInfo::WorkState state)
|
||||
return QApplication::translate("FeedReaderStringDefs", "Processing");
|
||||
}
|
||||
|
||||
return "";
|
||||
return QApplication::translate("FeedReaderStringDefs", "Unknown");
|
||||
}
|
||||
|
||||
QString FeedReaderStringDefs::errorString(const FeedInfo &feedInfo)
|
||||
@ -135,6 +135,15 @@ QString FeedReaderStringDefs::errorString(RsFeedReaderErrorState errorState, con
|
||||
case RS_FEED_ERRORSTATE_PROCESS_XPATH_NO_RESULT:
|
||||
errorText = QApplication::translate("FeedReaderStringDefs", "Empty XPath result");
|
||||
break;
|
||||
case RS_FEED_ERRORSTATE_PROCESS_XSLT_FORMAT_ERROR:
|
||||
errorText = QApplication::translate("FeedReaderStringDefs", "XSLT format error");
|
||||
break;
|
||||
case RS_FEED_ERRORSTATE_PROCESS_XSLT_TRANSFORM_ERROR:
|
||||
errorText = QApplication::translate("FeedReaderStringDefs", "XSLT transformation error");
|
||||
break;
|
||||
case RS_FEED_ERRORSTATE_PROCESS_XSLT_NO_RESULT:
|
||||
errorText = QApplication::translate("FeedReaderStringDefs", "Empty XSLT result");
|
||||
break;
|
||||
|
||||
default:
|
||||
errorText = QApplication::translate("FeedReaderStringDefs", "Unknown error");
|
||||
@ -146,3 +155,17 @@ QString FeedReaderStringDefs::errorString(RsFeedReaderErrorState errorState, con
|
||||
|
||||
return errorText;
|
||||
}
|
||||
|
||||
QString FeedReaderStringDefs::transforationTypeString(RsFeedTransformationType transformationType)
|
||||
{
|
||||
switch (transformationType) {
|
||||
case RS_FEED_TRANSFORMATION_TYPE_NONE:
|
||||
return QApplication::translate("FeedReaderStringDefs", "No transformation");
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XPATH:
|
||||
return QApplication::translate("FeedReaderStringDefs", "XPath");
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XSLT:
|
||||
return QApplication::translate("FeedReaderStringDefs", "XSLT");
|
||||
}
|
||||
|
||||
return QApplication::translate("FeedReaderStringDefs", "Unknown");
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
static QString workState(FeedInfo::WorkState state);
|
||||
static QString errorString(const FeedInfo &feedInfo);
|
||||
static QString errorString(RsFeedReaderErrorState errorState, const std::string &errorString);
|
||||
static QString transforationTypeString(RsFeedTransformationType transformationType);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "util/HandleRichText.h"
|
||||
#include "gui/settings/rsharesettings.h"
|
||||
|
||||
#include "interface/rsFeedReader.h"
|
||||
#include "retroshare/rsiface.h"
|
||||
#include "util/HTMLWrapper.h"
|
||||
|
||||
@ -146,35 +145,44 @@ PreviewFeedDialog::PreviewFeedDialog(RsFeedReader *feedReader, FeedReaderNotify
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->feedNameLabel->clear();
|
||||
ui->useXPathCheckBox->setChecked(true);
|
||||
|
||||
/* connect signals */
|
||||
connect(ui->previousPushButton, SIGNAL(clicked()), this, SLOT(previousMsg()));
|
||||
connect(ui->nextPushButton, SIGNAL(clicked()), this, SLOT(nextMsg()));
|
||||
connect(ui->closeStructureButton, SIGNAL(clicked()), this, SLOT(showStructureFrame()));
|
||||
connect(ui->structureButton, SIGNAL(toggled(bool)), this, SLOT(showStructureFrame(bool)));
|
||||
connect(ui->xpathPushButton, SIGNAL(toggled(bool)), this, SLOT(showXPathFrame(bool)));
|
||||
connect(ui->useXPathCheckBox, SIGNAL(toggled(bool)), this, SLOT(fillStructureTree()));
|
||||
connect(ui->structureButton, SIGNAL(toggled(bool)), this, SLOT(showStructureFrame()));
|
||||
connect(ui->xpathUseListWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(xpathListCustomPopupMenu(QPoint)));
|
||||
connect(ui->xpathRemoveListWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(xpathListCustomPopupMenu(QPoint)));
|
||||
connect(ui->xpathUseListWidget->itemDelegate(), SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), this, SLOT(xpathCloseEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
|
||||
connect(ui->xpathRemoveListWidget->itemDelegate(), SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), this, SLOT(xpathCloseEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
|
||||
connect(ui->transformationTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(transformationTypeChanged()));
|
||||
|
||||
connect(mNotify, SIGNAL(feedChanged(QString,int)), this, SLOT(feedChanged(QString,int)));
|
||||
connect(mNotify, SIGNAL(msgChanged(QString,QString,int)), this, SLOT(msgChanged(QString,QString,int)));
|
||||
|
||||
ui->transformationTypeComboBox->addItem(FeedReaderStringDefs::transforationTypeString(RS_FEED_TRANSFORMATION_TYPE_NONE), RS_FEED_TRANSFORMATION_TYPE_NONE);
|
||||
ui->transformationTypeComboBox->addItem(FeedReaderStringDefs::transforationTypeString(RS_FEED_TRANSFORMATION_TYPE_XPATH), RS_FEED_TRANSFORMATION_TYPE_XPATH);
|
||||
ui->transformationTypeComboBox->addItem(FeedReaderStringDefs::transforationTypeString(RS_FEED_TRANSFORMATION_TYPE_XSLT), RS_FEED_TRANSFORMATION_TYPE_XSLT);
|
||||
|
||||
ui->xsltTextEdit->setPlaceholderText(tr("XSLT is used on focus lost or when Ctrl+Enter is pressed"));
|
||||
|
||||
// ui->documentTreeWidget->setItemDelegate(new PreviewItemDelegate(ui->documentTreeWidget));
|
||||
ui->structureFrame->hide();
|
||||
showStructureFrame();
|
||||
|
||||
/* Set initial size the splitter */
|
||||
// QList<int> sizes;
|
||||
// sizes << 300 << 300 << 150; // Qt calculates the right sizes
|
||||
// ui->splitter->setSizes(sizes);
|
||||
|
||||
if (mFeedReader->addPreviewFeed(feedInfo, mFeedId)) {
|
||||
setFeedInfo("");
|
||||
} else {
|
||||
setFeedInfo(tr("Cannot create preview"));
|
||||
}
|
||||
setXPathInfo("");
|
||||
showXPathFrame(true);
|
||||
setTransformationInfo("");
|
||||
|
||||
/* fill xpath/xslt expressions */
|
||||
ui->transformationTypeComboBox->setCurrentIndex(ui->transformationTypeComboBox->findData(feedInfo.transformationType));
|
||||
|
||||
/* fill xpath expressions */
|
||||
QListWidgetItem *item;
|
||||
std::string xpath;
|
||||
foreach(xpath, feedInfo.xpathsToUse){
|
||||
@ -188,12 +196,15 @@ PreviewFeedDialog::PreviewFeedDialog(RsFeedReader *feedReader, FeedReaderNotify
|
||||
ui->xpathRemoveListWidget->addItem(item);
|
||||
}
|
||||
|
||||
ui->xsltTextEdit->setPlainText(QString::fromUtf8(feedInfo.xslt.c_str()));
|
||||
|
||||
updateMsgCount();
|
||||
|
||||
ui->xpathUseListWidget->installEventFilter(this);
|
||||
ui->xpathUseListWidget->viewport()->installEventFilter(this);
|
||||
ui->xpathRemoveListWidget->installEventFilter(this);
|
||||
ui->xpathRemoveListWidget->viewport()->installEventFilter(this);
|
||||
ui->xsltTextEdit->installEventFilter(this);
|
||||
|
||||
/* load settings */
|
||||
processSettings(true);
|
||||
@ -234,8 +245,6 @@ void PreviewFeedDialog::processSettings(bool load)
|
||||
|
||||
bool PreviewFeedDialog::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
long todo_here;
|
||||
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent) {
|
||||
@ -247,16 +256,28 @@ bool PreviewFeedDialog::eventFilter(QObject *obj, QEvent *event)
|
||||
QListWidgetItem *item = listWidget->currentItem();
|
||||
if (item) {
|
||||
delete(item);
|
||||
processXPath();
|
||||
processTransformation();
|
||||
}
|
||||
return true; // eat event
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) && (keyEvent->modifiers() & Qt::ControlModifier)) {
|
||||
/* Ctrl+Enter pressed */
|
||||
if (obj == ui->xsltTextEdit) {
|
||||
processTransformation();
|
||||
return true; // eat event
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event->type() == QEvent::Drop) {
|
||||
processXPath();
|
||||
processTransformation();
|
||||
}
|
||||
if (event->type() == QEvent::FocusOut) {
|
||||
if (obj == ui->xsltTextEdit) {
|
||||
processTransformation();
|
||||
}
|
||||
}
|
||||
/* pass the event on to the parent class */
|
||||
return QDialog::eventFilter(obj, event);
|
||||
@ -338,27 +359,51 @@ void PreviewFeedDialog::msgChanged(const QString &feedId, const QString &msgId,
|
||||
updateMsgCount();
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::showStructureFrame(bool show)
|
||||
void PreviewFeedDialog::showStructureFrame()
|
||||
{
|
||||
ui->structureButton->setChecked(show);
|
||||
ui->structureFrame->setVisible(show);
|
||||
bool show = ui->structureButton->isChecked();
|
||||
RsFeedTransformationType transformationType = (RsFeedTransformationType) ui->transformationTypeComboBox->itemData(ui->transformationTypeComboBox->currentIndex()).toInt();
|
||||
|
||||
if (show) {
|
||||
fillStructureTree();
|
||||
ui->structureTreeFrame->setVisible(show);
|
||||
|
||||
switch (transformationType) {
|
||||
case RS_FEED_TRANSFORMATION_TYPE_NONE:
|
||||
ui->msgTextOrg->hide();
|
||||
ui->structureTreeWidgetOrg->hide();
|
||||
ui->transformationFrame->hide();
|
||||
ui->xpathFrame->hide();
|
||||
ui->xsltFrame->hide();
|
||||
break;
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XPATH:
|
||||
ui->msgTextOrg->setVisible(show);
|
||||
ui->structureTreeWidgetOrg->show();
|
||||
ui->transformationFrame->setVisible(show);
|
||||
ui->xpathFrame->show();
|
||||
ui->xsltFrame->hide();
|
||||
break;
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XSLT:
|
||||
ui->msgTextOrg->setVisible(show);
|
||||
ui->structureTreeWidgetOrg->show();
|
||||
ui->transformationFrame->setVisible(show);
|
||||
ui->xpathFrame->hide();
|
||||
ui->xsltFrame->show();
|
||||
break;
|
||||
}
|
||||
|
||||
if (ui->msgTextOrg->isVisible()) {
|
||||
QString msgTxt = RsHtml().formatText(ui->msgTextOrg->document(), QString::fromUtf8(mDescription.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
|
||||
ui->msgTextOrg->setHtml(msgTxt);
|
||||
} else {
|
||||
ui->msgTextOrg->clear();
|
||||
}
|
||||
fillStructureTree(false);
|
||||
fillStructureTree(true);
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::showXPathFrame(bool show)
|
||||
void PreviewFeedDialog::transformationTypeChanged()
|
||||
{
|
||||
ui->xpathFrame->setVisible(show);
|
||||
|
||||
if (show) {
|
||||
ui->xpathPushButton->setToolTip(tr("Hide XPath expressions"));
|
||||
ui->xpathPushButton->setIcon(QIcon(":images/show_toolbox_frame.png"));
|
||||
} else {
|
||||
ui->xpathPushButton->setToolTip(tr("Show XPath expressions"));
|
||||
ui->xpathPushButton->setIcon(QIcon(":images/hide_toolbox_frame.png"));
|
||||
}
|
||||
showStructureFrame();
|
||||
processTransformation();
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::xpathListCustomPopupMenu(QPoint /*point*/)
|
||||
@ -396,7 +441,7 @@ void PreviewFeedDialog::xpathListCustomPopupMenu(QPoint /*point*/)
|
||||
|
||||
void PreviewFeedDialog::xpathCloseEditor(QWidget */*editor*/, QAbstractItemDelegate::EndEditHint /*hint*/)
|
||||
{
|
||||
processXPath();
|
||||
processTransformation();
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::addXPath()
|
||||
@ -468,7 +513,7 @@ void PreviewFeedDialog::removeXPath()
|
||||
delete(item);
|
||||
}
|
||||
|
||||
processXPath();
|
||||
processTransformation();
|
||||
}
|
||||
|
||||
int PreviewFeedDialog::getMsgPos()
|
||||
@ -491,10 +536,10 @@ void PreviewFeedDialog::setFeedInfo(const QString &info)
|
||||
ui->feedInfoLabel->setVisible(!info.isEmpty());
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::setXPathInfo(const QString &info)
|
||||
void PreviewFeedDialog::setTransformationInfo(const QString &info)
|
||||
{
|
||||
ui->xpathInfoLabel->setText(info);
|
||||
ui->xpathInfoLabel->setVisible(!info.isEmpty());
|
||||
ui->transformationInfoLabel->setText(info);
|
||||
ui->transformationInfoLabel->setVisible(!info.isEmpty());
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::fillFeedInfo(const FeedInfo &feedInfo)
|
||||
@ -551,8 +596,9 @@ void PreviewFeedDialog::updateMsg()
|
||||
if (mMsgId.empty() || !mFeedReader->getMsgInfo(mFeedId, mMsgId, msgInfo)) {
|
||||
ui->msgTitle->clear();
|
||||
ui->msgText->clear();
|
||||
ui->msgTextOrg->clear();
|
||||
mDescription.clear();
|
||||
mDescriptionXPath.clear();
|
||||
mDescriptionTransformed.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -561,8 +607,15 @@ void PreviewFeedDialog::updateMsg()
|
||||
/* store description */
|
||||
mDescription = msgInfo.description;
|
||||
|
||||
if (ui->msgTextOrg->isVisible()) {
|
||||
QString msgTxt = RsHtml().formatText(ui->msgTextOrg->document(), QString::fromUtf8(mDescription.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
|
||||
ui->msgTextOrg->setHtml(msgTxt);
|
||||
}
|
||||
|
||||
showStructureFrame();
|
||||
|
||||
/* process xpath */
|
||||
processXPath();
|
||||
processTransformation();
|
||||
}
|
||||
|
||||
static void buildNodeText(HTMLWrapper &html, xmlNodePtr node, QString &text)
|
||||
@ -699,44 +752,52 @@ static void examineChildElements(QTreeWidget *treeWidget, HTMLWrapper &html, QLi
|
||||
// treeWidget->setItemWidget(item, 0, label);
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::fillStructureTree()
|
||||
void PreviewFeedDialog::fillStructureTree(bool transform)
|
||||
{
|
||||
if (!ui->structureTreeWidget->isVisible()) {
|
||||
return;
|
||||
if (transform && ui->structureTreeWidget->isVisible()) {
|
||||
if (mDescriptionTransformed.empty()) {
|
||||
ui->structureTreeWidget->clear();
|
||||
} else {
|
||||
HTMLWrapper html;
|
||||
if (html.readHTML(mDescriptionTransformed.c_str(), "")) {
|
||||
xmlNodePtr root = html.getRootElement();
|
||||
if (root) {
|
||||
QList<xmlNodePtr> nodes;
|
||||
nodes.push_back(root);
|
||||
examineChildElements(ui->structureTreeWidget, html, nodes, ui->structureTreeWidget->invisibleRootItem());
|
||||
ui->structureTreeWidget->resizeColumnToContents(0);
|
||||
}
|
||||
} else {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem;
|
||||
item->setText(0, tr("Error parsing document") + ": " + QString::fromUtf8(html.lastError().c_str()));
|
||||
ui->structureTreeWidget->addTopLevelItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (ui->structureTreeWidget->topLevelItemCount() > 0) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (mDescriptionXPath.empty()) {
|
||||
ui->structureTreeWidget->clear();
|
||||
return;
|
||||
if (!transform && ui->structureTreeWidgetOrg->isVisible()) {
|
||||
if (mDescription.empty()) {
|
||||
ui->structureTreeWidgetOrg->clear();
|
||||
} else {
|
||||
HTMLWrapper html;
|
||||
if (html.readHTML(mDescription.c_str(), "")) {
|
||||
xmlNodePtr root = html.getRootElement();
|
||||
if (root) {
|
||||
QList<xmlNodePtr> nodes;
|
||||
nodes.push_back(root);
|
||||
examineChildElements(ui->structureTreeWidgetOrg, html, nodes, ui->structureTreeWidgetOrg->invisibleRootItem());
|
||||
ui->structureTreeWidgetOrg->resizeColumnToContents(0);
|
||||
}
|
||||
} else {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem;
|
||||
item->setText(0, tr("Error parsing document") + ": " + QString::fromUtf8(html.lastError().c_str()));
|
||||
ui->structureTreeWidgetOrg->addTopLevelItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool useXPath = ui->useXPathCheckBox->isChecked();
|
||||
|
||||
HTMLWrapper html;
|
||||
if (!html.readHTML(useXPath ? mDescriptionXPath.c_str() : mDescription.c_str(), "")) {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem;
|
||||
item->setText(0, tr("Error parsing document"));
|
||||
ui->structureTreeWidget->addTopLevelItem(item);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
xmlNodePtr root = html.getRootElement();
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<xmlNodePtr> nodes;
|
||||
nodes.push_back(root);
|
||||
examineChildElements(ui->structureTreeWidget, html, nodes, ui->structureTreeWidget->invisibleRootItem());
|
||||
ui->structureTreeWidget->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::getXPaths(std::list<std::string> &xpathsToUse, std::list<std::string> &xpathsToRemove)
|
||||
RsFeedTransformationType PreviewFeedDialog::getData(std::list<std::string> &xpathsToUse, std::list<std::string> &xpathsToRemove, std::string &xslt)
|
||||
{
|
||||
xpathsToUse.clear();
|
||||
xpathsToRemove.clear();
|
||||
@ -751,24 +812,40 @@ void PreviewFeedDialog::getXPaths(std::list<std::string> &xpathsToUse, std::list
|
||||
for (row = 0; row < rowCount; ++row) {
|
||||
xpathsToRemove.push_back(ui->xpathRemoveListWidget->item(row)->text().toUtf8().constData());
|
||||
}
|
||||
|
||||
xslt = ui->xsltTextEdit->toPlainText().toUtf8().constData();
|
||||
|
||||
return (RsFeedTransformationType) ui->transformationTypeComboBox->itemData(ui->transformationTypeComboBox->currentIndex()).toInt();
|
||||
}
|
||||
|
||||
void PreviewFeedDialog::processXPath()
|
||||
void PreviewFeedDialog::processTransformation()
|
||||
{
|
||||
std::list<std::string> xpathsToUse;
|
||||
std::list<std::string> xpathsToRemove;
|
||||
std::string xslt;
|
||||
|
||||
getXPaths(xpathsToUse, xpathsToRemove);
|
||||
RsFeedTransformationType transformationType = getData(xpathsToUse, xpathsToRemove, xslt);
|
||||
|
||||
mDescriptionXPath = mDescription;
|
||||
mDescriptionTransformed = mDescription;
|
||||
std::string errorString;
|
||||
RsFeedReaderErrorState result = mFeedReader->processXPath(xpathsToUse, xpathsToRemove, mDescriptionXPath, errorString);
|
||||
setXPathInfo(FeedReaderStringDefs::errorString(result, errorString));
|
||||
|
||||
RsFeedReaderErrorState result = RS_FEED_ERRORSTATE_OK;
|
||||
switch (transformationType) {
|
||||
case RS_FEED_TRANSFORMATION_TYPE_NONE:
|
||||
break;
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XPATH:
|
||||
result = mFeedReader->processXPath(xpathsToUse, xpathsToRemove, mDescriptionTransformed, errorString);
|
||||
break;
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XSLT:
|
||||
result = mFeedReader->processXslt(xslt, mDescriptionTransformed, errorString);
|
||||
break;
|
||||
}
|
||||
setTransformationInfo(FeedReaderStringDefs::errorString(result, errorString));
|
||||
|
||||
/* fill message */
|
||||
QString msgTxt = RsHtml().formatText(ui->msgText->document(), QString::fromUtf8(mDescriptionXPath.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
|
||||
QString msgTxt = RsHtml().formatText(ui->msgText->document(), QString::fromUtf8(mDescriptionTransformed.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
|
||||
ui->msgText->setHtml(msgTxt);
|
||||
|
||||
/* fill structure */
|
||||
fillStructureTree();
|
||||
fillStructureTree(true);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <QDialog>
|
||||
#include <QItemDelegate>
|
||||
|
||||
#include "interface/rsFeedReader.h"
|
||||
|
||||
namespace Ui {
|
||||
class PreviewFeedDialog;
|
||||
}
|
||||
@ -54,12 +56,12 @@ class FeedInfo;
|
||||
class PreviewFeedDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
PreviewFeedDialog(RsFeedReader *feedReader, FeedReaderNotify *notify, const FeedInfo &feedInfo, QWidget *parent = 0);
|
||||
~PreviewFeedDialog();
|
||||
|
||||
void getXPaths(std::list<std::string> &xpathsToUse, std::list<std::string> &xpathsToRemove);
|
||||
RsFeedTransformationType getData(std::list<std::string> &xpathsToUse, std::list<std::string> &xpathsToRemove, std::string &xslt);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev);
|
||||
@ -67,14 +69,13 @@ protected:
|
||||
private slots:
|
||||
void previousMsg();
|
||||
void nextMsg();
|
||||
void showStructureFrame(bool show = false);
|
||||
void showXPathFrame(bool show);
|
||||
void showStructureFrame();
|
||||
void xpathListCustomPopupMenu(QPoint point);
|
||||
void xpathCloseEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint);
|
||||
void addXPath();
|
||||
void editXPath();
|
||||
void removeXPath();
|
||||
void fillStructureTree();
|
||||
void transformationTypeChanged();
|
||||
|
||||
/* FeedReaderNotify */
|
||||
void feedChanged(const QString &feedId, int type);
|
||||
@ -84,11 +85,12 @@ private:
|
||||
void processSettings(bool load);
|
||||
int getMsgPos();
|
||||
void setFeedInfo(const QString &info);
|
||||
void setXPathInfo(const QString &info);
|
||||
void setTransformationInfo(const QString &info);
|
||||
void fillFeedInfo(const FeedInfo &feedInfo);
|
||||
void updateMsgCount();
|
||||
void updateMsg();
|
||||
void processXPath();
|
||||
void fillStructureTree(bool transform);
|
||||
void processTransformation();
|
||||
|
||||
RsFeedReader *mFeedReader;
|
||||
FeedReaderNotify *mNotify;
|
||||
@ -96,7 +98,7 @@ private:
|
||||
std::string mMsgId;
|
||||
std::list<std::string> mMsgIds;
|
||||
std::string mDescription;
|
||||
std::string mDescriptionXPath;
|
||||
std::string mDescriptionTransformed;
|
||||
|
||||
Ui::PreviewFeedDialog *ui;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,9 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
class RsFeedReader;
|
||||
extern RsFeedReader *rsFeedReader;
|
||||
|
||||
enum RsFeedReaderErrorState {
|
||||
RS_FEED_ERRORSTATE_OK = 0,
|
||||
|
||||
@ -47,13 +50,12 @@ enum RsFeedReaderErrorState {
|
||||
RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR = 150,
|
||||
RS_FEED_ERRORSTATE_PROCESS_XPATH_INTERNAL_ERROR = 151,
|
||||
RS_FEED_ERRORSTATE_PROCESS_XPATH_WRONG_EXPRESSION = 152,
|
||||
RS_FEED_ERRORSTATE_PROCESS_XPATH_NO_RESULT = 153
|
||||
RS_FEED_ERRORSTATE_PROCESS_XPATH_NO_RESULT = 153,
|
||||
RS_FEED_ERRORSTATE_PROCESS_XSLT_FORMAT_ERROR = 154,
|
||||
RS_FEED_ERRORSTATE_PROCESS_XSLT_TRANSFORM_ERROR = 155,
|
||||
RS_FEED_ERRORSTATE_PROCESS_XSLT_NO_RESULT = 156
|
||||
};
|
||||
|
||||
|
||||
class RsFeedReader;
|
||||
extern RsFeedReader *rsFeedReader;
|
||||
|
||||
enum RsFeedAddResult
|
||||
{
|
||||
RS_FEED_ADD_RESULT_SUCCESS,
|
||||
@ -64,6 +66,13 @@ enum RsFeedAddResult
|
||||
RS_FEED_ADD_RESULT_FEED_IS_NO_FOLDER
|
||||
};
|
||||
|
||||
enum RsFeedTransformationType
|
||||
{
|
||||
RS_FEED_TRANSFORMATION_TYPE_NONE = 0,
|
||||
RS_FEED_TRANSFORMATION_TYPE_XPATH = 1,
|
||||
RS_FEED_TRANSFORMATION_TYPE_XSLT = 2
|
||||
};
|
||||
|
||||
class FeedInfo
|
||||
{
|
||||
public:
|
||||
@ -96,28 +105,31 @@ public:
|
||||
flag.embedImages = false;
|
||||
flag.saveCompletePage = false;
|
||||
flag.preview = false;
|
||||
transformationType = RS_FEED_TRANSFORMATION_TYPE_NONE;
|
||||
}
|
||||
|
||||
std::string feedId;
|
||||
std::string parentId;
|
||||
std::string url;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string icon;
|
||||
std::string user;
|
||||
std::string password;
|
||||
std::string proxyAddress;
|
||||
uint16_t proxyPort;
|
||||
uint32_t updateInterval;
|
||||
time_t lastUpdate;
|
||||
uint32_t storageTime;
|
||||
std::string forumId;
|
||||
WorkState workstate;
|
||||
RsFeedReaderErrorState errorState;
|
||||
std::string errorString;
|
||||
std::string feedId;
|
||||
std::string parentId;
|
||||
std::string url;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string icon;
|
||||
std::string user;
|
||||
std::string password;
|
||||
std::string proxyAddress;
|
||||
uint16_t proxyPort;
|
||||
uint32_t updateInterval;
|
||||
time_t lastUpdate;
|
||||
uint32_t storageTime;
|
||||
std::string forumId;
|
||||
WorkState workstate;
|
||||
RsFeedReaderErrorState errorState;
|
||||
std::string errorString;
|
||||
|
||||
std::list<std::string> xpathsToUse;
|
||||
std::list<std::string> xpathsToRemove;
|
||||
RsFeedTransformationType transformationType;
|
||||
std::list<std::string> xpathsToUse;
|
||||
std::list<std::string> xpathsToRemove;
|
||||
std::string xslt;
|
||||
|
||||
struct {
|
||||
bool folder : 1;
|
||||
@ -152,6 +164,7 @@ public:
|
||||
std::string link;
|
||||
std::string author;
|
||||
std::string description;
|
||||
std::string descriptionTransformed;
|
||||
time_t pubDate;
|
||||
|
||||
struct {
|
||||
@ -202,8 +215,10 @@ public:
|
||||
virtual bool getFeedMsgIdList(const std::string &feedId, std::list<std::string> &msgIds) = 0;
|
||||
virtual bool processFeed(const std::string &feedId) = 0;
|
||||
virtual bool setMessageRead(const std::string &feedId, const std::string &msgId, bool read) = 0;
|
||||
virtual bool retransformMsg(const std::string &feedId, const std::string &msgId) = 0;
|
||||
|
||||
virtual RsFeedReaderErrorState processXPath(const std::list<std::string> &xpathsToUse, const std::list<std::string> &xpathsToRemove, std::string &description, std::string &errorString) = 0;
|
||||
virtual RsFeedReaderErrorState processXslt(const std::string &xslt, std::string &description, std::string &errorString) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -88,8 +88,10 @@ static void feedToInfo(const RsFeedReaderFeed *feed, FeedInfo &info)
|
||||
info.errorState = feed->errorState;
|
||||
info.errorString = feed->errorString;
|
||||
|
||||
info.transformationType = feed->transformationType;
|
||||
info.xpathsToUse = feed->xpathsToUse.ids;
|
||||
info.xpathsToRemove = feed->xpathsToRemove.ids;
|
||||
info.xslt = feed->xslt;
|
||||
|
||||
info.flag.folder = (feed->flag & RS_FEED_FLAG_FOLDER);
|
||||
info.flag.infoFromFeed = (feed->flag & RS_FEED_FLAG_INFO_FROM_FEED);
|
||||
@ -144,8 +146,10 @@ static void infoToFeed(const FeedInfo &info, RsFeedReaderFeed *feed, bool add)
|
||||
feed->forumId = info.forumId;
|
||||
}
|
||||
|
||||
feed->transformationType = info.transformationType;
|
||||
feed->xpathsToUse.ids = info.xpathsToUse;
|
||||
feed->xpathsToRemove.ids = info.xpathsToRemove;
|
||||
feed->xslt = info.xslt;
|
||||
|
||||
// feed->preview = info.flag.preview;
|
||||
|
||||
@ -200,6 +204,7 @@ static void feedMsgToInfo(const RsFeedReaderMsg *msg, FeedMsgInfo &info)
|
||||
info.link = msg->link;
|
||||
info.author = msg->author;
|
||||
info.description = msg->description;
|
||||
info.descriptionTransformed = msg->descriptionTransformed;
|
||||
info.pubDate = msg->pubDate;
|
||||
|
||||
info.flag.isnew = (msg->flag & RS_FEEDMSG_FLAG_NEW);
|
||||
@ -491,6 +496,7 @@ RsFeedAddResult p3FeedReader::setFeed(const std::string &feedId, const FeedInfo
|
||||
forumId = fi->forumId;
|
||||
librs::util::ConvertUtf8ToUtf16(fi->name, forumInfo.forumName);
|
||||
librs::util::ConvertUtf8ToUtf16(fi->description, forumInfo.forumDesc);
|
||||
forumInfo.forumName.insert(0, FEEDREADER_FORUM_PREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
@ -759,8 +765,11 @@ bool p3FeedReader::removeMsg(const std::string &feedId, const std::string &msgId
|
||||
return false;
|
||||
}
|
||||
|
||||
msgIt->second->flag |= RS_FEEDMSG_FLAG_DELETED | RS_FEEDMSG_FLAG_READ;
|
||||
msgIt->second->flag &= ~RS_FEEDMSG_FLAG_NEW;
|
||||
RsFeedReaderMsg *mi = msgIt->second;
|
||||
mi->flag |= RS_FEEDMSG_FLAG_DELETED | RS_FEEDMSG_FLAG_READ;
|
||||
mi->flag &= ~RS_FEEDMSG_FLAG_NEW;
|
||||
mi->description.clear();
|
||||
mi->descriptionTransformed.clear();
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
@ -805,8 +814,11 @@ bool p3FeedReader::removeMsgs(const std::string &feedId, const std::list<std::st
|
||||
continue;
|
||||
}
|
||||
|
||||
msgIt->second->flag |= RS_FEEDMSG_FLAG_DELETED | RS_FEEDMSG_FLAG_READ;
|
||||
msgIt->second->flag &= ~RS_FEEDMSG_FLAG_NEW;
|
||||
RsFeedReaderMsg *mi = msgIt->second;
|
||||
mi->flag |= RS_FEEDMSG_FLAG_DELETED | RS_FEEDMSG_FLAG_READ;
|
||||
mi->flag &= ~RS_FEEDMSG_FLAG_NEW;
|
||||
mi->description.clear();
|
||||
mi->descriptionTransformed.clear();
|
||||
|
||||
removedMsgs.push_back(*idIt);
|
||||
}
|
||||
@ -1121,11 +1133,74 @@ bool p3FeedReader::setMessageRead(const std::string &feedId, const std::string &
|
||||
return true;
|
||||
}
|
||||
|
||||
bool p3FeedReader::retransformMsg(const std::string &feedId, const std::string &msgId)
|
||||
{
|
||||
bool msgChanged = false;
|
||||
bool feedChanged = false;
|
||||
|
||||
{
|
||||
RsStackMutex stack(mFeedReaderMtx); /******* LOCK STACK MUTEX *********/
|
||||
|
||||
std::map<std::string, RsFeedReaderFeed*>::iterator feedIt = mFeeds.find(feedId);
|
||||
if (feedIt == mFeeds.end()) {
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReader::setMessageRead - feed " << feedId << " not found" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
RsFeedReaderFeed *fi = feedIt->second;
|
||||
|
||||
std::map<std::string, RsFeedReaderMsg*>::iterator msgIt;
|
||||
msgIt = fi->msgs.find(msgId);
|
||||
if (msgIt == fi->msgs.end()) {
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReader::setMessageRead - msg " << msgId << " not found" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
RsFeedReaderMsg *mi = msgIt->second;
|
||||
|
||||
std::string errorString;
|
||||
std::string descriptionTransformed = mi->descriptionTransformed;
|
||||
if (p3FeedReaderThread::processTransformation(*fi, mi, errorString) == RS_FEED_ERRORSTATE_OK) {
|
||||
if (mi->descriptionTransformed != descriptionTransformed) {
|
||||
msgChanged = true;
|
||||
}
|
||||
} else {
|
||||
if (!errorString.empty()) {
|
||||
fi->errorString = errorString;
|
||||
feedChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (feedChanged || msgChanged) {
|
||||
IndicateConfigChanged();
|
||||
if (mNotify) {
|
||||
if (feedChanged) {
|
||||
mNotify->notifyFeedChanged(feedId, NOTIFY_TYPE_MOD);
|
||||
}
|
||||
if (msgChanged) {
|
||||
mNotify->notifyMsgChanged(feedId, msgId, NOTIFY_TYPE_MOD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReader::processXPath(const std::list<std::string> &xpathsToUse, const std::list<std::string> &xpathsToRemove, std::string &description, std::string &errorString)
|
||||
{
|
||||
return p3FeedReaderThread::processXPath(xpathsToUse, xpathsToRemove, description, errorString);
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReader::processXslt(const std::string &xslt, std::string &description, std::string &errorString)
|
||||
{
|
||||
return p3FeedReaderThread::processXslt(xslt, description, errorString);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/****************************** p3Service **********************************/
|
||||
/***************************************************************************/
|
||||
@ -1776,7 +1851,8 @@ void p3FeedReader::onProcessSuccess_addMsgs(const std::string &feedId, std::list
|
||||
if (forum) {
|
||||
miNew->flag = RS_FEEDMSG_FLAG_DELETED;
|
||||
forumMsgs.push_back(*miNew);
|
||||
// miNew->description.clear();
|
||||
miNew->description.clear();
|
||||
miNew->descriptionTransformed.clear();
|
||||
} else {
|
||||
miNew->flag = RS_FEEDMSG_FLAG_NEW;
|
||||
addedMsgs.push_back(miNew->msgId);
|
||||
@ -1816,7 +1892,7 @@ void p3FeedReader::onProcessSuccess_addMsgs(const std::string &feedId, std::list
|
||||
forumMsgInfo.forumId = forumId;
|
||||
librs::util::ConvertUtf8ToUtf16(mi.title, forumMsgInfo.title);
|
||||
|
||||
std::string description = mi.description;
|
||||
std::string description = mi.descriptionTransformed.empty() ? mi.description : mi.descriptionTransformed;
|
||||
/* add link */
|
||||
if (!mi.link.empty()) {
|
||||
description += "<br><a href=\"" + mi.link + "\">" + mi.link + "</a>";
|
||||
|
@ -62,8 +62,10 @@ public:
|
||||
virtual bool getFeedMsgIdList(const std::string &feedId, std::list<std::string> &msgIds);
|
||||
virtual bool processFeed(const std::string &feedId);
|
||||
virtual bool setMessageRead(const std::string &feedId, const std::string &msgId, bool read);
|
||||
virtual bool retransformMsg(const std::string &feedId, const std::string &msgId);
|
||||
|
||||
virtual RsFeedReaderErrorState processXPath(const std::list<std::string> &xpathsToUse, const std::list<std::string> &xpathsToRemove, std::string &description, std::string &errorString);
|
||||
virtual RsFeedReaderErrorState processXslt(const std::string &xslt, std::string &description, std::string &errorString);
|
||||
|
||||
/****************** p3Service STUFF ******************/
|
||||
virtual int tick();
|
||||
|
@ -117,6 +117,10 @@ void p3FeedReaderThread::run()
|
||||
delete (*it1);
|
||||
}
|
||||
} else {
|
||||
result = processTransformation(feed, mi, errorString);
|
||||
if (result != RS_FEED_ERRORSTATE_OK) {
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
@ -258,14 +262,14 @@ static bool getFavicon(CURLWrapper &CURL, const std::string &url, std::string &i
|
||||
return result;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReaderThread::download(const RsFeedReaderFeed &feed, std::string &content, std::string &icon, std::string &error)
|
||||
RsFeedReaderErrorState p3FeedReaderThread::download(const RsFeedReaderFeed &feed, std::string &content, std::string &icon, std::string &errorString)
|
||||
{
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::download - feed " << feed.feedId << " (" << feed.name << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
content.clear();
|
||||
error.clear();
|
||||
errorString.clear();
|
||||
|
||||
RsFeedReaderErrorState result;
|
||||
|
||||
@ -291,7 +295,7 @@ RsFeedReaderErrorState p3FeedReaderThread::download(const RsFeedReaderFeed &feed
|
||||
result = RS_FEED_ERRORSTATE_OK;
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_DOWNLOAD_UNKNOWN_CONTENT_TYPE;
|
||||
error = contentType;
|
||||
errorString = contentType;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -300,17 +304,17 @@ RsFeedReaderErrorState p3FeedReaderThread::download(const RsFeedReaderFeed &feed
|
||||
break;
|
||||
default:
|
||||
result = RS_FEED_ERRORSTATE_DOWNLOAD_UNKOWN_RESPONSE_CODE;
|
||||
rs_sprintf(error, "%ld", responseCode);
|
||||
rs_sprintf(errorString, "%ld", responseCode);
|
||||
}
|
||||
|
||||
getFavicon(CURL, feed.url, icon);
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_DOWNLOAD_ERROR;
|
||||
error = curl_easy_strerror(code);
|
||||
errorString = curl_easy_strerror(code);
|
||||
}
|
||||
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::download - feed " << feed.feedId << " (" << feed.name << "), result " << result << ", error = " << error << std::endl;
|
||||
std::cerr << "p3FeedReaderThread::download - feed " << feed.feedId << " (" << feed.name << "), result " << result << ", error = " << errorString << std::endl;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
@ -805,7 +809,7 @@ static time_t parseISO8601Date(const std::string &pubDate)
|
||||
return result;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReaderThread::process(const RsFeedReaderFeed &feed, std::list<RsFeedReaderMsg*> &entries, std::string &error)
|
||||
RsFeedReaderErrorState p3FeedReaderThread::process(const RsFeedReaderFeed &feed, std::list<RsFeedReaderMsg*> &entries, std::string &errorString)
|
||||
{
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::process - feed " << feed.feedId << " (" << feed.name << ")" << std::endl;
|
||||
@ -826,7 +830,7 @@ RsFeedReaderErrorState p3FeedReaderThread::process(const RsFeedReaderFeed &feed,
|
||||
feedFormat = FORMAT_ATOM;
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_UNKNOWN_FORMAT;
|
||||
error = "Only RSS, RDF or ATOM supported";
|
||||
errorString = "Only RSS, RDF or ATOM supported";
|
||||
}
|
||||
|
||||
if (result == RS_FEED_ERRORSTATE_OK) {
|
||||
@ -962,19 +966,23 @@ RsFeedReaderErrorState p3FeedReaderThread::process(const RsFeedReaderFeed &feed,
|
||||
}
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_UNKNOWN_FORMAT;
|
||||
error = "Channel not found";
|
||||
errorString = "Channel not found";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_UNKNOWN_FORMAT;
|
||||
error = "Can't read document";
|
||||
errorString = "Can't read document";
|
||||
}
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_INTERNAL_ERROR;
|
||||
errorString = xml.lastError();
|
||||
}
|
||||
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::process - feed " << feed.feedId << " (" << feed.name << "), result " << result << ", error = " << error << std::endl;
|
||||
std::cerr << "p3FeedReaderThread::process - feed " << feed.feedId << " (" << feed.name << "), result " << result << ", error = " << errorString << std::endl;
|
||||
if (result == RS_FEED_ERRORSTATE_PROCESS_INTERNAL_ERROR) {
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
@ -1059,7 +1067,7 @@ RsFeedReaderErrorState p3FeedReaderThread::processMsg(const RsFeedReaderFeed &fe
|
||||
}
|
||||
|
||||
/* check if string contains xml chars (very simple test) */
|
||||
if (msg->description.find('<') == std::string::npos) {
|
||||
if (msg->description.find('<') == std::string::npos && feed.transformationType == RS_FEED_TRANSFORMATION_TYPE_NONE) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1164,10 +1172,6 @@ RsFeedReaderErrorState p3FeedReaderThread::processMsg(const RsFeedReaderFeed &fe
|
||||
}
|
||||
nodesToDelete.clear();
|
||||
|
||||
if (isRunning() && !feed.preview) {
|
||||
result = processXPath(feed.xpathsToUse.ids, feed.xpathsToRemove.ids, html, errorString);
|
||||
}
|
||||
|
||||
if (isRunning() && result == RS_FEED_ERRORSTATE_OK) {
|
||||
unsigned int xpathCount;
|
||||
unsigned int xpathIndex;
|
||||
@ -1241,8 +1245,10 @@ RsFeedReaderErrorState p3FeedReaderThread::processMsg(const RsFeedReaderFeed &fe
|
||||
if (result == RS_FEED_ERRORSTATE_OK) {
|
||||
if (isRunning()) {
|
||||
if (!html.saveHTML(msg->description)) {
|
||||
errorString = html.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processHTML - feed " << feed.feedId << " (" << feed.name << ") cannot dump html" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_INTERNAL_ERROR;
|
||||
}
|
||||
@ -1255,8 +1261,10 @@ RsFeedReaderErrorState p3FeedReaderThread::processMsg(const RsFeedReaderFeed &fe
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
} else {
|
||||
errorString = html.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processHTML - feed " << feed.feedId << " (" << feed.name << ") cannot read html" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
@ -1265,6 +1273,30 @@ RsFeedReaderErrorState p3FeedReaderThread::processMsg(const RsFeedReaderFeed &fe
|
||||
return result;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReaderThread::processTransformation(const RsFeedReaderFeed &feed, RsFeedReaderMsg *msg, std::string &errorString)
|
||||
{
|
||||
RsFeedReaderErrorState result = RS_FEED_ERRORSTATE_OK;
|
||||
|
||||
switch (feed.transformationType) {
|
||||
case RS_FEED_TRANSFORMATION_TYPE_NONE:
|
||||
break;
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XPATH:
|
||||
msg->descriptionTransformed = msg->description;
|
||||
result = processXPath(feed.xpathsToUse.ids, feed.xpathsToRemove.ids, msg->descriptionTransformed, errorString);
|
||||
break;
|
||||
case RS_FEED_TRANSFORMATION_TYPE_XSLT:
|
||||
msg->descriptionTransformed = msg->description;
|
||||
result = processXslt(feed.xslt, msg->descriptionTransformed, errorString);
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg->descriptionTransformed == msg->description) {
|
||||
msg->descriptionTransformed.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReaderThread::processXPath(const std::list<std::string> &xpathsToUse, const std::list<std::string> &xpathsToRemove, HTMLWrapper &html, std::string &errorString)
|
||||
{
|
||||
long todo_fill_errorString;
|
||||
@ -1376,8 +1408,6 @@ RsFeedReaderErrorState p3FeedReaderThread::processXPath(const std::list<std::str
|
||||
|
||||
RsFeedReaderErrorState result = RS_FEED_ERRORSTATE_OK;
|
||||
|
||||
long todo_fill_errorString;
|
||||
|
||||
/* process description */
|
||||
long todo; // encoding
|
||||
HTMLWrapper html;
|
||||
@ -1388,8 +1418,10 @@ RsFeedReaderErrorState p3FeedReaderThread::processXPath(const std::list<std::str
|
||||
|
||||
if (result == RS_FEED_ERRORSTATE_OK) {
|
||||
if (!html.saveHTML(description)) {
|
||||
errorString = html.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXPath - cannot dump html" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_INTERNAL_ERROR;
|
||||
}
|
||||
@ -1398,11 +1430,131 @@ RsFeedReaderErrorState p3FeedReaderThread::processXPath(const std::list<std::str
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXPath - no root element" << std::endl;
|
||||
#endif
|
||||
errorString = "No root element found";
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
} else {
|
||||
errorString = html.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXPath - cannot read html" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReaderThread::processXslt(const std::string &xslt, HTMLWrapper &html, std::string &errorString)
|
||||
{
|
||||
XMLWrapper style;
|
||||
if (!style.readXML(xslt.c_str())) {
|
||||
errorString = style.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXslt - error loading style" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
return RS_FEED_ERRORSTATE_PROCESS_XSLT_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
XMLWrapper xmlResult;
|
||||
if (!html.transform(style, xmlResult)) {
|
||||
errorString = html.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXslt - error transform" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
return RS_FEED_ERRORSTATE_PROCESS_XSLT_TRANSFORM_ERROR;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState result = RS_FEED_ERRORSTATE_OK;
|
||||
|
||||
xmlNodePtr root = xmlResult.getRootElement();
|
||||
if (root) {
|
||||
if (xmlResult.nodeName(root) == "html") {
|
||||
if (root->children && xmlResult.nodeName(root->children) == "body") {
|
||||
root = root->children->children;
|
||||
}
|
||||
}
|
||||
HTMLWrapper htmlNew;
|
||||
if (htmlNew.createHTML()) {
|
||||
xmlNodePtr body = htmlNew.getBody();
|
||||
if (body) {
|
||||
/* copy result nodes */
|
||||
xmlNodePtr node;
|
||||
for (node = root; node; node = node->next) {
|
||||
xmlNodePtr newNode = xmlCopyNode(node, 1);
|
||||
if (newNode) {
|
||||
if (!xmlAddChild(body, newNode)) {
|
||||
xmlFreeNode(newNode);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_INTERNAL_ERROR;
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXslt - node copy error" << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
} else {
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
|
||||
if (result == RS_FEED_ERRORSTATE_OK) {
|
||||
html = htmlNew;
|
||||
}
|
||||
} else {
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXslt - no result" << std::endl;
|
||||
#endif
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_XSLT_NO_RESULT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState p3FeedReaderThread::processXslt(const std::string &xslt, std::string &description, std::string &errorString)
|
||||
{
|
||||
if (xslt.empty()) {
|
||||
return RS_FEED_ERRORSTATE_OK;
|
||||
}
|
||||
|
||||
RsFeedReaderErrorState result = RS_FEED_ERRORSTATE_OK;
|
||||
|
||||
/* process description */
|
||||
long todo; // encoding
|
||||
HTMLWrapper html;
|
||||
if (html.readHTML(description.c_str(), "")) {
|
||||
xmlNodePtr root = html.getRootElement();
|
||||
if (root) {
|
||||
result = processXslt(xslt, html, errorString);
|
||||
|
||||
if (result == RS_FEED_ERRORSTATE_OK) {
|
||||
if (!html.saveHTML(description)) {
|
||||
errorString = html.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXslt - cannot dump html" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXslt - no root element" << std::endl;
|
||||
#endif
|
||||
errorString = "No root element found";
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
} else {
|
||||
errorString = html.lastError();
|
||||
#ifdef FEEDREADER_DEBUG
|
||||
std::cerr << "p3FeedReaderThread::processXslt - cannot read html" << std::endl;
|
||||
std::cerr << " Error: " << errorString << std::endl;
|
||||
#endif
|
||||
result = RS_FEED_ERRORSTATE_PROCESS_HTML_ERROR;
|
||||
}
|
||||
|
@ -51,11 +51,15 @@ public:
|
||||
static RsFeedReaderErrorState processXPath(const std::list<std::string> &xpathsToUse, const std::list<std::string> &xpathsToRemove, std::string &description, std::string &errorString);
|
||||
static RsFeedReaderErrorState processXPath(const std::list<std::string> &xpathsToUse, const std::list<std::string> &xpathsToRemove, HTMLWrapper &html, std::string &errorString);
|
||||
|
||||
static RsFeedReaderErrorState processXslt(const std::string &xslt, std::string &description, std::string &errorString);
|
||||
static RsFeedReaderErrorState processXslt(const std::string &xslt, HTMLWrapper &html, std::string &errorString);
|
||||
|
||||
static RsFeedReaderErrorState processTransformation(const RsFeedReaderFeed &feed, RsFeedReaderMsg *msg, std::string &errorString);
|
||||
private:
|
||||
virtual void run();
|
||||
|
||||
RsFeedReaderErrorState download(const RsFeedReaderFeed &feed, std::string &content, std::string &icon, std::string &error);
|
||||
RsFeedReaderErrorState process(const RsFeedReaderFeed &feed, std::list<RsFeedReaderMsg*> &entries, std::string &error);
|
||||
RsFeedReaderErrorState download(const RsFeedReaderFeed &feed, std::string &content, std::string &icon, std::string &errorString);
|
||||
RsFeedReaderErrorState process(const RsFeedReaderFeed &feed, std::list<RsFeedReaderMsg*> &entries, std::string &errorString);
|
||||
|
||||
std::string getProxyForFeed(const RsFeedReaderFeed &feed);
|
||||
RsFeedReaderErrorState processMsg(const RsFeedReaderFeed &feed, RsFeedReaderMsg *msg, std::string &errorString);
|
||||
|
@ -51,8 +51,10 @@ void RsFeedReaderFeed::clear()
|
||||
icon.clear();
|
||||
errorState = RS_FEED_ERRORSTATE_OK;
|
||||
errorString.clear();
|
||||
transformationType = RS_FEED_TRANSFORMATION_TYPE_NONE;
|
||||
xpathsToUse.ids.clear();
|
||||
xpathsToRemove.ids.clear();
|
||||
xslt.clear();
|
||||
|
||||
preview = false;
|
||||
workstate = WAITING;
|
||||
@ -85,8 +87,10 @@ uint32_t RsFeedReaderSerialiser::sizeFeed(RsFeedReaderFeed *item)
|
||||
s += GetTlvStringSize(item->forumId);
|
||||
s += sizeof(uint32_t); /* errorstate */
|
||||
s += GetTlvStringSize(item->errorString);
|
||||
s += sizeof(uint32_t); /* transformationType */
|
||||
s += item->xpathsToUse.TlvSize();
|
||||
s += item->xpathsToRemove.TlvSize();
|
||||
s += GetTlvStringSize(item->xslt);
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -110,7 +114,7 @@ bool RsFeedReaderSerialiser::serialiseFeed(RsFeedReaderFeed *item, void *data, u
|
||||
offset += 8;
|
||||
|
||||
/* add values */
|
||||
ok &= setRawUInt16(data, tlvsize, &offset, 0); /* version */
|
||||
ok &= setRawUInt16(data, tlvsize, &offset, 1); /* version */
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GENID, item->feedId);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_VALUE, item->parentId);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_LINK, item->url);
|
||||
@ -128,8 +132,10 @@ bool RsFeedReaderSerialiser::serialiseFeed(RsFeedReaderFeed *item, void *data, u
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_VALUE, item->forumId);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->errorState);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_VALUE, item->errorString);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->transformationType);
|
||||
ok &= item->xpathsToUse.SetTlv(data, tlvsize, &offset);
|
||||
ok &= item->xpathsToRemove.SetTlv(data, tlvsize, &offset);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_VALUE, item->xslt);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
@ -192,9 +198,28 @@ RsFeedReaderFeed *RsFeedReaderSerialiser::deserialiseFeed(void *data, uint32_t *
|
||||
ok &= getRawUInt32(data, rssize, &offset, &errorState);
|
||||
item->errorState = (RsFeedReaderErrorState) errorState;
|
||||
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_VALUE, item->errorString);
|
||||
if (version >= 1) {
|
||||
uint32_t value = RS_FEED_TRANSFORMATION_TYPE_NONE;
|
||||
ok &= getRawUInt32(data, rssize, &offset, &value);
|
||||
if (ok)
|
||||
{
|
||||
item->transformationType = (RsFeedTransformationType) value;
|
||||
}
|
||||
}
|
||||
ok &= item->xpathsToUse.GetTlv(data, rssize, &offset);
|
||||
ok &= item->xpathsToRemove.GetTlv(data, rssize, &offset);
|
||||
if (version >= 1) {
|
||||
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_VALUE, item->xslt);
|
||||
}
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
if (!item->xpathsToUse.ids.empty() || !item->xpathsToRemove.ids.empty())
|
||||
{
|
||||
/* set transformation type */
|
||||
item->transformationType = RS_FEED_TRANSFORMATION_TYPE_XPATH;
|
||||
}
|
||||
}
|
||||
if (offset != rssize)
|
||||
{
|
||||
/* error */
|
||||
@ -226,6 +251,7 @@ void RsFeedReaderMsg::clear()
|
||||
link.clear();
|
||||
author.clear();
|
||||
description.clear();
|
||||
descriptionTransformed.clear();
|
||||
pubDate = 0;
|
||||
flag = 0;
|
||||
}
|
||||
@ -245,6 +271,7 @@ uint32_t RsFeedReaderSerialiser::sizeMsg(RsFeedReaderMsg *item)
|
||||
s += GetTlvStringSize(item->link);
|
||||
s += GetTlvStringSize(item->author);
|
||||
s += GetTlvStringSize(item->description);
|
||||
s += GetTlvStringSize(item->descriptionTransformed);
|
||||
s += sizeof(time_t); /* pubDate */
|
||||
s += sizeof(uint32_t); /* flag */
|
||||
|
||||
@ -270,13 +297,14 @@ bool RsFeedReaderSerialiser::serialiseMsg(RsFeedReaderMsg *item, void *data, uin
|
||||
offset += 8;
|
||||
|
||||
/* add values */
|
||||
ok &= setRawUInt16(data, tlvsize, &offset, 0); /* version */
|
||||
ok &= setRawUInt16(data, tlvsize, &offset, 1); /* version */
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GENID, item->msgId);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_VALUE, item->feedId);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_NAME, item->title);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_LINK, item->link);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_VALUE, item->author);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_COMMENT, item->description);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_COMMENT, item->descriptionTransformed);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->pubDate);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->flag);
|
||||
|
||||
@ -328,6 +356,9 @@ RsFeedReaderMsg *RsFeedReaderSerialiser::deserialiseMsg(void *data, uint32_t *pk
|
||||
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_LINK, item->link);
|
||||
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_VALUE, item->author);
|
||||
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_COMMENT, item->description);
|
||||
if (version >= 1) {
|
||||
ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_COMMENT, item->descriptionTransformed);
|
||||
}
|
||||
ok &= getRawUInt32(data, rssize, &offset, (uint32_t*) &(item->pubDate));
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->flag));
|
||||
|
||||
|
@ -65,26 +65,28 @@ public:
|
||||
virtual void clear();
|
||||
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0);
|
||||
|
||||
std::string feedId;
|
||||
std::string parentId;
|
||||
std::string name;
|
||||
std::string url;
|
||||
std::string user;
|
||||
std::string password;
|
||||
std::string proxyAddress;
|
||||
uint16_t proxyPort;
|
||||
uint32_t updateInterval;
|
||||
time_t lastUpdate;
|
||||
uint32_t flag; // RS_FEED_FLAG_...
|
||||
std::string forumId;
|
||||
uint32_t storageTime;
|
||||
std::string description;
|
||||
std::string icon;
|
||||
RsFeedReaderErrorState errorState;
|
||||
std::string errorString;
|
||||
std::string feedId;
|
||||
std::string parentId;
|
||||
std::string name;
|
||||
std::string url;
|
||||
std::string user;
|
||||
std::string password;
|
||||
std::string proxyAddress;
|
||||
uint16_t proxyPort;
|
||||
uint32_t updateInterval;
|
||||
time_t lastUpdate;
|
||||
uint32_t flag; // RS_FEED_FLAG_...
|
||||
std::string forumId;
|
||||
uint32_t storageTime;
|
||||
std::string description;
|
||||
std::string icon;
|
||||
RsFeedReaderErrorState errorState;
|
||||
std::string errorString;
|
||||
|
||||
RsTlvStringSet xpathsToUse;
|
||||
RsTlvStringSet xpathsToRemove;
|
||||
RsFeedTransformationType transformationType;
|
||||
RsTlvStringSet xpathsToUse;
|
||||
RsTlvStringSet xpathsToRemove;
|
||||
std::string xslt;
|
||||
|
||||
/* Not Serialised */
|
||||
bool preview;
|
||||
@ -113,6 +115,7 @@ public:
|
||||
std::string link;
|
||||
std::string author;
|
||||
std::string description;
|
||||
std::string descriptionTransformed;
|
||||
time_t pubDate;
|
||||
uint32_t flag; // RS_FEEDMSG_FLAG_...
|
||||
};
|
||||
|
@ -32,7 +32,10 @@ bool HTMLWrapper::readHTML(const char *html, const char *url)
|
||||
{
|
||||
cleanup();
|
||||
|
||||
mDocument = htmlReadMemory(html, strlen(html), url, "", HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | HTML_PARSE_COMPACT | HTML_PARSE_NONET | HTML_PARSE_NOBLANKS);
|
||||
handleError(true, mLastErrorString);
|
||||
mDocument = htmlReadMemory(html, strlen(html), url, "", /*HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | */HTML_PARSE_COMPACT | HTML_PARSE_NONET | HTML_PARSE_NOBLANKS);
|
||||
handleError(false, mLastErrorString);
|
||||
|
||||
if (mDocument) {
|
||||
return true;
|
||||
}
|
||||
@ -48,7 +51,10 @@ bool HTMLWrapper::saveHTML(std::string &html)
|
||||
|
||||
xmlChar *newHtml = NULL;
|
||||
int newHtmlSize = 0;
|
||||
handleError(true, mLastErrorString);
|
||||
htmlDocDumpMemoryFormat(mDocument, &newHtml, &newHtmlSize, 0);
|
||||
handleError(false, mLastErrorString);
|
||||
|
||||
if (newHtml) {
|
||||
convertToString(newHtml, html);
|
||||
xmlFree(newHtml);
|
||||
|
@ -25,6 +25,14 @@
|
||||
#include "XMLWrapper.h"
|
||||
#include "XPathWrapper.h"
|
||||
|
||||
#include <util/rsstring.h>
|
||||
#include <util/rsthreads.h>
|
||||
#include <libxslt/transform.h>
|
||||
#include <libxslt/xsltutils.h>
|
||||
|
||||
static RsMutex xmlMtx("XMLWrapper");
|
||||
static std::string xmlErrorString;
|
||||
|
||||
XMLWrapper::XMLWrapper()
|
||||
{
|
||||
mDocument = NULL;
|
||||
@ -42,6 +50,35 @@ XMLWrapper::~XMLWrapper()
|
||||
xmlCharEncCloseFunc(mCharEncodingHandler);
|
||||
}
|
||||
|
||||
static void xmlErrorHandler(void */*context*/, const char *msg, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, msg);
|
||||
rs_sprintf_append_args(xmlErrorString, msg, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void XMLWrapper::handleError(bool init, std::string &errorString)
|
||||
{
|
||||
if (init) {
|
||||
xmlMtx.lock();
|
||||
xmlErrorString.clear();
|
||||
errorString.clear();
|
||||
|
||||
xsltSetGenericErrorFunc(this, xmlErrorHandler);
|
||||
xmlSetGenericErrorFunc(this, xmlErrorHandler);
|
||||
} else {
|
||||
xsltSetGenericErrorFunc(NULL, NULL);
|
||||
xmlSetGenericErrorFunc(NULL, NULL);
|
||||
|
||||
errorString = xmlErrorString;
|
||||
xmlErrorString.clear();
|
||||
|
||||
xmlMtx.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void XMLWrapper::trimString(std::string &string)
|
||||
{
|
||||
/* trim left */
|
||||
@ -59,7 +96,6 @@ void XMLWrapper::trimString(std::string &string)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
XMLWrapper &XMLWrapper::operator=(const XMLWrapper &xml)
|
||||
{
|
||||
cleanup();
|
||||
@ -80,6 +116,13 @@ void XMLWrapper::cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
void XMLWrapper::attach(xmlDocPtr document)
|
||||
{
|
||||
cleanup();
|
||||
|
||||
mDocument = document;
|
||||
}
|
||||
|
||||
bool XMLWrapper::convertToString(const xmlChar *xmlText, std::string &text)
|
||||
{
|
||||
bool result = false;
|
||||
@ -138,7 +181,10 @@ bool XMLWrapper::readXML(const char *xml)
|
||||
{
|
||||
cleanup();
|
||||
|
||||
mDocument = xmlReadDoc(BAD_CAST xml, "", NULL, XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_COMPACT | XML_PARSE_NOENT | XML_PARSE_NOCDATA);
|
||||
handleError(true, mLastErrorString);
|
||||
mDocument = xmlReadDoc(BAD_CAST xml, "", NULL, /*XML_PARSE_NOERROR | XML_PARSE_NOWARNING | */XML_PARSE_COMPACT | XML_PARSE_NOENT | XML_PARSE_NOCDATA);
|
||||
handleError(false, mLastErrorString);
|
||||
|
||||
if (mDocument) {
|
||||
return true;
|
||||
}
|
||||
@ -358,3 +404,23 @@ XPathWrapper *XMLWrapper::createXPath()
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool XMLWrapper::transform(const XMLWrapper &style, XMLWrapper &result)
|
||||
{
|
||||
handleError(true, mLastErrorString);
|
||||
|
||||
xmlDocPtr resultDoc = NULL;
|
||||
|
||||
xsltStylesheetPtr stylesheet = xsltParseStylesheetDoc(style.getDocument());
|
||||
if (stylesheet) {
|
||||
resultDoc = xsltApplyStylesheet(stylesheet, getDocument(), NULL);
|
||||
stylesheet->doc = NULL; // xsltFreeStylesheet is freeing doc
|
||||
xsltFreeStylesheet(stylesheet);
|
||||
}
|
||||
|
||||
result.attach(resultDoc);
|
||||
|
||||
handleError(false, mLastErrorString);
|
||||
|
||||
return resultDoc ? true : false;
|
||||
}
|
||||
|
@ -39,12 +39,16 @@ public:
|
||||
XMLWrapper &operator=(const XMLWrapper &xml);
|
||||
|
||||
void cleanup();
|
||||
std::string lastError() { return mLastErrorString; }
|
||||
|
||||
bool readXML(const char *xml);
|
||||
|
||||
xmlDocPtr getDocument() const;
|
||||
xmlNodePtr getRootElement() const;
|
||||
|
||||
bool convertToString(const xmlChar *xmlText, std::string &text);
|
||||
bool convertFromString(const char *text, xmlChar *&xmlText);
|
||||
|
||||
std::string nodeName(xmlNodePtr node);
|
||||
std::string attrName(xmlAttrPtr attr);
|
||||
|
||||
@ -62,12 +66,16 @@ public:
|
||||
|
||||
XPathWrapper *createXPath();
|
||||
|
||||
bool convertToString(const xmlChar *xmlText, std::string &text);
|
||||
bool convertFromString(const char *text, xmlChar *&xmlText);
|
||||
bool transform(const XMLWrapper &style, XMLWrapper &result);
|
||||
|
||||
protected:
|
||||
void attach(xmlDocPtr document);
|
||||
void handleError(bool init, std::string &errorString);
|
||||
|
||||
protected:
|
||||
xmlDocPtr mDocument;
|
||||
xmlCharEncodingHandlerPtr mCharEncodingHandler;
|
||||
std::string mLastErrorString;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
54
retroshare-gui/src/gui/common/RSPlainTextEdit.cpp
Normal file
54
retroshare-gui/src/gui/common/RSPlainTextEdit.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/****************************************************************
|
||||
*
|
||||
* RetroShare is distributed under the following license:
|
||||
*
|
||||
* Copyright (C) 2013, RetroShare Team
|
||||
*
|
||||
* This program 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 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#include "RSPlainTextEdit.h"
|
||||
|
||||
RSPlainTextEdit::RSPlainTextEdit(QWidget *parent)
|
||||
: QPlainTextEdit(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void RSPlainTextEdit::setPlaceholderText(const QString &text)
|
||||
{
|
||||
mPlaceholderText = text;
|
||||
viewport()->repaint();
|
||||
}
|
||||
|
||||
void RSPlainTextEdit::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPlainTextEdit::paintEvent(event);
|
||||
|
||||
if (mPlaceholderText.isEmpty() == false && toPlainText().isEmpty()) {
|
||||
QWidget *vieportWidget = viewport();
|
||||
QPainter painter(vieportWidget);
|
||||
|
||||
QPen pen = painter.pen();
|
||||
QColor color = pen.color();
|
||||
color.setAlpha(128);
|
||||
pen.setColor(color);
|
||||
painter.setPen(pen);
|
||||
|
||||
painter.drawText(QRect(QPoint(), vieportWidget->size()), Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextWordWrap, mPlaceholderText);
|
||||
}
|
||||
}
|
44
retroshare-gui/src/gui/common/RSPlainTextEdit.h
Normal file
44
retroshare-gui/src/gui/common/RSPlainTextEdit.h
Normal file
@ -0,0 +1,44 @@
|
||||
/****************************************************************
|
||||
*
|
||||
* RetroShare is distributed under the following license:
|
||||
*
|
||||
* Copyright (C) 2013, RetroShare Team
|
||||
*
|
||||
* This program 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 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
#ifndef RSPLAINTEXTEDIT_H
|
||||
#define RSPLAINTEXTEDIT_H
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
class RSPlainTextEdit : public QPlainTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RSPlainTextEdit(QWidget *parent = 0);
|
||||
|
||||
void setPlaceholderText(const QString &text);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
private:
|
||||
QString mPlaceholderText;
|
||||
};
|
||||
|
||||
#endif // RSPLAINTEXTEDIT_H
|
@ -397,6 +397,7 @@ HEADERS += rshare.h \
|
||||
gui/common/GroupDefs.h \
|
||||
gui/common/Emoticons.h \
|
||||
gui/common/RSListWidgetItem.h \
|
||||
gui/common/RSPlainTextEdit.h \
|
||||
gui/common/RSTreeWidget.h \
|
||||
gui/common/RSTreeWidgetItem.h \
|
||||
gui/common/RSTabWidget.h \
|
||||
@ -665,6 +666,7 @@ SOURCES += main.cpp \
|
||||
gui/common/GroupDefs.cpp \
|
||||
gui/common/Emoticons.cpp \
|
||||
gui/common/RSListWidgetItem.cpp \
|
||||
gui/common/RSPlainTextEdit.cpp \
|
||||
gui/common/RSTreeWidget.cpp \
|
||||
gui/common/RSTreeWidgetItem.cpp \
|
||||
gui/common/RSTabWidget.cpp \
|
||||
|
Loading…
x
Reference in New Issue
Block a user