Ticket #3334: importicons-libmythtv-09102007.diff

File importicons-libmythtv-09102007.diff, 36.1 KB (added by Matthew Wire <devel@…>, 19 years ago)

Import Icons patch - ready for full testing

  • libs/libmythtv/channeleditor.cpp

     
    1919#include "sourceutil.h"
    2020
    2121#include "scanwizard.h"
     22#include "importicons.h"
    2223
    2324ChannelWizard::ChannelWizard(int id, int default_sourceid)
    2425    : ConfigurationWizard()
     
    110111        return 0;
    111112}
    112113
    113 void ChannelListSetting::fillSelections(void)
     114int ChannelListSetting::fillSelections(void)
    114115{
    115116    QString currentValue = getValue();
     117
    116118    clearSelections();
    117119    addSelection(QObject::tr("(New Channel)"));
    118120    bool fAllSources = true;
     121    int nCount = 0;
    119122
    120123    QString querystr = "SELECT channel.name,channum,chanid ";
    121124
    122     if ((currentSourceID == "") || (currentSourceID == "Unassigned"))
     125    if ((currentSourceID == "") || (currentSourceID == "Unassigned")
     126                                || (currentSourceID == "(All)"))
    123127    {
    124128        querystr += ",videosource.name FROM channel "
    125129                    "LEFT JOIN videosource ON "
     
    184188                name += " (" + sourceid  + ")";
    185189
    186190            addSelection(name, chanid, (chanid == currentValue) ? true : false);
     191
     192            nCount++;
     193           
     194            // nCount increments first since "(New Channel)" offsets list by one
     195            if (chanid == currentValue)
     196                setCurrentItem(nCount);
    187197        }
    188198    }
     199    return nCount;
    189200}
    190201
    191202class SourceSetting : public ComboBoxSetting, public Storage
     
    194205    SourceSetting() : ComboBoxSetting(this)
    195206    {
    196207        setLabel(QObject::tr("Video Source"));
    197         addSelection(QObject::tr("(All)"),"");
     208        addSelection(QObject::tr("(All)"),"(All)");
    198209    };
    199210
    200211    void load()
     
    266277    buttonScan->setLabel(QObject::tr("Channel Scanner"));
    267278    buttonScan->setHelpText(QObject::tr("Starts the channel scanner."));
    268279    buttonScan->setEnabled(SourceUtil::IsAnySourceScanable());
     280   
     281    buttonImportIcon = new TransButtonSetting();
     282    buttonImportIcon->setLabel(QObject::tr("Icon Import"));
     283    buttonImportIcon->setHelpText(QObject::tr("Starts the icon importer"));
     284    buttonImportIcon->setEnabled(SourceUtil::IsAnySourceScanable());
    269285
    270286    buttonTransportEditor = new TransButtonSetting();
    271287    buttonTransportEditor->setLabel(QObject::tr("Transport Editor"));
     
    278294    HorizontalConfigurationGroup *h =
    279295        new HorizontalConfigurationGroup(false, false);
    280296    h->addChild(buttonScan);
     297    h->addChild(buttonImportIcon);
    281298    h->addChild(buttonTransportEditor);
    282299    addChild(h);
    283300
     
    293310            this, SLOT(menu(int)));
    294311    connect(buttonScan, SIGNAL(pressed()),
    295312            this, SLOT(scan()));
     313    connect(buttonImportIcon,  SIGNAL(pressed()),
     314            this, SLOT(channelIconImport()));
    296315    connect(buttonTransportEditor, SIGNAL(pressed()),
    297316            this, SLOT(transportEditor()));
    298317    connect(del,  SIGNAL(pressed()),
     
    459478    list->fillSelections();
    460479    list->setFocus();
    461480}
     481
     482void ChannelEditor::channelIconImport(void)
     483{
     484    if (list->fillSelections() == 0)
     485    {
     486        MythPopupBox::showOkPopup(gContext->GetMainWindow(), "",
     487                                        tr("Add some for channels first!"));
     488        return;
     489    }
     490   
     491    // Get selected channel name from database
     492    QString querystr = QString("SELECT channel.name FROM channel WHERE chanid='%1' ").arg(list->getValue());
     493    QString channelname = "";
     494    MSqlQuery query(MSqlQuery::InitCon());
     495    query.prepare(querystr);
     496   
     497    if (query.exec() && query.isActive() && query.size() > 0)
     498    {
     499        query.next();
     500        channelname = QString::fromUtf8(query.value(0).toString());
     501    }
     502   
     503    QStringList buttons;
     504    buttons.append(tr("Cancel"));
     505    buttons.append(tr("Import all icons.."));
     506    buttons.append(tr("Rescan for missing icons.."));
     507    if (channelname.isEmpty()==false)
     508        buttons.append(tr("Import icon for ") + channelname);
     509   
     510    int val = MythPopupBox::showButtonPopup(gContext->GetMainWindow(),
     511                                             "", "Channel Icon Import", buttons, 2);
     512    ImportIconsWizard *iconwizard;
     513    if (val == 0) // Cancel pressed
     514        return;
     515    else if (val == 1) // Import all icons pressed
     516        iconwizard = new ImportIconsWizard(false);
     517    else if (val == 2) // Rescan for missing pressed
     518        iconwizard = new ImportIconsWizard(true);
     519    else if (val == 3) // Import a single channel icon
     520        iconwizard = new ImportIconsWizard(true, channelname);
     521
     522    iconwizard->exec();
     523    iconwizard->deleteLater();
     524   
     525    list->fillSelections();
     526    list->setFocus();
     527}
  • libs/libmythtv/libmythtv.pro

     
    148148HEADERS += playgroup.h              progdetails.h
    149149HEADERS += channeleditor.h          channelsettings.h
    150150HEADERS += previewgenerator.h       transporteditor.h
     151HEADERS += importicons.h
    151152
    152153SOURCES += programinfo.cpp          proglist.cpp
    153154SOURCES += storagegroup.cpp
     
    170171SOURCES += progdetails.cpp
    171172SOURCES += channeleditor.cpp        channelsettings.cpp
    172173SOURCES += previewgenerator.cpp     transporteditor.cpp
     174SOURCES += importicons.cpp
    173175
    174176# DiSEqC
    175177HEADERS += diseqc.h                 diseqcsettings.h
  • libs/libmythtv/importicons.h

     
     1/* -*- Mode: c++ -*-
     2 * vim: set expandtab tabstop=4 shiftwidth=4:
     3 *
     4 * Original Project
     5 *      MythTV      http://www.mythtv.org
     6 *
     7 * Author(s):
     8 *      John Pullan, Matthew Wire 
     9 *
     10 * Description:
     11 */
     12
     13#ifndef IMPORTICONS_H
     14#define IMPORTICONS_H
     15
     16#include <qsqldatabase.h>
     17#include <qurl.h>
     18
     19#include "settings.h"
     20
     21class ImportIconsWizard : public QObject, public ConfigurationWizard
     22{
     23    Q_OBJECT
     24public:
     25    ImportIconsWizard(bool fRefresh, QString channelname=""); //!< constructs an ImportIconWizard
     26    MythDialog *dialogWidget(MythMainWindow *parent, const char *widgetName);
     27
     28    int exec();
     29
     30private:
     31
     32    enum dialogState
     33    {
     34        STATE_NORMAL,
     35        STATE_SEARCHING,
     36        STATE_DISABLED
     37    };
     38   
     39    struct CSVEntry                  //! describes the TV channel name
     40    {
     41        QString strChanId;           //!< local channel id
     42        QString strName;             //!< channel name
     43        QString strXmlTvId;          //!< the xmltvid
     44        QString strCallsign;         //!< callsign
     45        QString strTransportId;      //!< transport id
     46        QString strAtscMajorChan;    //!< ATSC major number
     47        QString strAtscMinorChan;    //!< ATSC minor number
     48        QString strNetworkId;        //!< network id
     49        QString strServiceId;        //!< service id
     50        QString strIconCSV;          //!< icon name (csv form)
     51        QString strNameCSV;          //!< name (csv form)
     52    }; 
     53    //! List of CSV entries
     54    typedef QValueList<CSVEntry> ListEntries;     
     55    //! iterator over list of CSV entries
     56    typedef QValueListIterator<CSVEntry> ListEntriesIter;
     57
     58    ListEntries m_listEntries;       //!< list of TV channels to search for
     59    ListEntries m_missingEntries;    //!< list of TV channels with no unique icon
     60    ListEntriesIter m_iter;          //!< the current iterator
     61    ListEntriesIter m_missingIter;
     62
     63    struct SearchEntry               //! search entry results
     64    {
     65        QString strID;               //!< the remote channel id
     66        QString strName;             //!< the remote name
     67        QString strLogo;             //!< the actual logo
     68    };
     69    //! List of SearchEntry entries
     70    typedef QValueList<SearchEntry> ListSearchEntries;
     71    //! iterator over list of SearchEntry entries
     72    typedef QValueListIterator<SearchEntry> ListSearchEntriesIter;
     73
     74    ListSearchEntries m_listSearch;  //!< the list of SearchEntry
     75    QString m_strMatches;            //!< the string for the submit() call
     76
     77    static const QString url;        //!< the default url
     78    QString m_strChannelDir;         //!< the location of the channel icon dir
     79    QString m_strChannelname;        //!< the channel name if searching for a single channel icon
     80
     81    bool m_fRefresh;                 //!< are we doing a refresh or not
     82    int m_nMaxCount;                 //!< the maximum number of TV channels
     83    int m_nCount;                    //!< the current search point (0..m_nMaxCount)
     84    int m_missingMaxCount;           //!< the total number of missing icons
     85    int m_missingCount;              //!< the current search point (0..m_missingCount)
     86
     87    void startDialog();
     88    bool importSingleIcon(const QString& channelname);
     89
     90    /*! \brief changes a string into csv format
     91     * \param str the string to change
     92     * \return the actual string
     93     */
     94    QString escape_csv(const QString& str);
     95
     96    /*! \brief extracts the csv values out of a string
     97     * \param str the string to work on
     98     * \return the actual QStringList
     99     */
     100    QStringList extract_csv(const QString& strLine);
     101
     102    /*! \brief use the equivalent of wget to fetch the POST command
     103     * \param url the url to send this to
     104     * \param strParam the string to send
     105     * \return the actual string
     106     */
     107    QString wget(QUrl& url,const QString& strParam);
     108 
     109    TransLineEditSetting *m_editName;    //!< name field for the icon
     110    TransListBoxSetting *m_listIcons;    //!< list of potential icons
     111    TransLineEditSetting *m_editManual;  //!< manual edit field
     112    TransButtonSetting *m_buttonManual;  //!< manual button field
     113    TransButtonSetting *m_buttonSkip;    //!< button skip
     114    TransButtonSetting *m_buttonSelect;    //!< button skip
     115
     116    /*! \brief determines if a particular icon is blocked
     117     * \param str the string to work on
     118     * \return true/false
     119     */
     120    bool isBlocked(const QString& strParam);
     121
     122    /*! \brief looks up the string to determine the caller/xmltvid
     123     * \param str the string to work on
     124     * \return true/false
     125     */
     126    bool lookup(const QString& strParam);
     127
     128    /*! \brief search the remote db for icons etc
     129     * \param str the string to work on
     130     * \return true/false
     131     */
     132    bool search(const QString& strParam);
     133
     134    /*! \brief submit the icon information back to the remote db
     135     * \param str the string to work on
     136     * \return true/false
     137     */
     138    bool submit(const QString& strParam);
     139
     140    /*! \brief retrieve the actual logo for the TV channel
     141     * \param str the string to work on
     142     * \return true/false
     143     */
     144    bool findmissing(const QString& strParam);
     145
     146    /*! \brief checks and attempts to download the logo file to the appropriate
     147     *   place
     148     * \param str the string of the downloaded url
     149     * \return true/false
     150     */
     151    bool checkAndDownload(const QString& str);
     152
     153    /*! \brief attempt the inital load of the TV channel information
     154     * \return the number of TV channels
     155     */
     156    unsigned initialLoad(QString name="");
     157
     158    /*! \brief attempts to move the itaration on one/more than one
     159     * \return true if we can go again or false if we can not
     160     */
     161    bool doLoad();
     162   
     163    bool m_closeDialog;
     164   
     165    ~ImportIconsWizard() { };
     166   
     167protected slots:
     168    void enableControls(dialogState state=STATE_NORMAL, bool selectEnabled=true);         //!< enable/disable the controls
     169    void manualSearch();           //!< process the manual search
     170    void menuSelect();
     171    void menuSelection(int nIndex);//!< process the icon selection
     172    void skip();                   //!< skip this icon
     173    void cancelPressed();
     174    void finishButtonPressed();
     175
     176};
     177
     178#endif // IMPORTICONS_H
  • libs/libmythtv/channeleditor.h

     
    2222    void edit();
    2323    void edit(int);
    2424    void scan(void);
    25     void transportEditor();
    26     void deleteChannels();
     25    void transportEditor(void);
     26    void channelIconImport(void);
     27    void deleteChannels(void);
    2728
    2829private:
    2930    int                 id;
    3031    SourceSetting      *source;
    3132    ChannelListSetting *list;
    3233    TransButtonSetting *buttonScan;
     34    TransButtonSetting *buttonImportIcon;
    3335    TransButtonSetting *buttonTransportEditor;
    3436};
    3537
     
    6870    bool getHideMode() { return currentHideMode; };
    6971
    7072public slots:
    71     void fillSelections(void);
     73    int fillSelections(void);
    7274    void setSortMode(const QString& sort) {
    7375        if (currentSortMode != sort) {
    7476            currentSortMode = sort;
  • libs/libmythtv/importicons.cpp

     
     1#include <sys/stat.h>
     2#include <qapplication.h>
     3#include <qregexp.h>
     4#include <qbuffer.h>
     5#include <qfileinfo.h>
     6
     7#include "mythwizard.h"
     8#include "httpcomms.h"
     9#include "importicons.h"
     10#include "util.h"
     11
     12ImportIconsWizard::ImportIconsWizard(bool fRefresh, QString channelname)
     13{
     14    m_fRefresh = fRefresh;   
     15    m_strChannelname = channelname;
     16    m_closeDialog = false;
     17    m_missingCount=0;
     18    m_missingMaxCount=0;
     19
     20}
     21
     22MythDialog *ImportIconsWizard::dialogWidget(MythMainWindow *parent,
     23                                     const char *widgetName)
     24{
     25    MythWizard *ret = (MythWizard*)ConfigurationWizard::dialogWidget(parent,widgetName);
     26    connect(ret->finishButton(), SIGNAL(pressed()), this, SLOT(finishButtonPressed()));
     27    return (MythDialog*)ret;
     28}
     29
     30int ImportIconsWizard::exec()
     31{
     32    m_strChannelDir =  MythContext::GetConfDir()+ "/channels";
     33    mkdir(MythContext::GetConfDir(),0776);
     34    mkdir(m_strChannelDir,0776);
     35    m_strChannelDir+="/";
     36
     37    if (m_strChannelname.isEmpty()){
     38        if (initialLoad() > 0)
     39        {
     40            startDialog();
     41            m_missingIter=m_missingEntries.begin();
     42            doLoad();
     43        }
     44    }
     45    else
     46    {
     47        importSingleIcon(m_strChannelname);
     48    }
     49
     50    if (m_closeDialog==false) // Need this if line to exit if cancel button is pressed
     51        while ((ConfigurationDialog::exec() == QDialog::Accepted) && (m_closeDialog == false))  {}
     52   
     53    return QDialog::Rejected;
     54}
     55
     56bool ImportIconsWizard::importSingleIcon(const QString& channelname)
     57{
     58    initialLoad(channelname);
     59    startDialog();
     60    m_missingMaxCount=1;
     61    m_editName->setValue(channelname);
     62    search(channelname);
     63}
     64
     65void ImportIconsWizard::startDialog()
     66{
     67    VerticalConfigurationGroup *manSearch =
     68        new VerticalConfigurationGroup(false,false,true,true);
     69   
     70    manSearch->addChild(m_editName = new TransLineEditSetting(false));
     71    m_editName->setLabel(QObject::tr("Name"));
     72    m_editName->setHelpText(QObject::tr("Name of the icon file"));
     73
     74    manSearch->addChild(m_listIcons = new TransListBoxSetting());
     75    m_listIcons->setHelpText(QObject::tr("List of possible icon files"));
     76
     77    m_editManual = new TransLineEditSetting();
     78    m_editManual->setHelpText(QObject::tr("Enter text here for the manual search"));
     79
     80    m_buttonManual = new TransButtonSetting();
     81    m_buttonManual->setLabel(QObject::tr("&Search"));
     82    m_buttonManual->setHelpText(QObject::tr("Manually search for the text"));
     83
     84    m_buttonSkip = new TransButtonSetting();
     85    m_buttonSkip->setLabel(QObject::tr("S&kip"));
     86    m_buttonSkip->setHelpText(QObject::tr("Skip this icon"));
     87
     88    m_buttonSelect = new TransButtonSetting();
     89    m_buttonSelect->setLabel(QObject::tr("S&elect"));
     90    m_buttonSelect->setHelpText(QObject::tr("Select this icon"));
     91
     92    HorizontalConfigurationGroup *hrz1 =
     93        new HorizontalConfigurationGroup(false, false, true, true);
     94
     95    hrz1->addChild(m_editManual);
     96    hrz1->addChild(m_buttonManual);
     97    hrz1->addChild(m_buttonSkip);
     98    hrz1->addChild(m_buttonSelect);
     99    manSearch->addChild(hrz1);
     100   
     101    addChild(manSearch);
     102
     103    connect(m_buttonManual, SIGNAL(pressed()), this, SLOT(manualSearch()));
     104    connect(m_buttonSkip, SIGNAL(pressed()), this, SLOT(skip()));
     105    connect(m_listIcons,SIGNAL(accepted(int)),this,
     106             SLOT(menuSelection(int)));
     107    connect(m_buttonSelect,SIGNAL(pressed()),this,
     108            SLOT(menuSelect()));
     109
     110    enableControls(STATE_NORMAL);
     111}
     112
     113const QString ImportIconsWizard::url="http://services.mythtv.org/channel-icon/";
     114
     115void ImportIconsWizard::enableControls(dialogState state, bool selectEnabled)
     116{
     117    switch (state)
     118    {
     119        case STATE_NORMAL:
     120            if (m_editManual->getValue())
     121                 m_buttonManual->setEnabled(true);
     122            else
     123            m_buttonManual->setEnabled(false);
     124            if (m_missingCount < m_missingMaxCount)
     125            {
     126                if (m_missingMaxCount < 2) //When there's only one icon, nothing to skip to!
     127                    m_buttonSkip->setEnabled(false);
     128                else
     129                    m_buttonSkip->setEnabled(true);
     130                m_editName->setEnabled(true);
     131                m_listIcons->setEnabled(true);
     132                m_editManual->setEnabled(true);
     133                m_buttonSelect->setEnabled(selectEnabled);
     134            }
     135            else
     136            {
     137                m_buttonSkip->setEnabled(false);
     138                m_editName->setEnabled(false);
     139                m_listIcons->setEnabled(false);
     140                m_editManual->setEnabled(false);
     141                m_buttonManual->setEnabled(false);
     142                m_buttonSelect->setEnabled(false);
     143            }
     144            break;
     145        case STATE_SEARCHING:
     146            m_buttonSkip->setEnabled(false);
     147            m_buttonSelect->setEnabled(false);
     148            m_buttonManual->setEnabled(false);
     149            m_listIcons->setEnabled(false);
     150            m_listIcons->clearSelections();
     151            m_listIcons->addSelection("Please wait...");
     152            m_editManual->setValue("");
     153            break;
     154        case STATE_DISABLED:
     155            m_buttonSkip->setEnabled(false);
     156            m_buttonSelect->setEnabled(false);
     157            m_buttonManual->setEnabled(false);
     158            m_listIcons->setEnabled(false);
     159            m_listIcons->clearSelections();
     160            m_editName->setEnabled(false);
     161            m_editName->setValue("");
     162            m_editManual->setEnabled(false);
     163            m_editManual->setValue("");
     164            m_listIcons->setFocus();
     165            break;   
     166    }       
     167}
     168
     169void ImportIconsWizard::manualSearch()
     170{
     171    QString str = m_editManual->getValue();
     172    search(escape_csv(str));   
     173}
     174
     175void ImportIconsWizard::skip()
     176{
     177    if (m_missingMaxCount > 1)
     178    {
     179        m_missingCount++;
     180        m_missingIter++;   
     181        doLoad();
     182    }
     183}
     184
     185void ImportIconsWizard::menuSelect()
     186{
     187    menuSelection(m_listIcons->currentItem());   
     188}
     189
     190void ImportIconsWizard::menuSelection(int nIndex)
     191{
     192    enableControls(STATE_SEARCHING);
     193    SearchEntry entry = *(m_listSearch.at(nIndex));
     194
     195    if ((!isBlocked((*m_iter).strIconCSV)) &&
     196            (checkAndDownload(entry.strLogo)))
     197    {
     198        CSVEntry entry2 = (*m_iter);
     199        m_strMatches += QString("%1,%2,%3,%4,%5,%6,%7,%8,%9\n").
     200                              arg(escape_csv(entry.strID)).
     201                              arg(escape_csv(entry2.strName)).
     202                              arg(escape_csv(entry2.strXmlTvId)).
     203                              arg(escape_csv(entry2.strCallsign)).
     204                              arg(escape_csv(entry2.strTransportId)).
     205                              arg(escape_csv(entry2.strAtscMajorChan)).
     206                              arg(escape_csv(entry2.strAtscMinorChan)).
     207                              arg(escape_csv(entry2.strNetworkId)).
     208                              arg(escape_csv(entry2.strServiceId));
     209        if (m_missingMaxCount > 1)
     210        {
     211            m_missingCount++;
     212            m_missingIter++;
     213            doLoad();
     214        }
     215        else
     216        {
     217            enableControls(STATE_DISABLED);
     218            m_closeDialog=true;
     219            m_listIcons->addSelection(QString("Channel icon for %1 was downloaded successfully.")
     220                                      .arg(entry2.strName));
     221        }
     222    }
     223    else
     224    {
     225        MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     226                            QObject::tr("Error downloading"),
     227                            QObject::tr("Failed to download the icon file"));
     228        enableControls(STATE_DISABLED);
     229        m_closeDialog=true;
     230    }
     231
     232}
     233
     234unsigned ImportIconsWizard::initialLoad(QString name)
     235{
     236    // Do not try and access dialog within this function
     237    VERBOSE(VB_CHANNEL, "initialLoad");
     238   
     239    QString querystring=("SELECT chanid,name,xmltvid,callsign,"
     240                  "dtv_multiplex.transportid, "
     241                  "atsc_major_chan,atsc_minor_chan,dtv_multiplex.networkid,"
     242                  "channel.serviceid, "
     243                  "channel.mplexid, dtv_multiplex.mplexid,"
     244                  "channel.icon, channel.visible FROM "
     245                  "channel, dtv_multiplex WHERE "
     246                  "channel.visible && "
     247                  "channel.mplexid=dtv_multiplex.mplexid");
     248    if (name.isEmpty()==false)
     249        querystring+=" && name=\"" + name + "\"";
     250    querystring+=" ORDER BY name";
     251
     252    MSqlQuery query(MSqlQuery::InitCon());
     253    query.prepare(querystring);
     254       
     255    m_listEntries.clear();           
     256    m_nCount=0;
     257    m_nMaxCount=0;
     258    m_missingMaxCount=0;
     259
     260    if (query.exec() && query.isActive() && query.size() > 0)
     261    {
     262        MythProgressDialog *progressDialog = new MythProgressDialog("Initialising, please wait...", query.size());
     263       
     264        sleep(2); // Ensures dialog is drawn before ping freezes execution
     265       
     266        if (!ping("services.mythtv.org", 3))
     267        {
     268            progressDialog->Close();
     269            progressDialog->deleteLater();
     270            MythPopupBox::showOkPopup(gContext->GetMainWindow(),
     271                                  tr("Bad Host"),
     272                                  tr("Failed to connect to the remote server"));
     273            return 0;
     274        }
     275
     276        while(query.next())
     277        {
     278            CSVEntry entry;
     279
     280            if (m_fRefresh)
     281            {
     282                QFileInfo file(query.value(11).toString());
     283                if (file.exists())
     284                    continue;
     285            }
     286           
     287            entry.strChanId=query.value(0).toString();
     288            entry.strName=query.value(1).toString();
     289            entry.strXmlTvId=query.value(2).toString();
     290            entry.strCallsign=query.value(3).toString();
     291            entry.strTransportId=query.value(4).toString();
     292            entry.strAtscMajorChan=query.value(5).toString();
     293            entry.strAtscMinorChan=query.value(6).toString();
     294            entry.strNetworkId=query.value(7).toString();
     295            entry.strServiceId=query.value(8).toString();
     296            entry.strIconCSV= QString("%1,%2,%3,%4,%5,%6,%7,%8,%9\n").
     297                              arg(escape_csv(entry.strChanId)).
     298                              arg(escape_csv(entry.strName)).
     299                              arg(escape_csv(entry.strXmlTvId)).
     300                              arg(escape_csv(entry.strCallsign)).
     301                              arg(escape_csv(entry.strTransportId)).
     302                              arg(escape_csv(entry.strAtscMajorChan)).
     303                              arg(escape_csv(entry.strAtscMinorChan)).
     304                              arg(escape_csv(entry.strNetworkId)).
     305                              arg(escape_csv(entry.strServiceId));
     306            entry.strNameCSV=escape_csv(entry.strName);
     307            VERBOSE(VB_CHANNEL,QString("chanid %1").arg(entry.strIconCSV));
     308
     309            m_listEntries.append(entry);
     310            m_nMaxCount++;
     311            progressDialog->setProgress(m_nMaxCount);
     312        }
     313        progressDialog->Close();
     314        progressDialog->deleteLater();
     315    }
     316   
     317    m_iter = m_listEntries.begin();
     318   
     319    if (name.isEmpty())
     320    {
     321        MythProgressDialog *progressDialog = new MythProgressDialog("Downloading, please wait...",
     322                                m_listEntries.size()+1, true, this, SLOT(cancelPressed()));
     323        while (!m_closeDialog && (m_iter != m_listEntries.end()))
     324        {
     325            progressDialog->setLabel(QString("Downloading %1 / %2 : ").arg(m_nCount+1)
     326                                     .arg(m_listEntries.size()+1) + (*m_iter).strName +
     327                                     QString("\nCould not find %1 icons.").arg(m_missingEntries.size()+1));
     328            if (!findmissing((*m_iter).strIconCSV))
     329                m_missingEntries.append((*m_iter));
     330            m_nCount++;
     331            m_iter++;
     332            m_missingMaxCount++;
     333            progressDialog->setProgress(m_nCount);
     334        }
     335        progressDialog->Close();
     336        progressDialog->deleteLater();
     337    }
     338   
     339    //Comment below for debugging - cancel button will continue to dialog
     340    if (m_closeDialog)
     341        m_nMaxCount=0;
     342    return m_nMaxCount;
     343}
     344
     345bool ImportIconsWizard::doLoad()
     346{
     347    VERBOSE(VB_CHANNEL, QString("%1 / %2").arg(m_missingCount).arg(m_missingMaxCount));
     348    if (m_missingCount >= m_missingMaxCount)
     349    {
     350        VERBOSE(VB_CHANNEL, "doLoad Icon search complete");
     351        if (!m_strMatches.isEmpty())
     352            submit(m_strMatches);
     353        m_closeDialog=true;
     354        return false;
     355    }
     356    else
     357    {
     358        // Look for the next missing icon
     359        m_editName->setValue((*m_missingIter).strName);
     360        search((*m_missingIter).strNameCSV);
     361        return true;
     362    }
     363}
     364
     365QString ImportIconsWizard::escape_csv(const QString& str)
     366{
     367    VERBOSE(VB_CHANNEL, "escape_csv");
     368    QRegExp rxDblForEscape("\"");
     369    QString str2 = str;
     370    str2.replace(rxDblForEscape,"\\\"");
     371    return "\""+str2+"\"";
     372}
     373
     374QStringList ImportIconsWizard::extract_csv(const QString& strLine)
     375{
     376    VERBOSE(VB_CHANNEL, "extract_csv");
     377    QStringList ret;
     378    //Clean up the line and split out the fields
     379    QString str = strLine;
     380
     381    unsigned int pos = 0;
     382    bool fFinish = false;
     383    while(!fFinish)
     384    {
     385        str=str.stripWhiteSpace();
     386        while(!fFinish)
     387        {
     388            QString strLeft;
     389            switch (str.at(pos).unicode())
     390            {
     391            case '\\':
     392                if (pos>=1)
     393                    str.left(pos-1)+str.mid(pos+1);
     394                else
     395                    str=str.mid(pos+1);
     396                pos+=2;
     397                if (pos > str.length())
     398                {
     399                    strLeft = str.left(pos);
     400                    if (strLeft.startsWith("\"") && strLeft.endsWith("\""))
     401                        strLeft=strLeft.mid(1,strLeft.length()-2);
     402                    ret.append(strLeft);
     403                    fFinish = true;
     404                }
     405                break;
     406            case ',':
     407                strLeft = str.left(pos);
     408                if (strLeft.startsWith("\"") && strLeft.endsWith("\""))
     409                    strLeft=strLeft.mid(1,strLeft.length()-2);
     410                ret.append(strLeft);
     411                if ((pos+1) > str.length())
     412                   fFinish = true;
     413                str=str.mid(pos+1);
     414                pos=0;
     415                break;
     416            default:
     417                pos++;
     418                if (pos > str.length())
     419                {
     420                    strLeft = str.left(pos);
     421                    if (strLeft.startsWith("\"") && strLeft.endsWith("\""))
     422                        strLeft=strLeft.mid(1,strLeft.length()-2);
     423                    ret.append(strLeft);
     424                    fFinish = true;
     425                }
     426            }
     427        }
     428    }
     429    return ret;
     430}
     431
     432
     433QString ImportIconsWizard::wget(QUrl& url,const QString& strParam )
     434{
     435    VERBOSE(VB_CHANNEL, "wget");
     436    QByteArray raw;
     437    QTextStream rawStream(raw,IO_WriteOnly);
     438    rawStream << strParam;
     439
     440    QBuffer data(raw);
     441    QHttpRequestHeader header;
     442
     443    header.setContentType(QString("application/x-www-form-urlencoded"));
     444    header.setContentLength(raw.size());
     445
     446    header.setValue("User-Agent", "MythTV Channel Icon lookup bot");
     447
     448    QString str = HttpComms::postHttp(url,&header,&data);
     449
     450    return str;
     451}
     452
     453bool ImportIconsWizard::checkAndDownload(const QString& str)
     454{
     455    // Do not try and access dialog within this function
     456    VERBOSE(VB_CHANNEL, "checkAndDownload");
     457   
     458    int iIndex = str.findRev('/');
     459    QString str2;
     460    if (iIndex < 0)
     461        str2=str;
     462    else
     463        str2=str.mid(iIndex+1);
     464
     465    QString str3 = str;
     466    QFileInfo file(m_strChannelDir+str2);
     467
     468    bool fRet;
     469    if (!file.exists())
     470        fRet = HttpComms::getHttpFile(m_strChannelDir+str2,str3);   
     471    else
     472        fRet = true;
     473
     474    if (fRet)
     475    {
     476        MSqlQuery query(MSqlQuery::InitCon());
     477        QString  qstr = "UPDATE channel SET icon = :ICON "
     478                        "WHERE chanid = :CHANID";
     479
     480        query.prepare(qstr);
     481        query.bindValue(":ICON", m_strChannelDir+str2);
     482        query.bindValue(":CHANID", (*m_iter).strChanId);
     483
     484        if (!query.exec())
     485        {
     486            MythContext::DBError("Error inserting channel icon", query);
     487            return false;
     488        }
     489 
     490    }
     491
     492    return fRet;
     493}
     494
     495bool ImportIconsWizard::isBlocked(const QString& strParam)
     496{
     497    VERBOSE(VB_CHANNEL, "isBlocked");
     498    QString strParam1 = strParam;
     499    QUrl::encode(strParam1);
     500    QUrl url(ImportIconsWizard::url+"/checkblock");
     501    QString str = wget(url,"csv="+strParam1);
     502
     503    if (str.startsWith("Error",false))
     504    {
     505        VERBOSE(VB_IMPORTANT, QString("Error from isBlocked : %1").arg(str));
     506        return true;
     507    }
     508    else if (str.isEmpty() || str.startsWith("\r\n"))
     509        return false;
     510    else
     511    {
     512        VERBOSE(VB_CHANNEL, QString("Icon Import: Working isBlocked"));
     513        int nVal = MythPopupBox::showOkCancelPopup(gContext->GetMainWindow(),
     514                            QObject::tr("Icon is blocked"),
     515                            QObject::tr("This combination of channel and icon "
     516                                        "has been blocked by the MythTV "
     517                                        "admins. The most common reason for "
     518                                        "this is that there is a better match "
     519                                        "available.\n "
     520                                        "Are you still sure that you want to "
     521                                        "use this icon?"),
     522                          true);       
     523        if (nVal == 1) // Use the icon
     524            return false;
     525        else // Don't use the icon
     526            return true;
     527    }
     528}
     529
     530
     531bool ImportIconsWizard::lookup(const QString& strParam)
     532{
     533    QString strParam1 = "callsign="+strParam;
     534    QUrl::encode(strParam1);
     535    QUrl url(ImportIconsWizard::url+"/lookup");
     536
     537    QString str = wget(url,strParam1);
     538    if (str.isEmpty() || str.startsWith("Error",false))
     539    {
     540        VERBOSE(VB_IMPORTANT, QString("Error from lookup : %1").arg(str));
     541        return true;
     542    }
     543    else
     544    {
     545        VERBOSE(VB_CHANNEL, QString("Icon Import: Working lookup : %1").arg(str));
     546        return false;
     547    }
     548}
     549
     550bool ImportIconsWizard::search(const QString& strParam)
     551{
     552    QString strParam1 = strParam;
     553    bool retVal = false;
     554    enableControls(STATE_SEARCHING);
     555    QUrl::encode(strParam1);
     556    QUrl url(ImportIconsWizard::url+"/search");
     557
     558    QString str = wget(url,"s="+strParam1);
     559   
     560    m_listSearch.clear();
     561    m_listIcons->clearSelections();
     562
     563    if (str.isEmpty() || str.startsWith("#") || str.startsWith("Error",false))
     564    {
     565        VERBOSE(VB_IMPORTANT, QString("Error from search : %1").arg(str));
     566        retVal=false;
     567    }
     568    else
     569    {
     570        VERBOSE(VB_CHANNEL, QString("Icon Import: Working search : %1").arg(str));
     571        QStringList strSplit=QStringList::split("\n",str);
     572
     573        for (QStringList::iterator begin=strSplit.begin();
     574             begin!=strSplit.end();begin++)
     575        {
     576            if (*begin != "#" )
     577            {
     578                QStringList ret = extract_csv(*begin);
     579                VERBOSE(VB_CHANNEL, QString("Icon Import: search : %1 %2 %3").arg(ret[0]).arg(ret[1]).arg(ret[2]));
     580                SearchEntry entry;
     581                entry.strID=ret[0];
     582                entry.strName=ret[1];
     583                entry.strLogo=ret[2];
     584                m_listSearch.append(entry);
     585                m_listIcons->addSelection(entry.strName);
     586            }
     587        }
     588        retVal=true;
     589    }
     590    enableControls(STATE_NORMAL, retVal);
     591    return retVal;
     592}
     593
     594bool ImportIconsWizard::findmissing(const QString& strParam)
     595{
     596    QString strParam1 = strParam;
     597    QUrl::encode(strParam1);
     598    QUrl url(ImportIconsWizard::url+"/findmissing");
     599
     600    QString str = wget(url,"csv="+strParam1);
     601    VERBOSE(VB_CHANNEL, QString("Icon Import: findmissing : strParam1 = %1. str = %2").arg(strParam1).arg(str));   
     602    if (str.isEmpty() || str.startsWith("#") || str.startsWith("Error",false))
     603    {
     604        VERBOSE(VB_IMPORTANT, QString("Error from findmissing : %1").arg(str));
     605        return false;
     606    }
     607    else
     608    {
     609        VERBOSE(VB_CHANNEL, QString("Icon Import: Working findmissing : %1").arg(str));
     610        QStringList strSplit=QStringList::split("\n",str);
     611        for (QStringList::iterator begin=strSplit.begin();
     612             begin!=strSplit.end();begin++)
     613        {
     614            if (*begin != "#" )
     615            {
     616                QStringList ret = extract_csv(*begin);
     617                VERBOSE(VB_CHANNEL, QString("Icon Import: findmissing : %1 %2 %3 %4 %5").arg(ret[0]).arg(ret[1]).arg(ret[2]).arg(ret[3]).arg(ret[4]));
     618                checkAndDownload(ret[4]);
     619            }
     620        }
     621        return true;
     622    }
     623}
     624
     625bool ImportIconsWizard::submit(const QString& strParam)
     626{
     627    enableControls(STATE_DISABLED);
     628   
     629    int nVal = MythPopupBox::showOkCancelPopup(
     630                            gContext->GetMainWindow(),
     631                            QObject::tr("Submit information"),
     632                            QObject::tr("You now have the opportunity to "
     633                                        "transmit your choices  back to "
     634                                        "mythtv.org so that others can "
     635                                        "benefit from your selections."),
     636                            true);       
     637    if (nVal == 0) // If cancel is pressed exit
     638        return false;
     639   
     640    QString strParam1 = strParam;
     641    QUrl::encode(strParam1);
     642    QUrl url(ImportIconsWizard::url+"/submit");
     643
     644    QString str = wget(url,"csv="+strParam1);
     645    if (str.isEmpty() || str.startsWith("#") || str.startsWith("Error",false))
     646    {
     647        VERBOSE(VB_IMPORTANT, QString("Error from submit : %1").arg(str));
     648        return false;
     649    }
     650    else
     651    {
     652        VERBOSE(VB_CHANNEL, QString("Icon Import: Working submit : %1").arg(str));
     653        QStringList strSplit=QStringList::split("\n",str);
     654        unsigned atsc =0, dvb =0, callsign =0, tv =0, xmltvid=0;
     655        for (QStringList::iterator begin=strSplit.begin();
     656             begin!=strSplit.end();begin++)
     657        {
     658            if (*begin != "#" )
     659            {
     660                QStringList strSplit2=QStringList::split(":",*begin);
     661                QString s=strSplit2[0].stripWhiteSpace();
     662                if (s=="a")
     663                     atsc=strSplit2[1].toUInt();
     664                else if (s=="c")
     665                     callsign=strSplit2[1].toUInt();
     666                else if (s=="d")
     667                     dvb=strSplit2[1].toUInt();
     668                else if (s=="t")
     669                     tv=strSplit2[1].toUInt();
     670                else if (s=="x")
     671                     xmltvid=strSplit2[1].toUInt();
     672            }
     673        }
     674        VERBOSE(VB_CHANNEL, QString("Icon Import: working submit : atsc=%1 callsign=%2 dvb=%3 tv=%4 xmltvid=%5")
     675                                              .arg(atsc).arg(callsign).arg(dvb).arg(tv).arg(xmltvid));
     676        return true;
     677    }
     678}
     679
     680void ImportIconsWizard::cancelPressed()
     681{
     682    m_closeDialog=true;
     683}
     684
     685void ImportIconsWizard::finishButtonPressed()
     686{
     687    m_closeDialog = true;
     688}