From 9b5edb06720245dc4e7f64652da3a91114717a04 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Mon, 25 Jan 2021 19:57:35 -0500 Subject: [PATCH] 2021-01-25 Fred Gleason * Added 'RDPodcastListModel'. * Refactored the 'Podcast Item List' dialog in rdcastmanager(1) to use the model-based API. Signed-off-by: Fred Gleason --- ChangeLog | 4 + lib/Makefile.am | 4 + lib/lib.pro | 4 + lib/librd_cs.ts | 70 +++++ lib/librd_de.ts | 70 +++++ lib/librd_es.ts | 70 +++++ lib/librd_fr.ts | 70 +++++ lib/librd_nb.ts | 70 +++++ lib/librd_nn.ts | 70 +++++ lib/librd_pt_BR.ts | 70 +++++ lib/rdpodcastfilter.cpp | 132 ++++++++ lib/rdpodcastfilter.h | 64 ++++ lib/rdpodcastlistmodel.cpp | 448 +++++++++++++++++++++++++++ lib/rdpodcastlistmodel.h | 81 +++++ rdadmin/list_feeds.cpp | 2 +- rdcastmanager/list_casts.cpp | 370 +++++----------------- rdcastmanager/list_casts.h | 27 +- rdcastmanager/logdialog.cpp | 3 - rdcastmanager/rdcastmanager_cs.ts | 66 +--- rdcastmanager/rdcastmanager_de.ts | 66 +--- rdcastmanager/rdcastmanager_es.ts | 68 +--- rdcastmanager/rdcastmanager_fr.ts | 90 +----- rdcastmanager/rdcastmanager_nb.ts | 78 +---- rdcastmanager/rdcastmanager_nn.ts | 78 +---- rdcastmanager/rdcastmanager_pt_BR.ts | 78 +---- 25 files changed, 1409 insertions(+), 744 deletions(-) create mode 100644 lib/rdpodcastfilter.cpp create mode 100644 lib/rdpodcastfilter.h create mode 100644 lib/rdpodcastlistmodel.cpp create mode 100644 lib/rdpodcastlistmodel.h diff --git a/ChangeLog b/ChangeLog index 33af0b1c..d99b3db4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20901,3 +20901,7 @@ 2021-01-25 Fred Gleason * Fixed a bug in 'RDFeedListModel' that caused feed icons to fail to be scaled correctly. +2021-01-25 Fred Gleason + * Added 'RDPodcastListModel'. + * Refactored the 'Podcast Item List' dialog in rdcastmanager(1) to + use the model-based API. diff --git a/lib/Makefile.am b/lib/Makefile.am index 6be71ce7..bfd59ce3 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -200,6 +200,8 @@ dist_librd_la_SOURCES = dbversion.h\ rdplaymeter.cpp rdplaymeter.h\ rdpeaksexport.cpp rdpeaksexport.h\ rdpodcast.cpp rdpodcast.h\ + rdpodcastfilter.cpp rdpodcastfilter.h\ + rdpodcastlistmodel.cpp rdpodcastlistmodel.h\ rdprocess.cpp rdprocess.h\ rdprofile.cpp rdprofile.h\ rdpushbutton.cpp rdpushbutton.h\ @@ -344,6 +346,8 @@ nodist_librd_la_SOURCES = moc_rdadd_cart.cpp\ moc_rdpasswd.cpp\ moc_rdplay_deck.cpp\ moc_rdplaymeter.cpp\ + moc_rdpodcastfilter.cpp\ + moc_rdpodcastlistmodel.cpp\ moc_rdprocess.cpp\ moc_rdpushbutton.cpp\ moc_rdrehash.cpp\ diff --git a/lib/lib.pro b/lib/lib.pro index c04157f9..e0a254dd 100644 --- a/lib/lib.pro +++ b/lib/lib.pro @@ -145,6 +145,8 @@ SOURCES += rdpanel_button.cpp SOURCES += rdpasswd.cpp SOURCES += rdplay_deck.cpp SOURCES += rdplaymeter.cpp +SOURCES += rdpodcastfilter.cpp +SOURCES += rdpodcastlistmodel.cpp SOURCES += rdprocess.cpp SOURCES += rdprofile.cpp SOURCES += rdpushbutton.cpp @@ -302,6 +304,8 @@ HEADERS += rdpaths.h HEADERS += rdpasswd.h HEADERS += rdplay_deck.h HEADERS += rdplaymeter.h +HEADERS += rdpodcastfilter.h +HEADERS += rdpodcastlistmodel.h HEADERS += rdprocess.h HEADERS += rdprofile.h HEADERS += rdpushbutton.h diff --git a/lib/librd_cs.ts b/lib/librd_cs.ts index 252b3acb..ea67322f 100644 --- a/lib/librd_cs.ts +++ b/lib/librd_cs.ts @@ -3268,6 +3268,76 @@ Zkuste to, prosím, znovu! OK + + RDPodcastFilter + + Filter: + + + + Only Show Active Items + + + + + RDPodcastListModel + + Title + + + + Status + + + + Start + + + + Expiration + + + + Length + Délka + + + Feed + + + + Category + + + + Posted By + + + + SHA1 + + + + unknown + + + + at + + + + on + + + + [none] + + + + Never + + + RDProcess diff --git a/lib/librd_de.ts b/lib/librd_de.ts index dc311e5c..77467363 100644 --- a/lib/librd_de.ts +++ b/lib/librd_de.ts @@ -3249,6 +3249,76 @@ bitte erneut versuchen! OK + + RDPodcastFilter + + Filter: + + + + Only Show Active Items + + + + + RDPodcastListModel + + Title + + + + Status + + + + Start + + + + Expiration + + + + Length + Länge + + + Feed + + + + Category + + + + Posted By + + + + SHA1 + + + + unknown + + + + at + + + + on + + + + [none] + + + + Never + + + RDProcess diff --git a/lib/librd_es.ts b/lib/librd_es.ts index ded757bd..a692071f 100644 --- a/lib/librd_es.ts +++ b/lib/librd_es.ts @@ -3236,6 +3236,76 @@ please try again! Aceptar + + RDPodcastFilter + + Filter: + + + + Only Show Active Items + + + + + RDPodcastListModel + + Title + + + + Status + + + + Start + + + + Expiration + + + + Length + Longitud + + + Feed + + + + Category + + + + Posted By + + + + SHA1 + + + + unknown + + + + at + + + + on + + + + [none] + + + + Never + + + RDProcess diff --git a/lib/librd_fr.ts b/lib/librd_fr.ts index b0fce93a..d31a8c1e 100644 --- a/lib/librd_fr.ts +++ b/lib/librd_fr.ts @@ -2671,6 +2671,76 @@ please try again! + + RDPodcastFilter + + Filter: + + + + Only Show Active Items + + + + + RDPodcastListModel + + Title + + + + Status + + + + Start + Début + + + Expiration + + + + Length + + + + Feed + + + + Category + + + + Posted By + + + + SHA1 + + + + unknown + + + + at + + + + on + + + + [none] + + + + Never + + + RDProcess diff --git a/lib/librd_nb.ts b/lib/librd_nb.ts index 681c38db..4bbcd5b1 100644 --- a/lib/librd_nb.ts +++ b/lib/librd_nb.ts @@ -3203,6 +3203,76 @@ prøv ein gong til! OK + + RDPodcastFilter + + Filter: + + + + Only Show Active Items + + + + + RDPodcastListModel + + Title + + + + Status + + + + Start + + + + Expiration + + + + Length + Lengd + + + Feed + + + + Category + + + + Posted By + + + + SHA1 + + + + unknown + + + + at + + + + on + + + + [none] + + + + Never + + + RDProcess diff --git a/lib/librd_nn.ts b/lib/librd_nn.ts index 681c38db..4bbcd5b1 100644 --- a/lib/librd_nn.ts +++ b/lib/librd_nn.ts @@ -3203,6 +3203,76 @@ prøv ein gong til! OK + + RDPodcastFilter + + Filter: + + + + Only Show Active Items + + + + + RDPodcastListModel + + Title + + + + Status + + + + Start + + + + Expiration + + + + Length + Lengd + + + Feed + + + + Category + + + + Posted By + + + + SHA1 + + + + unknown + + + + at + + + + on + + + + [none] + + + + Never + + + RDProcess diff --git a/lib/librd_pt_BR.ts b/lib/librd_pt_BR.ts index 25d187b4..f3460a30 100644 --- a/lib/librd_pt_BR.ts +++ b/lib/librd_pt_BR.ts @@ -3238,6 +3238,76 @@ por favor, tente novamente! OK + + RDPodcastFilter + + Filter: + + + + Only Show Active Items + + + + + RDPodcastListModel + + Title + + + + Status + + + + Start + + + + Expiration + + + + Length + Duração + + + Feed + + + + Category + + + + Posted By + + + + SHA1 + + + + unknown + + + + at + + + + on + + + + [none] + + + + Never + + + RDProcess diff --git a/lib/rdpodcastfilter.cpp b/lib/rdpodcastfilter.cpp new file mode 100644 index 00000000..db8be2df --- /dev/null +++ b/lib/rdpodcastfilter.cpp @@ -0,0 +1,132 @@ +// rdpodcastfilter.cpp +// +// Filter widget for podcasts. +// +// (C) Copyright 2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include "rdapplication.h" +#include "rdcart_search_text.h" +#include "rdescape_string.h" +#include "rdpodcast.h" +#include "rdpodcastfilter.h" + +RDPodcastFilter::RDPodcastFilter(QWidget *parent) + : RDWidget(parent) +{ + // + // Filter Phrase + // + d_filter_edit=new QLineEdit(this); + d_filter_label=new QLabel(d_filter_edit,tr("Filter:"),this); + d_filter_label->setFont(labelFont()); + d_filter_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + connect(d_filter_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filterChangedData(const QString &))); + + // + // Show Audio Carts Checkbox + // + d_showactive_check=new QCheckBox(this); + d_showactive_label= + new QLabel(d_showactive_check,tr("Only Show Active Items"),this); + d_showactive_label->setFont(labelFont()); + d_showactive_label->setAlignment(Qt::AlignVCenter|Qt::AlignLeft); + connect(d_showactive_check,SIGNAL(stateChanged(int)), + this,SLOT(checkChangedData(int))); +} + + +RDPodcastFilter::~RDPodcastFilter() +{ +} + + +QSize RDPodcastFilter::sizeHint() const +{ + return QSize(640,57); +} + + +QSizePolicy RDPodcastFilter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed); +} + + +QString RDPodcastFilter::filterSql() const +{ + return RDPodcastFilter::searchString(d_filter_edit->text(), + d_showactive_check->isChecked()); +} + + +QString RDPodcastFilter::filterText() const +{ + return d_filter_edit->text(); +} + + +void RDPodcastFilter::setFilterText(const QString &str) +{ + d_filter_edit->setText(str); + filterChangedData(str); +} + + +QString RDPodcastFilter::searchString(const QString &filter,bool active_only) +{ + QString ret; + if(!filter.trimmed().isEmpty()) { + QString fil=RDEscapeString(filter); + ret+=QString("&&((PODCASTS.ITEM_TITLE like \"%")+fil+"%\")||"+ + "(PODCASTS.ITEM_DESCRIPTION like \"%"+fil+"%\")||"+ + "(PODCASTS.ITEM_CATEGORY like \"%"+fil+"%\")||"+ + "(PODCASTS.ITEM_LINK like \"%"+fil+"%\")||"+ + "(PODCASTS.ITEM_COMMENTS like \"%"+fil+"%\")||"+ + "(PODCASTS.ITEM_AUTHOR like \"%"+fil+"%\")||"+ + "(PODCASTS.ITEM_SOURCE_TEXT like \"%"+fil+"%\")||"+ + "(PODCASTS.ITEM_SOURCE_URL like \"%"+fil+"%\"))"; + } + if(active_only) { + ret+=QString().sprintf("&&(PODCASTS.STATUS=%d)",RDPodcast::StatusActive); + } + return ret; +} + + +void RDPodcastFilter::filterChangedData(const QString &str) +{ + emit filterChanged(filterSql()); +} + + +void RDPodcastFilter::checkChangedData(int n) +{ + filterChangedData(""); +} + + +void RDPodcastFilter::resizeEvent(QResizeEvent *e) +{ + d_filter_label->setGeometry(10,3,55,20); + d_filter_edit->setGeometry(70,3,e->size().width()-80,20); + d_showactive_check->setGeometry(75,28,15,15); + d_showactive_label->setGeometry(95,26,size().width()-105,20); +} diff --git a/lib/rdpodcastfilter.h b/lib/rdpodcastfilter.h new file mode 100644 index 00000000..cfb0e03a --- /dev/null +++ b/lib/rdpodcastfilter.h @@ -0,0 +1,64 @@ +// rdpodcastfilter.h +// +// Filter widget for podcasts +// +// (C) Copyright 2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPODCASTFILTER_H +#define RDPODCASTFILTER_H + +#include +#include +#include +#include + +#include + +class RDPodcastFilter : public RDWidget +{ + Q_OBJECT; + public: + RDPodcastFilter(QWidget *parent=0); + ~RDPodcastFilter(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + QString filterSql() const; + QString filterText() const; + static QString searchString(const QString &filter,bool active_only); + + public slots: + void setFilterText(const QString &str); + + signals: + void filterChanged(const QString &where_sql); + + private slots: + void filterChangedData(const QString &str); + void checkChangedData(int n); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + QLineEdit *d_filter_edit; + QLabel *d_filter_label; + QCheckBox *d_showactive_check; + QLabel *d_showactive_label; +}; + + +#endif // RDPODCASTFILTER_H diff --git a/lib/rdpodcastlistmodel.cpp b/lib/rdpodcastlistmodel.cpp new file mode 100644 index 00000000..4718d45a --- /dev/null +++ b/lib/rdpodcastlistmodel.cpp @@ -0,0 +1,448 @@ +// rdpodcastlistmodel.cpp +// +// Data model for Rivendell podcast episodes +// +// (C) Copyright 2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include "rdapplication.h" +#include "rdconf.h" +#include "rdescape_string.h" +#include "rdpodcast.h" +#include "rdpodcastlistmodel.h" + +RDPodcastListModel::RDPodcastListModel(unsigned feed_id,QObject *parent) + : QAbstractTableModel(parent) +{ + d_feed_id=feed_id; + d_font_metrics=NULL; + d_bold_font_metrics=NULL; + + // + // Column Attributes + // + unsigned left=Qt::AlignLeft|Qt::AlignVCenter; + unsigned center=Qt::AlignCenter; + unsigned right=Qt::AlignRight|Qt::AlignVCenter; + + d_headers.push_back(tr("Title")); // 00 + d_alignments.push_back(left); + + d_headers.push_back(tr("Status")); // 01 + d_alignments.push_back(center); + + d_headers.push_back(tr("Start")); // 02 + d_alignments.push_back(left); + + d_headers.push_back(tr("Expiration")); // 03 + d_alignments.push_back(left); + + d_headers.push_back(tr("Length")); // 04 + d_alignments.push_back(right); + + d_headers.push_back(tr("Feed")); // 05 + d_alignments.push_back(center); + + d_headers.push_back(tr("Category")); // 06 + d_alignments.push_back(left); + + d_headers.push_back(tr("Posted By")); // 07 + d_alignments.push_back(left); + + d_headers.push_back(tr("SHA1")); // 08 + d_alignments.push_back(left); + + updateModel(); +} + + +RDPodcastListModel::~RDPodcastListModel() +{ +} + + +QPalette RDPodcastListModel::palette() +{ + return d_palette; +} + + +void RDPodcastListModel::setPalette(const QPalette &pal) +{ + d_palette=pal; +} + + +void RDPodcastListModel::setFont(const QFont &font) +{ + d_font=font; + if(d_font_metrics!=NULL) { + delete d_font_metrics; + } + d_font_metrics=new QFontMetrics(d_font); + + d_bold_font=font; + d_bold_font.setWeight(QFont::Bold); + if(d_bold_font_metrics!=NULL) { + delete d_bold_font_metrics; + } + d_bold_font_metrics=new QFontMetrics(d_bold_font); +} + + +int RDPodcastListModel::columnCount(const QModelIndex &parent) const +{ + return d_headers.size(); +} + + +int RDPodcastListModel::rowCount(const QModelIndex &parent) const +{ + return d_texts.size(); +} + + +QVariant RDPodcastListModel::headerData(int section,Qt::Orientation orient, + int role) const +{ + if((orient==Qt::Horizontal)&&(role==Qt::DisplayRole)) { + return d_headers.at(section); + } + return QVariant(); +} + + +QVariant RDPodcastListModel::data(const QModelIndex &index,int role) const +{ + QString str; + int col=index.column(); + int row=index.row(); + + if(row().width())+ + d_bold_font_metrics-> + width(d_texts.at(row).at(col).toString()),40); + } + return QSize(RD_LISTWIDGET_ITEM_WIDTH_PADDING+ + (d_icons.at(row).at(col).value().width())+ + d_font_metrics-> + width(d_texts.at(row).at(col).toString()),40); + + default: + break; + } + } + + return QVariant(); +} + + +unsigned RDPodcastListModel::castId(const QModelIndex &row) const +{ + return d_cast_ids.at(row.row()); +} + + +QModelIndex RDPodcastListModel::addCast(unsigned cast_id) +{ + beginInsertRows(QModelIndex(),0,0); + QList list; + for(int i=0;ifirst()) { + updateRow(row.row(),q); + emit dataChanged(createIndex(row.row(),0), + createIndex(row.row(),columnCount())); + } + delete q; + } +} + + +void RDPodcastListModel::refresh(unsigned cast_id) +{ + for(int i=0;itype()==RDNotification::FeedItemType) { + cast_id=notify->id().toUInt(); + cast=new RDPodcast(rda->config(),cast_id); + if(cast->feedId()==d_feed_id) { + switch(notify->action()) { + case RDNotification::AddAction: + addCast(cast_id); + break; + + case RDNotification::DeleteAction: + removeCast(cast_id); + break; + + case RDNotification::ModifyAction: + refresh(cast_id); + break; + + case RDNotification::LastAction: + case RDNotification::NoAction: + break; + + } + } + delete cast; + } +} + + +void RDPodcastListModel::updateModel() +{ + QList texts; + + RDSqlQuery *q=NULL; + QString sql=sqlFields()+ + "where "+ + QString().sprintf("PODCASTS.FEED_ID=%u ",d_feed_id)+ + d_filter_sql+ + " order by PODCASTS.ORIGIN_DATETIME desc"; + beginResetModel(); + d_cast_ids.clear(); + d_texts.clear(); + d_icons.clear(); + q=new RDSqlQuery(sql); + while(q->next()) { + d_cast_ids.push_back(0); + d_texts.push_back(texts); + d_icons.push_back(texts); + updateRow(d_texts.size()-1,q); + } + delete q; + endResetModel(); +} + + +void RDPodcastListModel::updateRowLine(int line) +{ + if(linefirst()) { + updateRow(line,q); + } + delete q; + } +} + + +void RDPodcastListModel::updateRow(int row,RDSqlQuery *q) +{ + QList texts; + QList icons; + + // Title + texts.push_back(q->value(2)); + if(q->value(13).isNull()) { + icons.push_back(rda->iconEngine()-> + applicationIcon(RDIconEngine::RdCastManager,32)); + } + else { + icons.push_back(QImage::fromData(q->value(13).toByteArray()). + scaled(32,32,Qt::IgnoreAspectRatio,Qt::SmoothTransformation)); + } + + // Status + texts.push_back(QVariant()); + switch((RDPodcast::Status)q->value(1).toUInt()) { + case RDPodcast::StatusActive: + if(q->value(3).toDateTime()<=QDateTime::currentDateTime()) { + icons.push_back(rda->iconEngine()->listIcon(RDIconEngine::GreenBall)); + } + else { + icons.push_back(rda->iconEngine()->listIcon(RDIconEngine::BlueBall)); + } + break; + + + case RDPodcast::StatusPending: + icons.push_back(rda->iconEngine()->listIcon(RDIconEngine::RedBall)); + break; + + case RDPodcast::StatusExpired: + icons.push_back(rda->iconEngine()->listIcon(RDIconEngine::WhiteBall)); + } + + // Start + texts.push_back(q->value(3).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); + icons.push_back(QVariant()); + + // Expiration + if(q->value(4).toDateTime().isValid()) { + texts.push_back(q->value(4).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); + } + else { + texts.push_back(tr("Never")); + } + icons.push_back(QVariant()); + + // Length + texts.push_back(RDGetTimeLength(q->value(5).toInt(),false,false)); + icons.push_back(QVariant()); + + // Feed Keyname + texts.push_back(q->value(7)); + icons.push_back(QVariant()); + + // Category + texts.push_back(q->value(8)); + icons.push_back(QVariant()); + + // Posted By + if(q->value(9).isNull()) { + texts.push_back(tr("unknown")+" "+tr("at")+" "+ + q->value(11).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); + } + else { + texts.push_back(q->value(9).toString()+" "+tr("on")+" "+ + q->value(10).toString()+" "+tr("at")+" "+ + q->value(11).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); + } + icons.push_back(QVariant()); + + // SHA1 + if(q->value(12).toString().isEmpty()) { + texts.push_back(tr("[none]")); + } + else { + texts.push_back(q->value(12)); + } + icons.push_back(QVariant()); + + d_cast_ids[row]=q->value(0).toUInt(); + d_texts[row]=texts; + d_icons[row]=icons; +} + + +QString RDPodcastListModel::sqlFields() const +{ + QString sql=QString("select ")+ + "PODCASTS.ID,"+ // 00 + "PODCASTS.STATUS,"+ // 01 + "PODCASTS.ITEM_TITLE,"+ // 02 + "PODCASTS.EFFECTIVE_DATETIME,"+ // 03 + "PODCASTS.EXPIRATION_DATETIME,"+ // 04 + "PODCASTS.AUDIO_TIME,"+ // 05 + "PODCASTS.ITEM_DESCRIPTION,"+ // 06 + "FEEDS.KEY_NAME,"+ // 07 + "PODCASTS.ITEM_CATEGORY,"+ // 08 + "PODCASTS.ORIGIN_LOGIN_NAME,"+ // 09 + "PODCASTS.ORIGIN_STATION,"+ // 10 + "PODCASTS.ORIGIN_DATETIME,"+ // 11 + "PODCASTS.SHA1_HASH,"+ // 12 + "FEED_IMAGES.DATA "+ // 13 + "from PODCASTS left join FEEDS "+ + "on PODCASTS.FEED_ID=FEEDS.ID left join FEED_IMAGES "+ + "on PODCASTS.ITEM_IMAGE_ID=FEED_IMAGES.ID "; + + return sql; +} diff --git a/lib/rdpodcastlistmodel.h b/lib/rdpodcastlistmodel.h new file mode 100644 index 00000000..bc4a16f7 --- /dev/null +++ b/lib/rdpodcastlistmodel.h @@ -0,0 +1,81 @@ +// rdpodcastlistmodel.h +// +// Data model for Rivendell podcast episodes +// +// (C) Copyright 2021 Fred Gleason +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPODCASTLISTMODEL_H +#define RDPODCASTLISTMODEL_H + +#include +#include +#include +#include + +#include +#include +#include + +class RDPodcastListModel : public QAbstractTableModel +{ + Q_OBJECT + public: + RDPodcastListModel(unsigned feed_id,QObject *parent=0); + ~RDPodcastListModel(); + QPalette palette(); + void setPalette(const QPalette &pal); + void setFont(const QFont &font); + int columnCount(const QModelIndex &parent=QModelIndex()) const; + int rowCount(const QModelIndex &parent=QModelIndex()) const; + QVariant headerData(int section,Qt::Orientation orient, + int role=Qt::DisplayRole) const; + QVariant data(const QModelIndex &index,int role=Qt::DisplayRole) const; + unsigned castId(const QModelIndex &row) const; + QModelIndex addCast(unsigned cast_id); + void removeCast(const QModelIndex &row); + void removeCast(unsigned cast_id); + void refresh(const QModelIndex &row); + void refresh(unsigned cast_id); + + public slots: + void setFilterSql(const QString &sql); + void processNotification(RDNotification *notify); + + protected: + void updateModel(); + void updateRowLine(int line); + void updateRow(int row,RDSqlQuery *q); + QString sqlFields() const; + + private: + QPalette d_palette; + QFont d_font; + QFontMetrics *d_font_metrics; + QFont d_bold_font; + QFontMetrics *d_bold_font_metrics; + bool d_include_none; + QList d_headers; + QList d_alignments; + QList d_cast_ids; + QList > d_texts; + QList > d_icons; + unsigned d_feed_id; + QString d_filter_sql; +}; + + +#endif // RDPODCASTLISTMODEL_H diff --git a/rdadmin/list_feeds.cpp b/rdadmin/list_feeds.cpp index da70b7e3..092871f8 100644 --- a/rdadmin/list_feeds.cpp +++ b/rdadmin/list_feeds.cpp @@ -98,7 +98,7 @@ ListFeeds::ListFeeds(QWidget *parent) connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); // - // Group List + // Feed List // list_feeds_view=new QTableView(this); list_feeds_view->setSelectionBehavior(QAbstractItemView::SelectRows); diff --git a/rdcastmanager/list_casts.cpp b/rdcastmanager/list_casts.cpp index b90439a6..6d0b3f4b 100644 --- a/rdcastmanager/list_casts.cpp +++ b/rdcastmanager/list_casts.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -32,15 +31,6 @@ #include "globals.h" #include "list_casts.h" -// -// Icons -// -#include "../icons/blueball.xpm" -#include "../icons/greenball.xpm" -#include "../icons/redball.xpm" -#include "../icons/whiteball.xpm" -#include "../icons/rdcastmanager-32x32.xpm" - ListCasts::ListCasts(unsigned feed_id,QWidget *parent) : RDDialog(parent) { @@ -54,21 +44,6 @@ ListCasts::ListCasts(unsigned feed_id,QWidget *parent) // setMinimumSize(sizeHint()); - // - // Create Icons - // - list_blueball_map=new QPixmap(blueball_xpm); - list_greenball_map=new QPixmap(greenball_xpm); - list_redball_map=new QPixmap(redball_xpm); - list_whiteball_map=new QPixmap(whiteball_xpm); - list_rdcastmanager_32x32_map=new QPixmap(rdcastmanager_32x32_xpm); - - // - // Notifications - // - connect(rda->ripc(),SIGNAL(notificationReceived(RDNotification *)), - this,SLOT(notificationReceivedData(RDNotification *))); - // // The Feed // @@ -95,63 +70,35 @@ ListCasts::ListCasts(unsigned feed_id,QWidget *parent) // // Filter // - list_filter_edit=new QLineEdit(this); - list_filter_label= - new QLabel(list_filter_edit,tr("Filter:"),this); - list_filter_label->setFont(labelFont()); - list_filter_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - connect(list_filter_edit,SIGNAL(textChanged(const QString &)), - this,SLOT(filterChangedData(const QString &))); + list_casts_filter=new RDPodcastFilter(this); // - // Active Check Box - // - list_active_check=new QCheckBox(this); - list_active_label= - new QLabel(list_active_check,tr("Only Show Active Items"),this); - list_active_label->setFont(labelFont()); - list_active_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); - connect(list_active_check,SIGNAL(toggled(bool)), - this,SLOT(activeToggledData(bool))); - - // - // Group List + // Podcast List // list_casts_label= new QLabel(list_feed->channelTitle(),this); list_casts_label->setFont(bigLabelFont()); list_casts_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); - list_casts_view=new RDListView(this); - list_casts_view->setAllColumnsShowFocus(true); - list_casts_view->setItemMargin(5); - list_casts_view->addColumn(tr(" ")); - list_casts_view->setColumnAlignment(0,Qt::AlignCenter); - list_casts_view->addColumn(tr("Title")); - list_casts_view->setColumnAlignment(1,Qt::AlignLeft); - - list_casts_view->addColumn(tr("Status")); - list_casts_view->setColumnAlignment(2,Qt::AlignCenter); - - list_casts_view->addColumn(tr("Start")); - list_casts_view->setColumnAlignment(3,Qt::AlignLeft); - list_casts_view->addColumn(tr("Expiration")); - list_casts_view->setColumnAlignment(4,Qt::AlignCenter); - list_casts_view->addColumn(tr("Length")); - list_casts_view->setColumnAlignment(5,Qt::AlignRight); - list_casts_view->addColumn(tr("Feed")); - list_casts_view->setColumnAlignment(6,Qt::AlignLeft); - list_casts_view->addColumn(tr("Category")); - list_casts_view->setColumnAlignment(7,Qt::AlignCenter); - list_casts_view->addColumn(tr("Posted By")); - list_casts_view->setColumnAlignment(8,Qt::AlignLeft); - list_casts_view->addColumn(tr("SHA1")); - list_casts_view->setColumnAlignment(9,Qt::AlignLeft); - if(!list_feed->isSuperfeed()) { - connect(list_casts_view, - SIGNAL(doubleClicked(Q3ListViewItem *,const QPoint &,int)), - this, - SLOT(doubleClickedData(Q3ListViewItem *,const QPoint &,int))); - } + list_casts_view=new QTableView(this); + list_casts_view->setSelectionBehavior(QAbstractItemView::SelectRows); + list_casts_view->setSelectionMode(QAbstractItemView::SingleSelection); + list_casts_view->setShowGrid(false); + list_casts_view->setSortingEnabled(false); + list_casts_view->setSortingEnabled(false); + list_casts_view->setWordWrap(false); + list_casts_model=new RDPodcastListModel(feed_id,this); + list_casts_model->setFont(font()); + list_casts_model->setPalette(palette()); + list_casts_view->setModel(list_casts_model); + connect(list_casts_model,SIGNAL(modelReset()),this,SLOT(modelResetData())); + connect(list_casts_model,SIGNAL(rowsInserted(const QModelIndex &,int,int)), + this,SLOT(rowsInsertedData(const QModelIndex &,int,int))); + connect(list_casts_view,SIGNAL(doubleClicked(const QModelIndex &)), + this,SLOT(doubleClickedData(const QModelIndex &))); + connect(list_casts_filter,SIGNAL(filterChanged(const QString &)), + list_casts_model,SLOT(setFilterSql(const QString &))); + connect(rda->ripc(),SIGNAL(notificationReceived(RDNotification *)), + list_casts_model,SLOT(processNotification(RDNotification *))); // // Post Cart Button @@ -205,10 +152,11 @@ ListCasts::ListCasts(unsigned feed_id,QWidget *parent) list_close_button->setText(tr("&Close")); connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); - RefreshList(); + // RefreshList(); connect(rda->ripc(),SIGNAL(userChanged()),this,SLOT(userChangedData())); + modelResetData(); userChangedData(); } @@ -247,14 +195,13 @@ void ListCasts::addCartData() RDFeed::errorString(err)); return; } - EditCast *edit_cast=new EditCast(cast_id,this); - edit_cast->exec(); - RDListViewItem *item=new RDListViewItem(list_casts_view); - item->setId(cast_id); - RefreshItem(item); - list_casts_view->setSelected(item,true); - list_casts_view->ensureItemVisible(item); - delete edit_cast; + EditCast *d=new EditCast(cast_id,this); + d->exec(); + QModelIndex row=list_casts_model->addCast(cast_id); + if(row.isValid()) { + list_casts_view->selectRow(row.row()); + } + delete d; rda->ripc()->sendNotification(RDNotification::FeedType, RDNotification::ModifyAction, @@ -280,14 +227,13 @@ void ListCasts::addFileData() RDFeed::errorString(err)); return; } - EditCast *edit_cast=new EditCast(cast_id,this); - edit_cast->exec(); - RDListViewItem *item=new RDListViewItem(list_casts_view); - item->setId(cast_id); - RefreshItem(item); - list_casts_view->setSelected(item,true); - list_casts_view->ensureItemVisible(item); - delete edit_cast; + EditCast *d=new EditCast(cast_id,this); + d->exec(); + QModelIndex row=list_casts_model->addCast(cast_id); + if(row.isValid()) { + list_casts_view->selectRow(row.row()); + } + delete d; rda->ripc()->sendNotification(RDNotification::FeedType, RDNotification::ModifyAction, @@ -303,9 +249,9 @@ void ListCasts::addLogData() RDFeed::Error err=RDFeed::ErrorOk; unsigned cast_id=0; - RDListLogs *d= + RDListLogs *lld= new RDListLogs(&logname,RDLogFilter::UserFilter,"RDCastManager",this); - if(d->exec()) { + if(lld->exec()) { RDLogModel *model=new RDLogModel(logname,true,this); model->load(); QTime start_time; @@ -319,11 +265,10 @@ void ListCasts::addLogData() start_line,end_line,&err))!=0) { EditCast *cast=new EditCast(cast_id,this); cast->exec(); - RDListViewItem *item=new RDListViewItem(list_casts_view); - item->setId(cast_id); - RefreshItem(item); - list_casts_view->setSelected(item,true); - list_casts_view->ensureItemVisible(item); + QModelIndex row=list_casts_model->addCast(cast_id); + if(row.isValid()) { + list_casts_view->selectRow(row.row()); + } delete cast; rda->ripc()->sendNotification(RDNotification::FeedType, RDNotification::ModifyAction, @@ -334,7 +279,7 @@ void ListCasts::addLogData() else { QMessageBox::warning(this,"RDCastManager - "+tr("Posting Error"), RDFeed::errorString(err)); - delete d; + delete lld; delete model; return; } @@ -344,41 +289,42 @@ void ListCasts::addLogData() else { // Render dialog was canceled! } } - delete d; + delete lld; } void ListCasts::editData() { - RDListViewItem *item=(RDListViewItem *)list_casts_view->selectedItem(); - if(item==NULL) { + QModelIndexList rows=list_casts_view->selectionModel()->selectedRows(); + + if(rows.size()!=1) { return; } - EditCast *edit_cast=new EditCast(item->id(),this); - if(edit_cast->exec()==0) { - RefreshItem(item); - + EditCast *d=new EditCast(list_casts_model->castId(rows.first()),this); + if(d->exec()) { + list_casts_model->refresh(rows.first()); rda->ripc()->sendNotification(RDNotification::FeedType, RDNotification::ModifyAction, list_feed->keyName()); rda->ripc()->sendNotification(RDNotification::FeedItemType, - RDNotification::ModifyAction,item->id()); + RDNotification::ModifyAction, + list_casts_model->castId(rows.first())); } - delete edit_cast; + delete d; } void ListCasts::deleteData() { QString sql; - RDSqlQuery *q; QString err_text; + QModelIndexList rows=list_casts_view->selectionModel()->selectedRows(); - RDListViewItem *item=(RDListViewItem *)list_casts_view->selectedItem(); - if(item==NULL) { + if(rows.size()!=1) { return; } - unsigned cast_id=item->id(); + + unsigned cast_id=list_casts_model->castId(rows.first()); if(QMessageBox::question(this,"RDCastManager - "+tr("Delete Item"), tr("Are you sure you want to delete this item?"), QMessageBox::Yes,QMessageBox::No)== @@ -395,7 +341,7 @@ void ListCasts::deleteData() qApp->processEvents(); sleep(1); qApp->processEvents(); - RDPodcast *cast=new RDPodcast(rda->config(),item->id()); + RDPodcast *cast=new RDPodcast(rda->config(),cast_id); if(!cast->dropAudio(list_feed,&err_text,rda->config()->logXloadDebugData())) { if(QMessageBox::warning(this,"RDCastManager - "+tr("Remote Error"), tr("Unable to drop remote audio!\n")+ @@ -409,13 +355,15 @@ void ListCasts::deleteData() } pd->setValue(1); qApp->processEvents(); - sql=QString().sprintf("delete from PODCASTS where ID=%u",item->id()); - q=new RDSqlQuery(sql); - delete q; - sql=QString().sprintf("update FEEDS set LAST_BUILD_DATETIME=now() \ - where ID=%u",list_feed_id); - q=new RDSqlQuery(sql); - delete q; + sql=QString("delete from PODCASTS where ")+ + QString().sprintf("ID=%u",cast_id); + RDSqlQuery::apply(sql); + + sql=QString("update FEEDS set ")+ + "LAST_BUILD_DATETIME=now() "+ + "where "+ + QString().sprintf("ID=%u",list_feed_id); + RDSqlQuery::apply(sql); if(!list_feed->postXml()) { QMessageBox::warning(this,"RDCastManager - "+tr("Remote Error"), @@ -426,7 +374,8 @@ void ListCasts::deleteData() delete pd; delete cast; - delete item; + + list_casts_model->removeCast(cast_id); rda->ripc()->sendNotification(RDNotification::FeedType, RDNotification::ModifyAction, list_feed->keyName()); @@ -435,8 +384,7 @@ void ListCasts::deleteData() } -void ListCasts::doubleClickedData(Q3ListViewItem *item,const QPoint &pt, - int col) +void ListCasts::doubleClickedData(const QModelIndex &index) { editData(); } @@ -457,19 +405,22 @@ void ListCasts::userChangedData() void ListCasts::filterChangedData(const QString &str) { - RefreshList(); + // RefreshList(); } -void ListCasts::notexpiredToggledData(bool state) +void ListCasts::modelResetData() { - RefreshList(); + list_casts_view->resizeColumnsToContents(); + list_casts_view->resizeRowsToContents(); } -void ListCasts::activeToggledData(bool state) +void ListCasts::rowsInsertedData(const QModelIndex &parent,int start,int end) { - RefreshList(); + for(int i=start;i<=end;i++) { + list_casts_view->resizeRowToContents(i); + } } @@ -491,10 +442,8 @@ void ListCasts::closeData() void ListCasts::resizeEvent(QResizeEvent *e) { - list_filter_label->setGeometry(10,10,40,20); - list_filter_edit->setGeometry(55,10,size().width()-65,20); - list_active_check->setGeometry(60,35,15,15); - list_active_label->setGeometry(80,33,200,20); + list_casts_filter-> + setGeometry(0,0,size().width(),list_casts_filter->sizeHint().height()); list_casts_label->setGeometry(15,57,size().width()-25,20); list_casts_view->setGeometry(10,76,size().width()-20,size().height()-146); list_cart_button->setGeometry(10,size().height()-60,80,50); @@ -504,158 +453,3 @@ void ListCasts::resizeEvent(QResizeEvent *e) list_delete_button->setGeometry(390,size().height()-60,80,50); list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); } - - -void ListCasts::notificationReceivedData(RDNotification *notify) -{ - unsigned cast_id=0; - RDListViewItem *item=NULL; - RDPodcast *cast=NULL; - - if(notify->type()==RDNotification::FeedItemType) { - cast_id=notify->id().toUInt(); - switch(notify->action()) { - case RDNotification::AddAction: - cast=new RDPodcast(rda->config(),cast_id); - if(cast->keyName()==list_feed->keyName()) { - item=new RDListViewItem(list_casts_view); - item->setId(cast_id); - RefreshItem(item); - delete cast; - return; - } - delete cast; - break; - - case RDNotification::DeleteAction: - item=(RDListViewItem *)list_casts_view->firstChild(); - while(item!=NULL) { - if(item->id()==(int)cast_id) { - delete item; - return; - } - item=(RDListViewItem *)item->nextSibling(); - } - break; - - case RDNotification::ModifyAction: - item=(RDListViewItem *)list_casts_view->firstChild(); - while(item!=NULL) { - if(item->id()==(int)cast_id) { - RefreshItem(item); - } - item=(RDListViewItem *)item->nextSibling(); - } - break; - - case RDNotification::LastAction: - case RDNotification::NoAction: - break; - - } - } -} - - -void ListCasts::RefreshList() -{ - QString sql; - RDSqlQuery *q; - RDListViewItem *item; - - list_casts_view->clear(); - sql=QString("select ID from PODCASTS ")+ - RDCastSearch(list_feed->keyName(),false, - list_filter_edit->text(), - list_active_check->isChecked())+ - " order by ORIGIN_DATETIME"; - q=new RDSqlQuery(sql); - while (q->next()) { - item=new RDListViewItem(list_casts_view); - item->setId(q->value(0).toInt()); - RefreshItem(item); - } - delete q; -} - - -void ListCasts::RefreshItem(RDListViewItem *item) -{ - QString sql; - RDSqlQuery *q; - - sql=QString("select ")+ - "PODCASTS.STATUS,"+ // 00 - "PODCASTS.ITEM_TITLE,"+ // 01 - "PODCASTS.EFFECTIVE_DATETIME,"+ // 02 - "PODCASTS.EXPIRATION_DATETIME,"+ // 03 - "PODCASTS.AUDIO_TIME,"+ // 04 - "PODCASTS.ITEM_DESCRIPTION,"+ // 05 - "FEEDS.KEY_NAME,"+ // 06 - "PODCASTS.ITEM_CATEGORY,"+ // 07 - "PODCASTS.ORIGIN_LOGIN_NAME,"+ // 08 - "PODCASTS.ORIGIN_STATION,"+ // 09 - "PODCASTS.ORIGIN_DATETIME,"+ // 10 - "PODCASTS.SHA1_HASH,"+ // 11 - "FEED_IMAGES.DATA "+ // 12 - "from PODCASTS left join FEEDS "+ - "on PODCASTS.FEED_ID=FEEDS.ID left join FEED_IMAGES "+ - "on PODCASTS.ITEM_IMAGE_ID=FEED_IMAGES.ID where "+ - QString().sprintf("PODCASTS.ID=%d",item->id()); - q=new RDSqlQuery(sql); - if(q->first()) { - if(q->value(12).isNull()) { - item->setPixmap(0,*list_rdcastmanager_32x32_map); - } - else { - QImage img=QImage::fromData(q->value(12).toByteArray()); - item->setPixmap(0,QPixmap::fromImage(img.scaled(32,32))); - } - item->setText(1,q->value(1).toString()); - switch((RDPodcast::Status)q->value(0).toUInt()) { - case RDPodcast::StatusActive: - if(q->value(2).toDateTime()<=QDateTime::currentDateTime()) { - item->setPixmap(2,*list_greenball_map); - } - else { - item->setPixmap(2,*list_blueball_map); - } - break; - - case RDPodcast::StatusPending: - item->setPixmap(2,*list_redball_map); - break; - - case RDPodcast::StatusExpired: - item->setPixmap(2,*list_whiteball_map); - break; - } - item->setText(3,q->value(2).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); - if(q->value(3).isNull()) { - item->setText(4,tr("Never")); - } - else { - item->setText(4,q->value(3).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); - } - item->setText(5,RDGetTimeLength(q->value(4).toInt(),false,false)); - - item->setText(6,q->value(6).toString()); - item->setText(7,q->value(7).toString()); - if(q->value(8).isNull()) { - item->setText(8,tr("unknown")+" "+tr("at")+" "+ - q->value(10).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); - } - else { - item->setText(8,q->value(8).toString()+" "+tr("on")+" "+ - q->value(9).toString()+" "+tr("at")+" "+ - q->value(10).toDateTime().toString("MM/dd/yyyy hh:mm:ss")); - } - if(q->value(11).toString().isEmpty()) { - item->setText(9,tr("[none]")); - } - else { - item->setText(9,q->value(11).toString()); - } - } - delete q; -} diff --git a/rdcastmanager/list_casts.h b/rdcastmanager/list_casts.h index ce5a2328..8fed40a4 100644 --- a/rdcastmanager/list_casts.h +++ b/rdcastmanager/list_casts.h @@ -23,11 +23,13 @@ #include #include +#include #include #include #include -#include +#include +#include #include "render_dialog.h" @@ -46,41 +48,30 @@ class ListCasts : public RDDialog void addLogData(); void editData(); void deleteData(); - void doubleClickedData(Q3ListViewItem *item,const QPoint &pt,int col); + void doubleClickedData(const QModelIndex &index); void userChangedData(); void filterChangedData(const QString &str); - void notexpiredToggledData(bool state); - void activeToggledData(bool state); + void modelResetData(); + void rowsInsertedData(const QModelIndex &parent,int start,int end); void postProgressChangedData(int step); void closeData(); - void notificationReceivedData(RDNotification *notify); protected: void resizeEvent(QResizeEvent *e); private: - void RefreshList(); - void RefreshItem(RDListViewItem *item); - void GetEncoderId(); RDCutDialog *list_cut_dialog; QLabel *list_casts_label; - RDListView *list_casts_view; + QTableView *list_casts_view; + RDPodcastListModel *list_casts_model; QPushButton *list_cart_button; QPushButton *list_file_button; QPushButton *list_log_button; QPushButton *list_edit_button; QPushButton *list_delete_button; QPushButton *list_close_button; - QPixmap *list_blueball_map; - QPixmap *list_greenball_map; - QPixmap *list_redball_map; - QPixmap *list_whiteball_map; - QPixmap *list_rdcastmanager_32x32_map; unsigned list_feed_id; - QLabel *list_filter_label; - QLineEdit *list_filter_edit; - QLabel *list_active_label; - QCheckBox *list_active_check; + RDPodcastFilter *list_casts_filter; QProgressDialog *list_progress_dialog; RenderDialog *list_render_dialog; RDFeed *list_feed; diff --git a/rdcastmanager/logdialog.cpp b/rdcastmanager/logdialog.cpp index 2e9d5f45..92a90196 100644 --- a/rdcastmanager/logdialog.cpp +++ b/rdcastmanager/logdialog.cpp @@ -50,9 +50,6 @@ LogDialog::LogDialog(QWidget *parent) LogDialog::~LogDialog() { - if(d_model!=NULL) { - delete d_model; - } } diff --git a/rdcastmanager/rdcastmanager_cs.ts b/rdcastmanager/rdcastmanager_cs.ts index 985c225a..60bffa5a 100644 --- a/rdcastmanager/rdcastmanager_cs.ts +++ b/rdcastmanager/rdcastmanager_cs.ts @@ -207,7 +207,7 @@ Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : Title - Název + Název Origin @@ -219,7 +219,7 @@ Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : Length - Délka + Délka Description @@ -227,7 +227,7 @@ Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : Category - Skupina + Skupina Link @@ -279,7 +279,7 @@ Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : Remote Error - Chyba u protistrany + Chyba u protistrany Unable to delete remote audio! @@ -289,7 +289,7 @@ Podcast trotzdem löschen? Never - Nikdy + Nikdy File Error @@ -309,11 +309,11 @@ Podcast trotzdem löschen? - + Filter: - Filtr: + Filtr: Only Show Unexpired Casts @@ -325,7 +325,7 @@ Podcast trotzdem löschen? Posting Error - Chyba při vyvěšení + Chyba při vyvěšení Unable to delete remote audio! @@ -334,20 +334,16 @@ Podcast trotzdem löschen? The server said: " - Server hlásí: " + Server hlásí: " Continue deleting cast? - Pokračovat v mazání podcastu? + Pokračovat v mazání podcastu? Cancel - - Feed - - Post From Log @@ -357,34 +353,6 @@ Log Podcast Item List - - Only Show Active Items - - - - Posted By - - - - at - - - - Start - - - - Expiration - - - - unknown - - - - on - - Delete Item @@ -397,18 +365,6 @@ Log Deleting Item... - - Select Audio File - - - - SHA1 - - - - [none] - - Unable to drop remote audio! @@ -419,7 +375,7 @@ Log - Status + Select Audio File diff --git a/rdcastmanager/rdcastmanager_de.ts b/rdcastmanager/rdcastmanager_de.ts index 29ec3bd4..b237bd6b 100644 --- a/rdcastmanager/rdcastmanager_de.ts +++ b/rdcastmanager/rdcastmanager_de.ts @@ -192,7 +192,7 @@ Car&t/Cut Title - Titel + Titel Origin @@ -204,7 +204,7 @@ Car&t/Cut Length - Länge + Länge Description @@ -212,7 +212,7 @@ Car&t/Cut Category - Kategorie + Kategorie Link @@ -264,7 +264,7 @@ Car&t/Cut Remote Error - Fehler an Gegenstelle + Fehler an Gegenstelle Unable to delete remote audio! @@ -274,7 +274,7 @@ Podcast trotzdem löschen? Never - Nie + Nie File Error @@ -294,11 +294,11 @@ Podcast trotzdem löschen? - + Filter: - Filter: + Filter: Only Show Unexpired Casts @@ -310,7 +310,7 @@ Podcast trotzdem löschen? Posting Error - Fehler beim posten + Fehler beim posten Unable to delete remote audio! @@ -319,20 +319,16 @@ Podcast trotzdem löschen? The server said: " - Der Server meldet: " + Der Server meldet: " Continue deleting cast? - Löschen des Podcasts fortsetzen? + Löschen des Podcasts fortsetzen? Cancel - - Feed - - Post From Log @@ -342,34 +338,6 @@ Log Podcast Item List - - Only Show Active Items - - - - Posted By - - - - at - - - - Start - - - - Expiration - - - - unknown - - - - on - - Delete Item @@ -382,18 +350,6 @@ Log Deleting Item... - - Select Audio File - - - - SHA1 - - - - [none] - - Unable to drop remote audio! @@ -404,7 +360,7 @@ Log - Status + Select Audio File diff --git a/rdcastmanager/rdcastmanager_es.ts b/rdcastmanager/rdcastmanager_es.ts index 04c818c3..067e6805 100644 --- a/rdcastmanager/rdcastmanager_es.ts +++ b/rdcastmanager/rdcastmanager_es.ts @@ -166,7 +166,7 @@ Episodios Title - Título + Título Origin @@ -182,7 +182,7 @@ Episodios Category - Categoría + Categoría Link @@ -190,7 +190,7 @@ Episodios Never - Nunca + Nunca Podcast List @@ -222,7 +222,7 @@ Car&t./Audio Length - Longitud + Longitud Subscription @@ -230,13 +230,9 @@ Car&t./Audio &Reporte de Suscripción - - - - Filter: - Filtro: + Filtro: Only Show Unexpired Casts @@ -248,7 +244,7 @@ Suscripción Posting Error - Error de Post + Error de Post Delete Podcast @@ -264,7 +260,7 @@ Suscripción Remote Error - Error remoto + Error remoto Unable to delete remote audio! @@ -274,20 +270,16 @@ Suscripción The server said: " - El servidor dio el error: " + El servidor dio el error: " Continue deleting cast? - ¿Continuar eliminando podcasts? + ¿Continuar eliminando podcasts? Cancel - - Feed - - Post From Log @@ -297,34 +289,6 @@ Log Podcast Item List - - Only Show Active Items - - - - Posted By - - - - at - - - - Start - - - - Expiration - - - - unknown - - - - on - - Delete Item @@ -337,18 +301,6 @@ Log Deleting Item... - - Select Audio File - - - - SHA1 - - - - [none] - - Unable to drop remote audio! @@ -359,7 +311,7 @@ Log - Status + Select Audio File diff --git a/rdcastmanager/rdcastmanager_fr.ts b/rdcastmanager/rdcastmanager_fr.ts index ade1acd6..6bbe9cf1 100644 --- a/rdcastmanager/rdcastmanager_fr.ts +++ b/rdcastmanager/rdcastmanager_fr.ts @@ -128,18 +128,6 @@ Car&t/Cut - - Title - - - - Length - - - - Category - - Uploading Audio... @@ -148,42 +136,10 @@ Car&t/Cut Progress - - Never - - - - - - - - Filter: - - - - Posting Error - - - - Remote Error - - - - The server said: " - - - - Continue deleting cast? - - Cancel - - Feed - - Post From Log @@ -194,31 +150,7 @@ Log - Only Show Active Items - - - - Posted By - - - - at - - - - Start - - - - Expiration - - - - unknown - - - - on + Posting Error @@ -234,15 +166,7 @@ Log - Select Audio File - - - - SHA1 - - - - [none] + Remote Error @@ -250,12 +174,20 @@ Log + + The server said: " + + + + Continue deleting cast? + + Unable to update remote XML data! - Status + Select Audio File diff --git a/rdcastmanager/rdcastmanager_nb.ts b/rdcastmanager/rdcastmanager_nb.ts index ebae7b99..cce8af3a 100644 --- a/rdcastmanager/rdcastmanager_nb.ts +++ b/rdcastmanager/rdcastmanager_nb.ts @@ -183,11 +183,11 @@ Korg/Ku&tt - + Title - Tittel + Tittel Origin @@ -199,7 +199,7 @@ Korg/Ku&tt Length - Lengd + Lengd Description @@ -207,7 +207,7 @@ Korg/Ku&tt Category - Kategori + Kategori Link @@ -273,7 +273,7 @@ Vil du halda fram med å sletta podkasten? Never - Aldri + Aldri File Error @@ -291,30 +291,10 @@ Vil du halda fram med å sletta podkasten? Unsupported file type! Filtypen er ikkje støtta! - - Filter: - - - - Posting Error - - - - The server said: " - - - - Continue deleting cast? - - Cancel - - Feed - - Post From Log @@ -325,31 +305,7 @@ Log - Only Show Active Items - - - - Posted By - - - - at - - - - Start - - - - Expiration - - - - unknown - - - - on + Posting Error @@ -364,29 +320,25 @@ Log Deleting Item... - - Select Audio File - - - - SHA1 - - - - [none] - - Unable to drop remote audio! + + The server said: " + + + + Continue deleting cast? + + Unable to update remote XML data! - Status + Select Audio File diff --git a/rdcastmanager/rdcastmanager_nn.ts b/rdcastmanager/rdcastmanager_nn.ts index ebae7b99..cce8af3a 100644 --- a/rdcastmanager/rdcastmanager_nn.ts +++ b/rdcastmanager/rdcastmanager_nn.ts @@ -183,11 +183,11 @@ Korg/Ku&tt - + Title - Tittel + Tittel Origin @@ -199,7 +199,7 @@ Korg/Ku&tt Length - Lengd + Lengd Description @@ -207,7 +207,7 @@ Korg/Ku&tt Category - Kategori + Kategori Link @@ -273,7 +273,7 @@ Vil du halda fram med å sletta podkasten? Never - Aldri + Aldri File Error @@ -291,30 +291,10 @@ Vil du halda fram med å sletta podkasten? Unsupported file type! Filtypen er ikkje støtta! - - Filter: - - - - Posting Error - - - - The server said: " - - - - Continue deleting cast? - - Cancel - - Feed - - Post From Log @@ -325,31 +305,7 @@ Log - Only Show Active Items - - - - Posted By - - - - at - - - - Start - - - - Expiration - - - - unknown - - - - on + Posting Error @@ -364,29 +320,25 @@ Log Deleting Item... - - Select Audio File - - - - SHA1 - - - - [none] - - Unable to drop remote audio! + + The server said: " + + + + Continue deleting cast? + + Unable to update remote XML data! - Status + Select Audio File diff --git a/rdcastmanager/rdcastmanager_pt_BR.ts b/rdcastmanager/rdcastmanager_pt_BR.ts index 8b8dca72..bf83dd59 100644 --- a/rdcastmanager/rdcastmanager_pt_BR.ts +++ b/rdcastmanager/rdcastmanager_pt_BR.ts @@ -166,7 +166,7 @@ Episódio Filter: - Filtro: + Filtro: Only Show Unexpired Casts @@ -178,12 +178,12 @@ Episódio - + Title - Título + Título Origin @@ -195,7 +195,7 @@ Episódio Length - Duração + Duração Description @@ -203,7 +203,7 @@ Episódio Category - Categoria + Categoria Link @@ -241,7 +241,7 @@ Assinaturas Posting Error - Erro na Postagem + Erro na Postagem Delete Podcast @@ -265,7 +265,7 @@ Assinaturas Remote Error - Erro Remoto + Erro Remoto Unable to delete remote audio! @@ -275,24 +275,12 @@ Continuar deletando cast? Never - Nunca - - - The server said: " - - - - Continue deleting cast? - + Nunca Cancel - - Feed - - Post From Log @@ -302,34 +290,6 @@ Log Podcast Item List - - Only Show Active Items - - - - Posted By - - - - at - - - - Start - - - - Expiration - - - - unknown - - - - on - - Delete Item @@ -342,29 +302,25 @@ Log Deleting Item... - - Select Audio File - - - - SHA1 - - - - [none] - - Unable to drop remote audio! + + The server said: " + + + + Continue deleting cast? + + Unable to update remote XML data! - Status + Select Audio File