// rdlibrarymodel.cpp // // Data model for the Rivendell cart library // // (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 "rdlibrarymodel.h" #include "rdtimeprobe.h" RDLibraryModel::RDLibraryModel(QObject *parent) : QAbstractItemModel(parent) { d_font_metrics=NULL; d_bold_font_metrics=NULL; d_show_notes=false; d_filter_sql=""; d_cart_limit=RD_MAX_CART_NUMBER+1; // Effectively "unlimited" d_sort_column=0; d_sort_order=Qt::AscendingOrder; d_sort_clauses[Qt::AscendingOrder]="asc"; d_sort_clauses[Qt::DescendingOrder]="desc"; d_filter_set=false; // // Column Attributes // unsigned left=Qt::AlignLeft|Qt::AlignVCenter; unsigned center=Qt::AlignCenter; unsigned right=Qt::AlignRight|Qt::AlignVCenter; d_headers.push_back(tr("Cart")); // 00 d_alignments.push_back(center); d_order_columns.push_back("`CART`.`NUMBER`"); d_headers.push_back(tr("Group")); // 01 d_alignments.push_back(center); d_order_columns.push_back("`CART`.`GROUP_NAME`"); d_headers.push_back(tr("Length")); // 02 d_alignments.push_back(right); d_order_columns.push_back("`CART`.`FORCED_LENGTH`"); d_headers.push_back(tr("Talk")); // 03 d_alignments.push_back(right); d_order_columns.push_back("`CART`.`MAXIMUM_TALK_LENGTH`"); d_headers.push_back(tr("Title")); // 04 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`TITLE`"); d_headers.push_back(tr("Artist")); // 05 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`ARTIST`"); d_headers.push_back(tr("Start")); // 06 d_alignments.push_back(center); d_order_columns.push_back("`CART`.`START_DATETIME`"); d_headers.push_back(tr("End")); // 07 d_alignments.push_back(center); d_order_columns.push_back("`CART`.`END_DATETIME`"); d_headers.push_back(tr("Album")); // 08 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`ALBUM`"); d_headers.push_back(tr("Label")); // 09 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`LABEL`"); d_headers.push_back(tr("Composer")); // 10 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`COMPOSER`"); d_headers.push_back(tr("Conductor")); // 11 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`CONDUCTOR`"); d_headers.push_back(tr("Publisher")); // 12 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`PUBLISHER`"); d_headers.push_back(tr("Client")); // 13 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`CLIENT`"); d_headers.push_back(tr("Agency")); // 14 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`AGENCY`"); d_headers.push_back(tr("User Defined")); // 15 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`USER_DEFINED`"); d_headers.push_back(tr("Cuts")); // 16 d_alignments.push_back(right); d_order_columns.push_back("`CART`.`CUT_QUANTITY`"); d_headers.push_back(tr("Last Cut Played")); // 17 d_alignments.push_back(right); d_order_columns.push_back("`CART`.`LAST_CUT_PLAYED`"); d_headers.push_back(tr("Enforce Length")); // 18 d_alignments.push_back(center); d_order_columns.push_back("`CART`.`ENFORCE_LENGTH`"); d_headers.push_back(tr("Length Deviation")); // 19 d_alignments.push_back(center); d_order_columns.push_back("`CART`.`LENGTH_DEVIATION`"); d_headers.push_back(tr("Owned By")); // 20 d_alignments.push_back(left); d_order_columns.push_back("`CART`.`OWNER`"); } RDLibraryModel::~RDLibraryModel() { } QPalette RDLibraryModel::palette() { return d_palette; } void RDLibraryModel::setPalette(const QPalette &pal) { d_palette=pal; } void RDLibraryModel::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); } QModelIndex RDLibraryModel::index(int row,int col, const QModelIndex &parent) const { if(!parent.isValid()) { return createIndex(row,col,(quintptr)0); } if((parent.column()==0)&&(parent.internalId()==0)) { return createIndex(row,col,(quintptr)(1+parent.row())); } return QModelIndex(); } QModelIndex RDLibraryModel::parent(const QModelIndex &index) const { if(index.isValid()&&(index.internalId()>0)) { return createIndex(index.internalId()-1,0,(quintptr)0); } return QModelIndex(); } int RDLibraryModel::columnCount(const QModelIndex &parent) const { return d_headers.size(); } int RDLibraryModel::rowCount(const QModelIndex &parent) const { if(parent.isValid()) { if(parent.internalId()==0) { return d_cut_texts.at(parent.row()).size(); } return d_cut_texts.at(parent.internalId()-1).size(); } return d_texts.size(); } bool RDLibraryModel::hasChildren(const QModelIndex &parent) const { if(parent.isValid()) { if((parent.internalId()==0)&&(parent.column()==0)) { return d_cut_texts.at(parent.row()).size()>0; } return false; } return true; } Qt::ItemFlags RDLibraryModel::flags(const QModelIndex &index) const { return Qt::ItemIsSelectable|Qt::ItemIsDragEnabled|Qt::ItemIsEnabled; } QVariant RDLibraryModel::headerData(int section,Qt::Orientation orient, int role) const { if((orient==Qt::Horizontal)&&(role==Qt::DisplayRole)) { return d_headers.at(section); } return QVariant(); } QVariant RDLibraryModel::data(const QModelIndex &index,int role) const { QString str; int col=index.column(); int row=index.row(); QPixmap pix; if(!index.isValid()) { return QVariant(); } if(index.internalId()>0) { // Cuts if(rowwidth(d_cut_texts. at(index.internalId()-1).at(row).at(col).toString()), RD_LISTWIDGET_ITEM_HEIGHT); default: break; } } } else { // Carts if(row().width())+ d_font_metrics->width(d_texts.at(row).at(col).toString()), RD_LISTWIDGET_ITEM_HEIGHT); default: break; } } } return QVariant(); } void RDLibraryModel::sort(int col,Qt::SortOrder order) { d_sort_column=col; d_sort_order=order; if(d_filter_set) { setFilterSql(d_filter_sql,d_cart_limit); } /* printf("RDLibraryModel::sort():\n"); printf(" d_filter_sql: %s\n",d_filter_sql.toUtf8().constData()); printf(" d_cart_limit: %d\n",d_cart_limit); printf("\n"); */ } bool RDLibraryModel::isCart(const QModelIndex &index) const { return index.internalId()==0; } bool RDLibraryModel::isCut(const QModelIndex &index) const { return index.internalId()>0; } unsigned RDLibraryModel::cartNumber(const QModelIndex &index) const { if(index.isValid()) { if(isCart(index)) { return d_cart_numbers.at(index.row()); } return d_cart_numbers.at(index.internalId()-1); } return 0; } QString RDLibraryModel::cutName(const QModelIndex &index) const { if(index.isValid()) { if(isCut(index)) { return d_cut_cutnames.at(index.internalId()-1).at(index.row()); } } return QString(); } QModelIndex RDLibraryModel::cartRow(unsigned cartnum) const { int pos=d_cart_numbers.indexOf(cartnum); if(pos<0) { return QModelIndex(); } return createIndex(pos,0,(quintptr)0); } QModelIndex RDLibraryModel::cutRow(const QString &cutname) const { int cartpos=d_cart_numbers.indexOf(RDCut::cartNumber(cutname)); if(cartpos<0) { return QModelIndex(); } int cutpos=d_cut_cutnames.at(cartpos).indexOf(cutname); if(cutpos<0) { return QModelIndex(); } return createIndex(cutpos,0,cartpos+1); } RDCart::Type RDLibraryModel::cartType(const QModelIndex &index) const { if(isCart(index)) { return d_cart_types.at(index.row()); } return d_cart_types.at(index.internalId()-1); } QString RDLibraryModel::cartOwnedBy(const QModelIndex &index) { if(isCart(index)) { return d_texts.at(index.row()).at(20).toString(); } return d_texts.at(index.internalId()-1).at(20).toString(); } QModelIndex RDLibraryModel::addCart(unsigned cartnum) { // // Find the insertion offset // int offset=d_texts.size(); for(int i=0;i list; for(int i=0;i > list_list; list_list.push_back(list); d_icons.insert(offset,list); d_texts.insert(offset,list); d_notes.insert(offset,QVariant()); d_cart_numbers.insert(offset,0); d_cut_texts.insert(offset,list_list); d_cut_cutnames.insert(offset,QStringList()); d_background_colors.insert(offset,QVariant()); d_cart_types.insert(offset,RDCart::All); QString sql=sqlFields()+ "where "+ QString::asprintf("`CART`.`NUMBER`=%u",cartnum); RDSqlQuery *q=new RDSqlQuery(sql); if(q->first()) { updateRow(offset,q); } delete q; endInsertRows(); emit rowCountChanged(d_texts.size()); return createIndex(offset,0,(quintptr)0); } void RDLibraryModel::removeCart(const QModelIndex &index) { beginRemoveRows(QModelIndex(),index.row(),index.row()); d_texts.removeAt(index.row()); d_notes.removeAt(index.row()); d_cart_numbers.removeAt(index.row()); d_cut_texts.removeAt(index.row()); d_cut_cutnames.removeAt(index.row()); d_background_colors.removeAt(index.row()); d_cart_types.removeAt(index.row()); d_icons.removeAt(index.row()); endRemoveRows(); emit rowCountChanged(d_texts.size()); } void RDLibraryModel::removeCart(unsigned cartnum) { for(int i=0;iprintWaypoint("updateModel - 1"); QString sql; RDSqlQuery *q=NULL; // // Placeholder values // QList list; QList icons; for(int i=0;i > list_list; list_list.push_back(list); probe->printWaypoint("updateModel - 2"); // // Reload the color table // d_group_colors.clear(); sql=QString("select ")+ "`NAME`,"+ // 00 "`COLOR` "+ // 01 "from `GROUPS` order by `NAME`"; q=new RDSqlQuery(sql); while(q->next()) { d_group_colors[q->value(0).toString()]=QColor(q->value(1).toString()); } delete q; probe->printWaypoint("updateModel - 3"); sql=sqlFields()+ filter_sql; beginResetModel(); d_texts.clear(); d_notes.clear(); d_cart_numbers.clear(); d_cut_texts.clear(); d_cut_cutnames.clear(); d_background_colors.clear(); d_cart_types.clear(); d_icons.clear(); unsigned prev_cartnum=0; int carts_loaded=0; probe->printWaypoint("updateModel - 4"); // printf("RDLibraryModel::updateModel() SQL: %s\n",sql.toUtf8().constData()); q=new RDSqlQuery(sql); while(q->next()&&(carts_loadedvalue(0).toUInt()!=prev_cartnum) { d_texts.push_back(list); d_notes.push_back(QVariant()); d_cart_numbers.push_back(0); d_cut_texts.push_back(list_list); d_cut_cutnames.push_back(QStringList()); d_background_colors.push_back(QVariant()); d_cart_types.push_back(RDCart::All); d_icons.push_back(icons); updateRow(d_texts.size()-1,q); prev_cartnum=q->value(0).toUInt(); carts_loaded++; } // printf("carts_loaded: %d\n",carts_loaded); } delete q; probe->printWaypoint("updateModel - 5"); endResetModel(); probe->printWaypoint("updateModel - 6"); emit rowCountChanged(d_texts.size()); probe->printWaypoint("updateModel - 7"); delete probe; } void RDLibraryModel::updateCartLine(int cartline) { QString sql=sqlFields()+ "where "+ "`CART`.`NUMBER`="+d_texts.at(cartline).at(0).toString(); RDSqlQuery *q=new RDSqlQuery(sql); if(q->first()) { updateRow(cartline,q); emit dataChanged(createIndex(cartline,0,(quintptr)0), createIndex(cartline,columnCount(),(quintptr)0)); } delete q; } void RDLibraryModel::updateRow(int row,RDSqlQuery *q) { unsigned cartnum=q->value(0).toUInt(); // // Text Values (Qt::Display) // switch((RDCart::Type)q->value(15).toUInt()) { case RDCart::Audio: if(q->value(21).isNull()) { d_icons[row][0]=rda->iconEngine()->typeIcon(RDLogLine::Cart); } else { d_icons[row][0]= rda->iconEngine()->typeIcon(RDLogLine::Cart,RDLogLine::Tracker); } break; case RDCart::Macro: d_icons[row][0]=rda->iconEngine()->typeIcon(RDLogLine::Macro); break; case RDCart::All: break; } d_cart_types[row]=(RDCart::Type)q->value(15).toUInt(); d_texts[row][0]= // Cart Number QString::asprintf("%06d",q->value(0).toUInt()); d_cart_numbers[row]=q->value(0).toUInt(); d_texts[row][1]=q->value(12); // Group d_texts[row][2]=RDGetTimeLength(q->value(1).toUInt()); // Total Length if(q->value(16).toUInt()==1) { d_texts[row][3]= // Talk Length RDGetTimeLength(q->value(28).toUInt()-q->value(27).toUInt()); } else { d_texts[row][3]="0:00"; } d_texts[row][4]=q->value(2); // Title d_texts[row][5]=q->value(3); // Artist if(!q->value(13).toDateTime().isNull()) { // Start DateTime d_texts[row][6]= q->value(13).toDateTime().toString("MM/dd/yyyy - hh:mm:ss"); } else { d_texts[row][6]=QVariant(); } if(!q->value(14).toDateTime().isNull()) { // End DateTime d_texts[row][7]=q->value(14).toDateTime().toString("MM/dd/yyyy - hh:mm:ss"); } else { d_texts[row][7]=tr("TFN"); } d_texts[row][8]=q->value(4); // Album d_texts[row][9]=q->value(5); // Label d_texts[row][10]=q->value(9); // Composer d_texts[row][11]=q->value(11); // Conductor d_texts[row][12]=q->value(10); // Publisher d_texts[row][13]=q->value(6); // Client d_texts[row][14]=q->value(7); // Agency d_texts[row][15]=q->value(8); // User Defined d_texts[row][16]= // Cut Quan QString::asprintf("%u",q->value(16).toUInt()); d_texts[row][17]= // Last Cut Played QString::asprintf("%u",q->value(17).toUInt()); d_texts[row][18]=q->value(18); // Enforce Length d_texts[row][19]= // Length Deviation QString::asprintf("%u",q->value(20).toUInt()); d_texts[row][20]=q->value(21); // Owned By d_notes[row]=q->value(30).toString(); if(q->value(15).toUInt()==RDCart::Audio) { switch((RDCart::Validity)q->value(22).toUInt()) { case RDCart::NeverValid: d_background_colors[row]=QColor(RD_CART_ERROR_COLOR); break; case RDCart::ConditionallyValid: if(q->value(14).toDateTime().isValid()&& (q->value(14).toDateTime()value(15).toUInt()==RDCart::Macro) { d_background_colors[row]= QColor(palette().color(QPalette::Active,QPalette::Base)); } // // Cut Attributes // d_cut_texts[row].clear(); d_cut_cutnames[row].clear(); QList list; for(int i=0;ivalue(24).isNull()) { return; // No cuts! } // Process d_cut_cutnames[row].push_back(q->value(24).toString()); d_cut_texts[row].push_back(list); d_cut_texts[row].back()[0]=tr("Cut")+ // Cut Number QString::asprintf(" %03d",RDCut::cutNumber(q->value(24).toString())); d_cut_texts[row].back()[2]= // Length RDGetTimeLength(q->value(26).toUInt()-q->value(25).toUInt()); d_cut_texts[row].back()[3]= // Talk Length RDGetTimeLength(q->value(28).toUInt()-q->value(27).toUInt()); d_cut_texts[row].back()[4]=q->value(29).toString(); // Description } while(q->next()&&(q->value(0).toUInt()==cartnum)); q->previous(); } QString RDLibraryModel::sqlFields() const { QString sql=QString("select distinct ")+ "`CART`.`NUMBER`,"+ // 00 "`CART`.`FORCED_LENGTH`,"+ // 01 "`CART`.`TITLE`,"+ // 02 "`CART`.`ARTIST`,"+ // 03 "`CART`.`ALBUM`,"+ // 04 "`CART`.`LABEL`,"+ // 05 "`CART`.`CLIENT`,"+ // 06 "`CART`.`AGENCY`,"+ // 07 "`CART`.`USER_DEFINED`,"+ // 08 "`CART`.`COMPOSER`,"+ // 09 "`CART`.`PUBLISHER`,"+ // 10 "`CART`.`CONDUCTOR`,"+ // 11 "`CART`.`GROUP_NAME`,"+ // 12 "`CART`.`START_DATETIME`,"+ // 13 "`CART`.`END_DATETIME`,"+ // 14 "`CART`.`TYPE`,"+ // 15 "`CART`.`CUT_QUANTITY`,"+ // 16 "`CART`.`LAST_CUT_PLAYED`,"+ // 17 "`CART`.`ENFORCE_LENGTH`,"+ // 18 "`CART`.`PRESERVE_PITCH`,"+ // 19 "`CART`.`LENGTH_DEVIATION`,"+ // 20 "`CART`.`OWNER`,"+ // 21 "`CART`.`VALIDITY`,"+ // 22 "`GROUPS`.`COLOR`,"+ // 23 "`CUTS`.`CUT_NAME`,"+ // 24 "`CUTS`.`START_POINT`,"+ // 25 "`CUTS`.`END_POINT`,"+ // 26 "`CUTS`.`TALK_START_POINT`,"+ // 27 "`CUTS`.`TALK_END_POINT`,"+ // 28 "`CUTS`.`DESCRIPTION`,"+ // 29 "`CART`.`NOTES`,"+ // 30 "`CUTS`.`PLAY_ORDER` "+ // 31 "from `CART` "+ "left join `GROUPS` on `CART`.`GROUP_NAME`=`GROUPS`.`NAME` "+ "left join `CUTS` on `CART`.`NUMBER`=`CUTS`.`CART_NUMBER` "+ "left join `CART_SCHED_CODES` "+ "on `CART`.`NUMBER`=`CART_SCHED_CODES`.`CART_NUMBER` "; return sql; } QByteArray RDLibraryModel::DumpIndex(const QModelIndex &index,const QString &caption) const { QByteArray ret; if(!caption.isEmpty()) { ret+=(caption+": ").toUtf8(); } if(index.isValid()) { ret+=QString::asprintf("QModelIndex(%d,%d,%llu)", index.row(),index.column(),index.internalId()). toUtf8(); } else { ret+=QString("QModelIndex()").toUtf8(); } return ret; }