Re: [linux-minidisc] implementing netmd support in the gui application
Hi,
as some patches have been committed since i started implementation of
netmd support i rebased my local master branch now and updated my local
work branch.
You can find my work at netmd_integration_latest branch on my github
account [1].
Also i made a patch which can be applied to the current master
repository attached to this email.
Thomas
[1] http://github.com/tharp/linux-minidisc
>From 6444acb4e5fdc7c4b77d37cf26306a639722fe96 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Wed, 9 Jan 2013 23:57:41 +0100
Subject: [PATCH] implement netmd support in qhimdtransfer, also some basic
rearrangement needed for switching between himd and netmd
devices, move himd transfer routines to new class
QHiMDDevice, some minor bugs fixed
---
qhimdtransfer/qhimddetection.cpp | 262 +++++++++++++++++---
qhimdtransfer/qhimddetection.h | 106 +++++---
qhimdtransfer/qhimdmainwindow.cpp | 444 ++++++++-------------------------
qhimdtransfer/qhimdmainwindow.h | 30 +--
qhimdtransfer/qhimdmainwindow.ui | 18 +-
qhimdtransfer/qhimdmodel.cpp | 289 ----------------------
qhimdtransfer/qhimdmodel.h | 68 -----
qhimdtransfer/qhimdtransfer.pro | 13 +-
qhimdtransfer/qhimduploaddialog.cpp | 4 +-
qhimdtransfer/qhimduploaddialog.h | 4 +-
qhimdtransfer/qhimdwindetection.cpp | 203 ++++++++++-----
qhimdtransfer/qmddevice.cpp | 480 ++++++++++++++++++++++++++++++++++++
qhimdtransfer/qmddevice.h | 98 ++++++++
qhimdtransfer/qmdmodel.cpp | 358 +++++++++++++++++++++++++++
qhimdtransfer/qmdmodel.h | 80 ++++++
qhimdtransfer/qmdtrack.cpp | 204 +++++++++++++++
qhimdtransfer/qmdtrack.h | 81 ++++++
17 files changed, 1888 insertions(+), 854 deletions(-)
delete mode 100644 qhimdtransfer/qhimdmodel.cpp
delete mode 100644 qhimdtransfer/qhimdmodel.h
create mode 100644 qhimdtransfer/qmddevice.cpp
create mode 100644 qhimdtransfer/qmddevice.h
create mode 100644 qhimdtransfer/qmdmodel.cpp
create mode 100644 qhimdtransfer/qmdmodel.h
create mode 100644 qhimdtransfer/qmdtrack.cpp
create mode 100644 qhimdtransfer/qmdtrack.h
diff --git a/qhimdtransfer/qhimddetection.cpp b/qhimdtransfer/qhimddetection.cpp
index d563587..d0839bb 100644
--- a/qhimdtransfer/qhimddetection.cpp
+++ b/qhimdtransfer/qhimddetection.cpp
@@ -1,73 +1,279 @@
#include <QtCore/QDebug>
#include "qhimddetection.h"
+#include <QDebug>
+
+void QHiMDDetection::clearDeviceList()
+{
+ QMDDevice * mddev;
+ QNetMDDevice * nmddev;
+ int i = 0;
+
+ while( i < dlist.count() )
+ {
+ mddev = dlist.at(i);
+ if(mddev->deviceType() == NETMD_DEVICE)
+ {
+ nmddev = static_cast<QNetMDDevice *>(mddev);
+ if(nmddev->isOpen())
+ nmddev->close();
+ delete nmddev;
+ nmddev = NULL;
+ dlist.removeAt(i);
+ continue;
+ }
+ else if(mddev->deviceType() == HIMD_DEVICE)
+ {
+ remove_himddevice(mddev->path()); // uses platform dependent function if available
+ continue;
+ }
+ }
+
+ if(!dlist.isEmpty())
+ dlist.clear();
+ emit deviceListChanged(dlist);
+}
QHiMDDetection::QHiMDDetection(QObject *parent) :
QObject(parent)
{
}
-himd_device *QHiMDDetection::find_by_path(QString path)
+QHiMDDetection::~QHiMDDetection()
{
- for (int i = 0; i < device_list.size(); i++)
- if(device_list.at(i)->path == path)
- return device_list.at(i);
+ clearDeviceList();
+ cleanup_netmd_list();
+}
- return NULL;
+void QHiMDDetection::cleanup_netmd_list()
+{
+ if(dev_list != NULL)
+ netmd_clean(&dev_list);
+}
+
+void QHiMDDetection::rescan_netmd_devices()
+{
+ QNetMDDevice * dev;
+ int i = 0;
+
+ // find and remove netmd devices
+ while(i < dlist.count())
+ {
+ if(dlist.at(i)->deviceType() != NETMD_DEVICE)
+ {
+ i++;
+ continue;
+ }
+ dev = static_cast<QNetMDDevice *>(dlist.at(i));
+ if(dev->isOpen())
+ dev->close();
+
+ delete dev;
+ dev = NULL;
+ dlist.removeAt(i);
+ }
+
+ netmd_clean(&dev_list);
+ dev_list = NULL;
+
+ emit deviceListChanged(dlist);
+ scan_for_netmd_devices();
}
-// slots
+void QHiMDDetection::scan_for_minidisc_devices()
+{
+ os_data data;
-void QHiMDDetection::himd_busy(QString path)
+ /* create device entry for disc images first */
+ QHiMDDevice * mddev = new QHiMDDevice();
+ data.md_inserted = true;
+ mddev->setName("disc image");
+ mddev->setPlatformData(data);
+ dlist.append(mddev);
+ emit deviceListChanged(dlist);
+
+ scan_for_himd_devices();
+ scan_for_netmd_devices();
+}
+
+void QHiMDDetection::remove_himddevice(QString path)
{
- himd_device * dev = find_by_path(path);
- if (!dev)
+ QHiMDDevice * dev = static_cast<QHiMDDevice *>(find_by_path(path));
+ int i = dlist.indexOf(find_by_path(path));
+
+ if(i < 0)
return;
- dev->is_busy = true;
- qDebug() << "himd device at " + dev->path + " : device busy, starting transfer";
+ if(dev->isOpen())
+ dev->close();
+ delete dev;
+ dev = NULL;
+
+ dlist.removeAt(i);
}
-void QHiMDDetection::himd_idle(QString path)
+void QHiMDDetection::scan_for_netmd_devices()
{
- himd_device * dev = find_by_path(path);
- if (!dev)
+ netmd_device * md;
+ netmd_error error = netmd_init(&dev_list);
+ struct libusb_device_descriptor desc;
+ QNetMDDevice * mddev;
+
+ if (error != NETMD_NO_ERROR)
return;
- dev->is_busy = false;
- qDebug() << "himd device at " + dev->path + " : device idle, transfer complete";
+ md = dev_list; // pick first device
+
+ while( md != NULL) {
+ libusb_get_device_descriptor(md->usb_dev, &desc);
+ mddev = new QNetMDDevice();
+ mddev->setName(identify_usb_device(desc.idVendor, desc.idProduct));
+ mddev->setUsbDevice(md);
+ dlist.append(mddev);
+ emit deviceListChanged(dlist);
+ md = md->link; // pick next device
+ }
+}
+
+QMDDevice *QHiMDDetection::find_by_path(QString path)
+{
+ QMDDevice * mddev;
+
+ foreach(mddev, dlist)
+ {
+ if(mddev->path() == path)
+ return mddev;
+ }
+ return NULL;
+}
+
+QMDDevice *QHiMDDetection::find_by_name(QString name)
+{
+ QMDDevice * mddev;
+
+ foreach(mddev, dlist)
+ {
+ if(mddev->name() == name)
+ return mddev;
+ }
+ return NULL;
}
const char * identify_usb_device(int vid, int pid)
{
+ if(vid == SHARP)
+ {
+ switch(pid)
+ {
+ case IM_MT880H:
+ return "SHARP IM-MT880H / IM-MT899H (NetMD)";
+ case IM_DR400:
+ return "SHARP IM-DR400 / IM-DR410 (NetMD)";
+ case IM_DR80:
+ return "SHARP IM-DR80 / IM-DR420/ IM-DR580 or KENWOOD DMC-S9NET (NetMD)";
+ }
+ }
+
if (vid != SONY)
return NULL;
switch (pid)
{
- case MZ_NH1:
+ case MZ_NH1_HIMD:
return "SONY MZ-NH1";
- case MZ_NH3D:
+ case MZ_NH3D_HIMD:
return "SONY MZ-NH3D";
- case MZ_NH900:
+ case MZ_NH900_HIMD:
return "SONY MZ-NH900";
- case MZ_NH700:
+ case MZ_NH700_HIMD:
return "SONY MZ-NH700 / MZ-NH800";
- case MZ_NH600:
+ case MZ_NH600_HIMD:
return "SONY MZ-NH600(D)";
- case LAM_3:
+ case LAM_3_HIMD:
return "SONY LAM-3";
- case MZ_DH10P:
+ case MZ_DH10P_HIMD:
return "SONY MZ-DH10P";
- case MZ_RH10:
+ case MZ_RH10_HIMD:
return "SONY MZ-RH10";
- case MZ_RH910:
+ case MZ_RH910_HIMD:
return "SONY MZ-RH910";
- case CMT_AH10:
+ case CMT_AH10_HIMD:
return "SONY CMT-AH10";
- case DS_HMD1:
+ case DS_HMD1_HIMD:
return "SONY DS-HMD1";
- case MZ_RH1:
+ case MZ_RH1_HIMD:
return "SONY MZ-RH1";
+ case PCLK_XX:
+ return "SONY PCLK-XX (NetMD)";
+ case UNKNOWN_A:
+ return "SONY (unknown model, NetMD)";
+ case MZ_N1:
+ return "SONY MZ-N1 (NetMD)";
+ case UNKNOWN_B:
+ return "SONY (unknown model, NetMD)";
+ case LAM_1:
+ return "Sony LAM-1 (NetMD)";
+ case MDS_JE780:
+ return "SONY MDS-JE780 / MDS-JE980 (NetMD)";
+ case MZ_N505:
+ return "SONY MZ-N505 (NetMD)";
+ case MZ_S1:
+ return "SONY MZ-S1 (NetMD)";
+ case MZ_N707:
+ return "SONY MZ-N707 (NetMD)";
+ case CMT_C7NT:
+ return "SONY CMT-C7NT (NetMD)";
+ case PCGA_MDN1:
+ return "SONY PCGA-MDN1 (NetMD)";
+ case CMT_L7HD:
+ return "SONY CMT-L7HD (NetMD)";
+ case MZ_N10:
+ return "SONY MZ-N10 (NetMD)";
+ case MZ_N910:
+ return "SONY MZ-N910 (NetMD)";
+ case MZ_N710:
+ return "SONY MZ-N710 / MZ-NE810 / MZ-NF810 (NetMD)";
+ case MZ_N510:
+ return "SONY MZ-N510 (NetMD)";
+ case MZ_NE410:
+ return "SONY MZ-NE410 / MZ-DN430 / MZ-NF520 (NetMD)";
+ case MZ_NE810:
+ return "SONY MZ-NE810 / MZ-NE910 (NetMD)";
+ case CMT_M333NT:
+ return "SONY CMT-M333NT / CMT_M373NT (NetMD)";
+ case LAM_10:
+ return "SONY LAM-10 (NetMD)";
+ case AIWA_AM_NX1:
+ return "AIWA AM-NX1 (NetMD)";
+ case AIWA_AM_NX9:
+ return "AIWA AM-NX9 (NetMD)";
+ case MZ_NH1:
+ return "SONY MZ-NH1 (NetMD)";
+ case MZ_NH3D:
+ return "SONY MZ-NH3D (NetMD)";
+ case MZ_NH900:
+ return "SONY MZ-NH900 (NetMD)";
+ case MZ_NH700:
+ return "SONY MZ-NH700 / MZ-NH800 (NetMD)";
+ case MZ_NH600:
+ return "SONY MZ-NH600 / MZ-NH600D (NetMD)";
+ case MZ_N920:
+ return "SONY MZ-N920 (NetMD)";
+ case LAM_3:
+ return "SONY LAM-3 (NetMD)";
+ case MZ_DH10P:
+ return "SONY MZ-DH10P (NetMD)";
+ case MZ_RH10:
+ return "SONY MZ-RH10 (NetMD)";
+ case MZ_RH910:
+ return "SONY MZ-RH910 (NetMD)";
+ case CMT_AH10_A:
+ return "SONY CMT-AH10 (NetMD)";
+ case CMT_AH10_B:
+ return "SONY CMT-AH10 (NetMD)";
+ case DS_HMD1:
+ return "SONY DS-HMD1 (NetMD)";
+ case MZ_RH1:
+ return "SONY MZ-RH1 (NetMD)";
}
return NULL;
}
diff --git a/qhimdtransfer/qhimddetection.h b/qhimdtransfer/qhimddetection.h
index 5c30be9..9d53305 100644
--- a/qhimdtransfer/qhimddetection.h
+++ b/qhimdtransfer/qhimddetection.h
@@ -4,52 +4,98 @@
#include <QObject>
#include <QList>
#include <QString>
+#include <qmddevice.h>
-#define SONY 0x054c //known himd-mode product IDs
-#define MZ_NH1 0x017f
-#define MZ_NH3D 0x0181
-#define MZ_NH900 0x0183
-#define MZ_NH700 0x0185
-#define MZ_NH600 0x0187
-#define LAM_3 0x018a
-#define MZ_DH10P 0x01ea
-#define MZ_RH10 0x021a
-#define MZ_RH910 0x021c
-#define CMT_AH10 0x022d
-#define DS_HMD1 0x023d
-#define MZ_RH1 0x0287
-
-struct himd_device {
- bool is_busy;
- QString path;
- bool md_inserted;
- QString recorder_name;
- virtual ~himd_device(){} /* for polymorphic delete */
- };
+// known vendor IDs
+#define SONY 0x054c
+#define SHARP 0x4dd
+
+// known himd-mode product IDs
+#define MZ_NH1_HIMD 0x017f
+#define MZ_NH3D_HIMD 0x0181
+#define MZ_NH900_HIMD 0x0183
+#define MZ_NH700_HIMD 0x0185
+#define MZ_NH600_HIMD 0x0187
+#define LAM_3_HIMD 0x018b
+#define MZ_DH10P_HIMD 0x01ea
+#define MZ_RH10_HIMD 0x021a
+#define MZ_RH910_HIMD 0x021c
+#define CMT_AH10_HIMD 0x022d
+#define DS_HMD1_HIMD 0x023d
+#define MZ_RH1_HIMD 0x0287
+
+// known Sony/Aiwa netmd-mode product IDs
+#define PCLK_XX 0x34
+#define UNKNOWN_A 0x36
+#define MZ_N1 0x75
+#define UNKNOWN_B 0x7c
+#define LAM_1 0x80
+#define MDS_JE780 0x81 // or MDS-JE980
+#define MZ_N505 0x84
+#define MZ_S1 0x85
+#define MZ_N707 0x86
+#define CMT_C7NT 0x8e
+#define PCGA_MDN1 0x97
+#define CMT_L7HD 0xad
+#define MZ_N10 0xc6
+#define MZ_N910 0xc7
+#define MZ_N710 0xc8 // or MZ-NE810/NF810
+#define MZ_N510 0xc9 // or MZ-NF610
+#define MZ_NE410 0xca // or MZ-DN430/NF520
+#define MZ_NE810 0xeb // or MZ-NE910
+#define CMT_M333NT 0xe7 // or CMT-M373NT
+#define LAM_10 0x101
+#define AIWA_AM_NX1 0x113
+#define AIWA_AM_NX9 0x14c
+#define MZ_NH1 0x17e
+#define MZ_NH3D 0x180
+#define MZ_NH900 0x182
+#define MZ_NH700 0x184 // or MZ-NH800
+#define MZ_NH600 0x186 // or MZ-NH600D
+#define MZ_N920 0x188
+#define LAM_3 0x18a
+#define MZ_DH10P 0x1e9
+#define MZ_RH10 0x219
+#define MZ_RH910 0x21b
+#define CMT_AH10_A 0x21d
+#define CMT_AH10_B 0x22c
+#define DS_HMD1 0x23c
+#define MZ_RH1 0x286
+
+// known Sharp netmd-mode product IDs
+#define IM_MT880H 0x7202 // or IM-MT899H
+#define IM_DR400 0x9013 // or IM-DR410
+#define IM_DR80 0x9014 // or IM-DR420/DR580 / Kenwood DMC-S9NET
const char * identify_usb_device(int vid, int pid);
+typedef QList<QMDDevice *> QMDDevicePtrList;
+
class QHiMDDetection : public QObject {
Q_OBJECT
Q_DISABLE_COPY(QHiMDDetection)
protected:
- QList<himd_device *> device_list;
+ QMDDevicePtrList dlist;
+ netmd_device * dev_list;
public:
explicit QHiMDDetection(QObject *parent = 0);
- virtual ~QHiMDDetection() {}
+ virtual ~QHiMDDetection();
+ virtual void clearDeviceList();
+ virtual void cleanup_netmd_list();
+ void rescan_netmd_devices();
+ void scan_for_minidisc_devices();
virtual void scan_for_himd_devices(){}
- himd_device *find_by_path(QString path);
-
-protected slots:
- virtual void himd_busy(QString path);
- virtual void himd_idle(QString path);
+ virtual void remove_himddevice(QString path);
+ void scan_for_netmd_devices();
+ QMDDevice *find_by_path(QString path);
+ QMDDevice *find_by_name(QString name);
signals:
- void himd_found(QString path);
- void himd_removed(QString path);
+ void deviceListChanged(QMDDevicePtrList list);
};
QHiMDDetection * createDetection(QObject * parent = NULL);
#endif // QHIMDDETECTION_H
+
diff --git a/qhimdtransfer/qhimdmainwindow.cpp b/qhimdtransfer/qhimdmainwindow.cpp
index e2675d9..a406ea5 100644
--- a/qhimdtransfer/qhimdmainwindow.cpp
+++ b/qhimdtransfer/qhimdmainwindow.cpp
@@ -1,213 +1,11 @@
#include "qhimdmainwindow.h"
#include "ui_qhimdmainwindow.h"
#include "qhimdaboutdialog.h"
-#include "qhimduploaddialog.h"
#include <QtGui/QMessageBox>
-#include <QtGui/QApplication>
#include <QtCore/QDebug>
-QString QHiMDMainWindow::dumpmp3(const QHiMDTrack & trk, QString file)
-{
- QString errmsg;
- struct himd_mp3stream str;
- struct himderrinfo status;
- unsigned int len;
- const unsigned char * data;
- QFile f(file);
-
- if(!f.open(QIODevice::ReadWrite))
- {
- return tr("Error opening file for MP3 output");
- }
- if(!(errmsg = trk.openMpegStream(&str)).isNull())
- {
- f.remove();
- return tr("Error opening track: ") + errmsg;
- }
- while(himd_mp3stream_read_block(&str, &data, &len, NULL, &status) >= 0)
- {
- if(f.write((const char*)data,len) == -1)
- {
- errmsg = tr("Error writing audio data");
- goto clean;
- }
- uploadDialog->blockTransferred();
- QApplication::processEvents();
- if(uploadDialog->upload_canceled())
- {
- errmsg = tr("upload aborted by the user");
- goto clean;
- }
-
- }
- if(status.status != HIMD_STATUS_AUDIO_EOF)
- errmsg = tr("Error reading audio data: ") + status.statusmsg;
-
-clean:
- f.close();
- himd_mp3stream_close(&str);
- if(!errmsg.isNull())
- f.remove();
- return errmsg;
-}
-
-static inline TagLib::String QStringToTagString(const QString & s)
-{
- return TagLib::String(s.toUtf8().data(), TagLib::String::UTF8);
-}
-
-static void addid3tag(QString title, QString artist, QString album, QString file)
-{
-#ifdef Q_OS_WIN
- TagLib::FileRef f(file.toStdWString().c_str());
-#else
- TagLib::FileRef f(file.toUtf8().data());
-#endif
- TagLib::Tag *t = f.tag();
- t->setTitle(QStringToTagString(title));
- t->setArtist(QStringToTagString(artist));
- t->setAlbum(QStringToTagString(album));
- t->setComment("*** imported from HiMD via QHiMDTransfer ***");
- f.file()->save();
-}
-
-QString QHiMDMainWindow::dumpoma(const QHiMDTrack & track, QString file)
-{
- QString errmsg;
- struct himd_nonmp3stream str;
- struct himderrinfo status;
- unsigned int len;
- const unsigned char * data;
- QFile f(file);
-
- if(!f.open(QIODevice::ReadWrite))
- return tr("Error opening file for ATRAC output");
-
- if(!(errmsg = track.openNonMpegStream(&str)).isNull())
- {
- f.remove();
- return tr("Error opening track: ") + status.statusmsg;
- }
-
- if(f.write(track.makeEA3Header()) == -1)
- {
- errmsg = tr("Error writing header");
- goto clean;
- }
- while(himd_nonmp3stream_read_block(&str, &data, &len, NULL, &status) >= 0)
- {
- if(f.write((const char*)data,len) == -1)
- {
- errmsg = tr("Error writing audio data");
- goto clean;
- }
- uploadDialog->blockTransferred();
- QApplication::processEvents();
- if(uploadDialog->upload_canceled())
- {
- errmsg = QString("upload aborted by the user");
- goto clean;
- }
- }
- if(status.status != HIMD_STATUS_AUDIO_EOF)
- errmsg = QString("Error reading audio data: ") + status.statusmsg;
-
-clean:
- f.close();
- himd_nonmp3stream_close(&str);
-
- if(!errmsg.isNull())
- f.remove();
- return errmsg;
-}
-
-QString QHiMDMainWindow::dumppcm(const QHiMDTrack & track, QString file)
-{
- struct himd_nonmp3stream str;
- struct himderrinfo status;
- unsigned int len, i;
- int left, right;
- int clipcount;
- QString errmsg;
- QFile f(file);
- const unsigned char * data;
- sox_format_t * out;
- sox_sample_t soxbuf [HIMD_MAX_PCMFRAME_SAMPLES * 2];
- sox_signalinfo_t signal_out;
-
- signal_out.channels = 2;
- signal_out.length = 0;
- signal_out.precision = 16;
- signal_out.rate = 44100;
-
- if(!(out = sox_open_write(file.toUtf8(), &signal_out, NULL, NULL, NULL, NULL)))
- return tr("Error opening file for WAV output");
-
- if(!(errmsg = track.openNonMpegStream(&str)).isNull())
- {
- f.remove();
- return tr("Error opening track: ") + status.statusmsg;
- }
-
- while(himd_nonmp3stream_read_block(&str, &data, &len, NULL, &status) >= 0)
- {
-
- for(i = 0; i < len/4; i++) {
-
- left = data[i*4]*256+data[i*4+1];
- right = data[i*4+2]*256+data[i*4+3];
- if (left > 0x8000) left -= 0x10000;
- if (right > 0x8000) right -= 0x10000;
-
- soxbuf[i*2] = SOX_SIGNED_16BIT_TO_SAMPLE(left, clipcount);
- soxbuf[i*2+1] = SOX_SIGNED_16BIT_TO_SAMPLE(right, clipcount);
- (void)clipcount; /* suppess "is unused" warning */
- }
-
- if (sox_write(out, soxbuf, len/2) != len/2)
- {
- errmsg = tr("Error writing audio data");
- goto clean;
- }
- uploadDialog->blockTransferred();
- QApplication::processEvents();
- if(uploadDialog->upload_canceled())
- {
- errmsg = QString("upload aborted by the user");
- goto clean;
- }
- }
- if(status.status != HIMD_STATUS_AUDIO_EOF)
- errmsg = QString("Error reading audio data: ") + status.statusmsg;
-
-clean:
- sox_close(out);
- himd_nonmp3stream_close(&str);
-
- if(!errmsg.isNull())
- f.remove();
- return errmsg;
-}
-
-void QHiMDMainWindow::checkfile(QString UploadDirectory, QString &filename, QString extension)
-{
- QFile f;
- QString newname;
- int i = 2;
-
- f.setFileName(UploadDirectory + "/" + filename + extension);
- while(f.exists())
- {
- newname = filename + " (" + QString::number(i) + ")";
- f.setFileName(UploadDirectory + "/" + newname + extension);
- i++;
- }
- if(!newname.isEmpty())
- filename = newname;
-}
-
void QHiMDMainWindow::set_buttons_enable(bool connect, bool download, bool upload, bool rename, bool del, bool format, bool quit)
{
ui->action_Connect->setEnabled(connect);
@@ -221,13 +19,10 @@ void QHiMDMainWindow::set_buttons_enable(bool connect, bool download, bool uploa
ui->download_button->setEnabled(download);
}
-void QHiMDMainWindow::init_himd_browser()
+void QHiMDMainWindow::init_himd_browser(QAbstractListModel * model)
{
- int i = 0;
+ ui->TrackList->setModel(model);
- ui->TrackList->setModel(&trackmodel);
- for(;i < trackmodel.columnCount(); i++)
- ui->TrackList->resizeColumnToContents(i);
QObject::connect(ui->TrackList->selectionModel(), SIGNAL(selectionChanged (const QItemSelection &, const QItemSelection &)),
this, SLOT(handle_himd_selection_change(const QItemSelection&, const QItemSelection&)));
}
@@ -237,7 +32,6 @@ void QHiMDMainWindow::init_local_browser()
QStringList DownloadFileList;
localmodel.setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
localmodel.setNameFilters(QStringList() << "*.mp3" << "*.wav" << "*.oma");
- localmodel.setSelectableExtensions(trackmodel.downloadableFileExtensions());
localmodel.setNameFilterDisables(false);
localmodel.setReadOnly(false);
localmodel.setRootPath("/");
@@ -259,8 +53,9 @@ void QHiMDMainWindow::save_window_settings()
settings.setValue("geometry", QMainWindow::saveGeometry());
settings.setValue("windowState", QMainWindow::saveState());
- for(;i < trackmodel.columnCount(); i++)
+ for(;i < htmodel.columnCount(); i++)
settings.setValue("himd_browser" + QString::number(i), ui->TrackList->columnWidth(i));
+ /* TODO: save and restore columnWidth for netmd model */
}
void QHiMDMainWindow::read_window_settings()
@@ -270,7 +65,7 @@ void QHiMDMainWindow::read_window_settings()
QMainWindow::restoreGeometry(settings.value("geometry").toByteArray());
QMainWindow::restoreState(settings.value("windowState").toByteArray());
- for(; i < trackmodel.columnCount(); i++)
+ for(; i < htmodel.columnCount(); i++)
{
width = settings.value("himd_browser" + QString::number(i), 0).toInt();
if(width != 0)
@@ -280,105 +75,73 @@ void QHiMDMainWindow::read_window_settings()
bool QHiMDMainWindow::autodetect_init()
{
- int k;
-
- k = QObject::connect(detect, SIGNAL(himd_found(QString)), this, SLOT(himd_found(QString)));
- k += QObject::connect(detect, SIGNAL(himd_removed(QString)), this, SLOT(himd_removed(QString)));
-
- if(!k)
+ if(!QObject::connect(detect, SIGNAL(deviceListChanged(QMDDevicePtrList)), this, SLOT(device_list_changed(QMDDevicePtrList))))
return false;
- QObject::connect(this, SIGNAL(himd_busy(QString)), detect, SLOT(himd_busy(QString)));
- QObject::connect(this, SIGNAL(himd_idle(QString)), detect, SLOT(himd_idle(QString)));
-
- detect->scan_for_himd_devices();
+ detect->scan_for_minidisc_devices();
return true;
}
-void QHiMDMainWindow::open_himd_at(const QString & path)
+void QHiMDMainWindow::setCurrentDevice(QMDDevice *dev)
{
- QMessageBox himdStatus;
- QString error;
+ current_device = dev;
+ QObject::connect(current_device, SIGNAL(closed()), this, SLOT(current_device_closed()));
+}
- error = trackmodel.open(path.toAscii());
+void QHiMDMainWindow::open_device(QMDDevice * dev)
+{
+ QMessageBox mdStatus;
+ QString error;
- if (!error.isNull()) {
- himdStatus.setText(tr("Error opening HiMD data. Make sure you chose the proper root directory of your HiMD-Walkman.\n") + error);
- himdStatus.exec();
+ if(dev->deviceType() == HIMD_DEVICE && dev->path().isEmpty())
+ {
+ mdStatus.setText(tr("Error opening himd device/disc image , no device path given\nPlease use connect button to set the path to the himd device/disc image"));
+ mdStatus.exec();
set_buttons_enable(1,0,0,0,0,0,1);
return;
}
- ui->himdpath->setText(path);
- settings.setValue("lastHiMDDirectory", path);
+ if(current_device)
+ current_device_closed();
- himd_device * dev = detect->find_by_path(path);
- if(dev)
- ui->statusBar->showMessage(dev->recorder_name);
+ setCurrentDevice(dev);
+ if(current_device->deviceType() == NETMD_DEVICE) {
+ error = ntmodel.open(current_device);
+ init_himd_browser(&ntmodel);
+ localmodel.setSelectableExtensions(ntmodel.downloadableFileExtensions());
+ }
+ else if(current_device->deviceType() == HIMD_DEVICE) {
+ error = htmodel.open(current_device);
+ init_himd_browser(&htmodel);
+ localmodel.setSelectableExtensions(htmodel.downloadableFileExtensions());
+ }
else
- ui->statusBar->clearMessage();
+ {
+ mdStatus.setText(tr("Error opening minidisc device, unknown/invalid device type given\n"));
+ mdStatus.exec();
+ set_buttons_enable(1,0,0,0,0,0,1);
+ return;
+ }
+ if (!error.isNull()) {
+ mdStatus.setText(tr("Error opening minidisc device:\n") + error);
+ mdStatus.exec();
+ set_buttons_enable(1,0,0,0,0,0,1);
+ return;
+ }
+
+ ui->DiscTitle->setText(current_device->discTitle());
set_buttons_enable(1,0,0,1,1,1,1);
}
void QHiMDMainWindow::upload_to(const QString & UploadDirectory)
{
- emit himd_busy(ui->himdpath->text());
+ QMDTrackIndexList tlist;
- QHiMDTrackList tracks = trackmodel.tracks(ui->TrackList->selectionModel()->selectedRows(0));
+ foreach(QModelIndex index, ui->TrackList->selectionModel()->selectedRows(0))
+ tlist.append(index.row());
- int allblocks = 0;
- for(int i = 0;i < tracks.length(); i++)
- allblocks += tracks[i].blockcount();
-
- uploadDialog->init(tracks.length(), allblocks);
-
- for(int i = 0;i < tracks.length(); i++)
- {
- QString filename, errmsg;
- QString title = tracks[i].title();
- if(title.isNull())
- filename = tr("Track %1").arg(tracks[i].tracknum()+1);
- else
- filename = tracks[i].artist() + " - " + title;
-
- uploadDialog->starttrack(tracks[i], filename);
- if (!tracks[i].copyprotected())
- {
- QString codec = tracks[i].codecname();
- if (codec == "MPEG")
- {
- checkfile(UploadDirectory, filename, ".mp3");
- errmsg = dumpmp3 (tracks[i], UploadDirectory + "/" + filename + ".mp3");
- if(errmsg.isNull())
- addid3tag (tracks[i].title(),tracks[i].artist(),tracks[i].album(), UploadDirectory+ "/" +filename + ".mp3");
- }
- else if (codec == "LPCM")
- {
- checkfile(UploadDirectory, filename, ".wav");
- errmsg = dumppcm (tracks[i], UploadDirectory + "/" + filename + ".wav");
- }
- else if (codec == "AT3+" || codec == "AT3 ")
- {
- checkfile(UploadDirectory, filename, ".oma");
- errmsg = dumpoma (tracks[i], UploadDirectory + "/" + filename + ".oma");
- }
- }
- else
- errmsg = tr("upload disabled because of DRM encryption");
-
- if(errmsg.isNull())
- uploadDialog->trackSucceeded();
- else
- uploadDialog->trackFailed(errmsg);
-
- QApplication::processEvents();
- if(uploadDialog->upload_canceled())
- break;
- }
- uploadDialog->finished();
-
- emit himd_idle(ui->himdpath->text());
+ current_device->batchUpload(tlist, UploadDirectory);
}
QHiMDMainWindow::QHiMDMainWindow(QWidget *parent)
@@ -386,22 +149,25 @@ QHiMDMainWindow::QHiMDMainWindow(QWidget *parent)
{
aboutDialog = new QHiMDAboutDialog;
formatDialog = new QHiMDFormatDialog;
- uploadDialog = new QHiMDUploadDialog;
+ current_device = NULL;
detect = createDetection(this);
ui->setupUi(this);
ui->updir->setText(settings.value("lastUploadDirectory",
QDir::homePath()).toString());
set_buttons_enable(1,0,0,0,0,0,1);
- init_himd_browser();
+ init_himd_browser(&htmodel); // use himd tracks model as default
init_local_browser();
read_window_settings();
- ui->himd_devices->hide();
+ ui->himdpath->hide();
if(!autodetect_init())
ui->statusBar->showMessage(" autodetection disabled", 10000);
}
QHiMDMainWindow::~QHiMDMainWindow()
{
+ if(current_device && current_device->isOpen())
+ current_device->close();
+
save_window_settings();
delete ui;
}
@@ -454,8 +220,9 @@ void QHiMDMainWindow::on_action_Format_triggered()
void QHiMDMainWindow::on_action_Connect_triggered()
{
int index;
+ QHiMDDevice *dev;
QString HiMDDirectory;
- HiMDDirectory = settings.value("lastHiMDDirectory", QDir::rootPath()).toString();
+ HiMDDirectory = settings.value("lastImageDirectory", QDir::rootPath()).toString();
HiMDDirectory = QFileDialog::getExistingDirectory(this,
tr("Select directory of HiMD Medium"),
HiMDDirectory,
@@ -464,21 +231,13 @@ void QHiMDMainWindow::on_action_Connect_triggered()
if(HiMDDirectory.isEmpty())
return;
- index = ui->himd_devices->findText(HiMDDirectory);
- if(index == -1)
- {
- ui->himd_devices->addItem(HiMDDirectory);
- index = ui->himd_devices->findText(HiMDDirectory);
- }
- ui->himd_devices->setCurrentIndex(index);
+ index = ui->himd_devices->findText("disc image");
+ ui->himd_devices->setCurrentIndex(index); // index of disk image device
+ dev = (QHiMDDevice *)ui->himd_devices->itemData(index).value<void *>();
+ dev->setPath(HiMDDirectory);
+ ui->himd_devices->setItemText(index, QString((dev->name() + " at " + dev->path() )));
- if(ui->himd_devices->isHidden())
- {
- ui->himd_devices->show();
- ui->himdpath->hide();
- }
-
- open_himd_at(HiMDDirectory);
+ open_device(dev);
}
void QHiMDMainWindow::on_upload_button_clicked()
@@ -506,67 +265,60 @@ void QHiMDMainWindow::handle_local_selection_change(const QItemSelection&, const
}
if(localmodel.fileInfo(index).isFile())
- download_possible = trackmodel.is_open();
+ download_possible = current_device->isOpen();
ui->action_Download->setEnabled(download_possible);
ui->download_button->setEnabled(download_possible);
}
-void QHiMDMainWindow::himd_found(QString HiMDPath)
+void QHiMDMainWindow::device_list_changed(QMDDevicePtrList dplist)
{
- int index;
+ QString device;
+ QMDDevice * dev;
- if(HiMDPath.isEmpty())
- return;
+ /* close current device if it is removed from device list */
+ if(current_device != NULL && current_device->isOpen() && !dplist.contains(current_device)) {
+ current_device_closed();
+ }
- index = ui->himd_devices->findText(HiMDPath);
- if(index == -1)
- ui->himd_devices->addItem(HiMDPath);
+ ui->himd_devices->clear();
- if(ui->himd_devices->isHidden())
+ foreach(dev, dplist)
{
- ui->himd_devices->show();
- ui->himdpath->hide();
+ device = QString(dev->deviceType() == NETMD_DEVICE ? dev->name() : dev->name() + " at " + dev->path() );
+ ui->himd_devices->addItem(device, qVariantFromValue((void *)dev));
}
- if(!trackmodel.is_open())
- {
- index = ui->himd_devices->findText(HiMDPath);
- ui->himd_devices->setCurrentIndex(index);
- open_himd_at(HiMDPath);
+ if(current_device)
+ ui->himd_devices->setCurrentIndex(dplist.indexOf(current_device));
+ else {
+ if(dplist.count() > 1) {
+ ui->himd_devices->setCurrentIndex(1);
+ open_device(dplist.at(1)); // open first autodetected device
+ }
}
-
}
-
-void QHiMDMainWindow::himd_removed(QString HiMDPath)
+void QHiMDMainWindow::on_himd_devices_activated(QString device)
{
- int index;
+ QMDDevice * dev;
+ int index = ui->himd_devices->findText(device);
- if(HiMDPath.isEmpty())
- return;
- if (ui->himdpath->text() == HiMDPath)
- {
- ui->himdpath->setText(tr("(disconnected)"));
- ui->statusBar->clearMessage();
- trackmodel.close();
- }
-
- index = ui->himd_devices->findText(HiMDPath);
- if(index != -1)
- {
- ui->himd_devices->removeItem(index);
- }
+ dev = (QMDDevice *)ui->himd_devices->itemData(index).value<void *>();
- if(ui->himd_devices->count() == 0)
- {
- ui->himd_devices->hide();
- ui->himdpath->show();
- }
+ open_device(dev);
}
-void QHiMDMainWindow::on_himd_devices_activated(QString device)
+void QHiMDMainWindow::current_device_closed()
{
- open_himd_at(device);
+ QObject::disconnect(current_device, SIGNAL(closed()), this, SLOT(current_device_closed()));
+
+ if(current_device->deviceType() == NETMD_DEVICE)
+ ntmodel.close();
+
+ else if(current_device->deviceType() == HIMD_DEVICE)
+ htmodel.close();
+
+ current_device = NULL;
}
void QHiMDMainWindow::on_download_button_clicked()
diff --git a/qhimdtransfer/qhimdmainwindow.h b/qhimdtransfer/qhimdmainwindow.h
index 85be8ae..c08d465 100644
--- a/qhimdtransfer/qhimdmainwindow.h
+++ b/qhimdtransfer/qhimdmainwindow.h
@@ -6,14 +6,9 @@
#include <QtCore/QSettings>
#include "qhimdaboutdialog.h"
#include "qhimdformatdialog.h"
-#include "qhimduploaddialog.h"
#include "qhimddetection.h"
-#include "qhimdmodel.h"
-#include "../libhimd/himd.h"
-#include <tlist.h>
-#include <fileref.h>
-#include <tfile.h>
-#include <tag.h>
+#include "qmdmodel.h"
+#include "qmddevice.h"
extern "C" {
#include <sox.h>
@@ -36,22 +31,20 @@ private:
Ui::QHiMDMainWindowClass *ui;
QHiMDAboutDialog * aboutDialog;
QHiMDFormatDialog * formatDialog;
- QHiMDUploadDialog * uploadDialog;
QHiMDDetection * detect;
- QHiMDTracksModel trackmodel;
+ QNetMDTracksModel ntmodel;
+ QHiMDTracksModel htmodel;
QHiMDFileSystemModel localmodel;
QSettings settings;
- QString dumpmp3(const QHiMDTrack & trk, QString file);
- QString dumpoma(const QHiMDTrack & trk, QString file);
- QString dumppcm(const QHiMDTrack & trk, QString file);
- void checkfile(QString UploadDirectory, QString &filename, QString extension);
+ QMDDevice * current_device;
void set_buttons_enable(bool connect, bool download, bool upload, bool rename, bool del, bool format, bool quit);
- void init_himd_browser();
+ void init_himd_browser(QAbstractListModel *model);
void init_local_browser();
void save_window_settings();
void read_window_settings();
bool autodetect_init();
- void open_himd_at(const QString & path);
+ void setCurrentDevice(QMDDevice * dev);
+ void open_device(QMDDevice * dev);
void upload_to(const QString & path);
private slots:
@@ -64,14 +57,11 @@ private slots:
void on_upload_button_clicked();
void handle_himd_selection_change(const QItemSelection&, const QItemSelection&);
void handle_local_selection_change(const QItemSelection&, const QItemSelection&);
- void himd_found(QString path);
- void himd_removed(QString path);
+ void device_list_changed(QMDDevicePtrList dplist);
void on_himd_devices_activated(QString device);
+ void current_device_closed();
void on_download_button_clicked();
-signals:
- void himd_busy(QString path);
- void himd_idle(QString path);
};
#endif // QHIMDMAINWINDOW_H
diff --git a/qhimdtransfer/qhimdmainwindow.ui b/qhimdtransfer/qhimdmainwindow.ui
index b55845f..f394d92 100644
--- a/qhimdtransfer/qhimdmainwindow.ui
+++ b/qhimdtransfer/qhimdmainwindow.ui
@@ -35,7 +35,7 @@
</font>
</property>
<property name="text">
- <string>HiMD path</string>
+ <string><html><head/><body><p>minidisc device (path):</p></body></html></string>
</property>
</widget>
</item>
@@ -52,6 +52,20 @@
</layout>
</item>
<item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="disc_title_text">
+ <property name="text">
+ <string><html><head/><body><p><span style=" font-weight:600;">disc title:</span></p></body></html></string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="DiscTitle"/>
+ </item>
+ </layout>
+ </item>
+ <item>
<widget class="QTreeView" name="TrackList">
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
@@ -174,7 +188,7 @@
<x>0</x>
<y>0</y>
<width>784</width>
- <height>18</height>
+ <height>20</height>
</rect>
</property>
<widget class="QMenu" name="menu_Action">
diff --git a/qhimdtransfer/qhimdmodel.cpp b/qhimdtransfer/qhimdmodel.cpp
deleted file mode 100644
index ac4bde5..0000000
--- a/qhimdtransfer/qhimdmodel.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-#include <QtGui/QFont>
-#include <QtGui/QFontMetrics>
-#include "qhimdmodel.h"
-
-static QString get_himd_str(struct himd * himd, int idx)
-{
- QString outstr;
- char * str;
- if(!idx)
- return QString();
- str = himd_get_string_utf8(himd, idx, NULL, NULL);
- if(!str)
- return QString();
-
- outstr = QString::fromUtf8(str);
- himd_free(str);
- return outstr;
-}
-
-QHiMDTrack::QHiMDTrack(struct himd * himd, unsigned int trackindex) : himd(himd), trknum(trackindex)
-{
- trackslot = himd_get_trackslot(himd, trackindex, NULL);
- if(trackslot != 0)
- if(himd_get_track_info(himd, trackslot, &ti, NULL) < 0)
- trackslot = -1;
-}
-
-unsigned int QHiMDTrack::tracknum() const
-{
- return trknum;
-}
-
-QString QHiMDTrack::title() const
-{
- if(trackslot != 0)
- return get_himd_str(himd, ti.title);
- else
- return QString();
-}
-
-QString QHiMDTrack::artist() const
-{
- if(trackslot != 0)
- return get_himd_str(himd, ti.artist);
- else
- return QString();
-}
-
-QString QHiMDTrack::album() const
-{
- if(trackslot != 0)
- return get_himd_str(himd, ti.album);
- else
- return QString();
-}
-
-QString QHiMDTrack::codecname() const
-{
- if(trackslot != 0)
- return himd_get_codec_name(&ti);
- else
- return QString();
-}
-
-QTime QHiMDTrack::duration() const
-{
- QTime t;
- if(trackslot != 0)
- return t.addSecs(ti.seconds);
- else
- return t;
-}
-
-bool QHiMDTrack::copyprotected() const
-{
- if(trackslot != 0)
- return !himd_track_uploadable(himd, &ti);
- return true;
-}
-
-int QHiMDTrack::blockcount() const
-{
- if(trackslot != 0)
- return himd_track_blocks(himd, &ti, NULL);
- else
- return 0;
-}
-
-QString QHiMDTrack::openMpegStream(struct himd_mp3stream * str) const
-{
- struct himderrinfo status;
- if(himd_mp3stream_open(himd, trackslot, str, &status) < 0)
- return QString::fromUtf8(status.statusmsg);
- return QString();
-}
-
-QString QHiMDTrack::openNonMpegStream(struct himd_nonmp3stream * str) const
-{
- struct himderrinfo status;
- if(himd_nonmp3stream_open(himd, trackslot, str, &status) < 0)
- return QString::fromUtf8(status.statusmsg);
- return QString();
-}
-
-QByteArray QHiMDTrack::makeEA3Header() const
-{
- char header[EA3_FORMAT_HEADER_SIZE];
- make_ea3_format_header(header, &ti.codec_info);
- return QByteArray(header,EA3_FORMAT_HEADER_SIZE);
-}
-
-enum columnum {
- ColId, ColTitle, ColArtist, ColAlbum, ColLength, ColCodec, ColUploadable,
- LAST_columnnum = ColUploadable
-};
-
-QVariant QHiMDTracksModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if(orientation != Qt::Horizontal)
- return QVariant();
-
- if(role == Qt::SizeHintRole)
- {
- static QFont f;
- static QFontMetrics met(f);
- switch((columnum)section)
- {
- case ColId:
- return QSize(met.width("9999")+5, 0);
- case ColTitle:
- case ColArtist:
- case ColAlbum:
- return QSize(25*met.averageCharWidth(), 0);
- case ColLength:
- return QSize(met.width("9:99:99"), 0);
- case ColCodec:
- case ColUploadable:
- /* Really use the header for the metric in these columns,
- contents will be shorter */
- return QAbstractListModel::headerData(section,orientation,role);
- }
- }
-
- if(role == Qt::DisplayRole)
- {
- switch((columnum)section)
- {
- case ColId:
- return tr("Nr.");
- case ColTitle:
- return tr("Title");
- case ColArtist:
- return tr("Artist");
- case ColAlbum:
- return tr("Album");
- case ColLength:
- return tr("Length");
- case ColCodec:
- return tr("Format");
- case ColUploadable:
- return tr("Uploadable");
- }
- }
- return QVariant();
-}
-
-QVariant QHiMDTracksModel::data(const QModelIndex & index, int role) const
-{
- if(role == Qt::TextAlignmentRole &&
- (index.column() == ColId || index.column() == ColLength))
- return Qt::AlignRight;
-
- if(index.row() >= rowCount())
- return QVariant();
-
- QHiMDTrack track(himd, index.row());
-
- if(role == Qt::CheckStateRole && index.column() == ColUploadable)
- return track.copyprotected() ? Qt::Unchecked : Qt::Checked;
-
- if(role == Qt::DisplayRole)
- {
- switch((columnum)index.column())
- {
- case ColId:
- return index.row() + 1;
- case ColTitle:
- return track.title();
- case ColArtist:
- return track.artist();
- case ColAlbum:
- return track.album();
- case ColLength:
- {
- QTime t = track.duration();
- if(t < QTime(1,0,0))
- return t.toString("m:ss");
- else
- return t.toString("h:mm:ss");
- }
- case ColCodec:
- return track.codecname();
- case ColUploadable:
- return QVariant(); /* Displayed by checkbox */
- }
- }
- return QVariant();
-}
-
-int QHiMDTracksModel::rowCount(const QModelIndex &) const
-{
- if(himd)
- return himd_track_count(himd);
- else
- return 0;
-}
-
-int QHiMDTracksModel::columnCount(const QModelIndex &) const
-{
- return LAST_columnnum+1;
-}
-
-QString QHiMDTracksModel::open(const QString & path)
-{
- struct himd * newhimd;
- struct himderrinfo status;
-
- newhimd = new struct himd;
- if(himd_open(newhimd,path.toUtf8(), &status) < 0)
- {
- delete newhimd;
- return QString::fromUtf8(status.statusmsg);
- }
- close();
- himd = newhimd;
- reset(); /* inform views that the model contents changed */
- return QString();
-}
-
-bool QHiMDTracksModel::is_open()
-{
- return himd != NULL;
-}
-
-void QHiMDTracksModel::close()
-{
- struct himd * oldhimd;
- if(!himd)
- return;
- oldhimd = himd;
- himd = NULL;
- reset(); /* inform views that the model contents changed */
- himd_close(oldhimd);
- delete oldhimd;
-}
-
-QHiMDTrack QHiMDTracksModel::track(int trknum) const
-{
- return QHiMDTrack(himd, trknum);
-}
-
-QHiMDTrackList QHiMDTracksModel::tracks(const QModelIndexList & modelindices) const
-{
- QHiMDTrackList tracks;
- QModelIndex index;
- foreach(index, modelindices)
- tracks.append(track(index.row()));
- return tracks;
-}
-
-QStringList QHiMDTracksModel::downloadableFileExtensions() const
-{
- return (QStringList() << "mp3");
-}
-
-/* QFileSystemModel stuff */
-
-Qt::ItemFlags QHiMDFileSystemModel::flags(const QModelIndex &index) const
-{
- if(!isDir(index) && !selectableExtensions.contains((fileInfo(index).suffix()), Qt::CaseInsensitive))
- return Qt::NoItemFlags; //not selectable, not enabled (grayed out in the browser)
-
- return QFileSystemModel::flags(index);
-}
-
-void QHiMDFileSystemModel::setSelectableExtensions(QStringList extensions)
-{
- selectableExtensions = extensions;
-}
diff --git a/qhimdtransfer/qhimdmodel.h b/qhimdtransfer/qhimdmodel.h
deleted file mode 100644
index 6ccc2f8..0000000
--- a/qhimdtransfer/qhimdmodel.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef QHIMDMODEL_H
-#define QHIMDMODEL_H
-
-#include <QtCore/QAbstractListModel>
-#include <QtCore/QTime>
-#include <QtCore/QList>
-#include <QtCore/QStringList>
-#include <QtGui/QFileSystemModel>
-#include "himd.h"
-
-#include "sony_oma.h"
-
-class QHiMDTracksModel;
-
-class QHiMDTrack {
- struct himd * himd;
- unsigned int trknum;
- unsigned int trackslot;
- struct trackinfo ti;
-public:
- QHiMDTrack(struct himd * himd, unsigned int trackindex);
- unsigned int tracknum() const;
- QString title() const;
- QString artist() const;
- QString album() const;
- QString codecname() const;
- QTime duration() const;
- bool copyprotected() const;
- int blockcount() const;
-
- QString openMpegStream(struct himd_mp3stream * str) const;
- QString openNonMpegStream(struct himd_nonmp3stream * str) const;
- QByteArray makeEA3Header() const;
-};
-
-typedef QList<QHiMDTrack> QHiMDTrackList;
-
-class QHiMDTracksModel : public QAbstractListModel {
- Q_OBJECT
-
- struct himd *himd;
-public:
- QHiMDTracksModel() : himd(NULL) {}
- /* QAbstractListModel stuff */
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
- virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
- virtual int rowCount(const QModelIndex & parent = QModelIndex() ) const;
- virtual int columnCount(const QModelIndex & parent = QModelIndex() ) const;
- /* HiMD containter stuff */
- QString open(const QString & path); /* returns null if OK, error message otherwise */
- bool is_open();
- void close();
- QHiMDTrack track(int trackidx) const;
- QHiMDTrackList tracks(const QModelIndexList & indices) const;
- QStringList downloadableFileExtensions() const;
-};
-
-class QHiMDFileSystemModel : public QFileSystemModel {
- Q_OBJECT
-
- QStringList selectableExtensions;
-public:
- virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- void setSelectableExtensions(QStringList extensions);
-};
-
-
-#endif
diff --git a/qhimdtransfer/qhimdtransfer.pro b/qhimdtransfer/qhimdtransfer.pro
index 236b5e9..ad6c396 100644
--- a/qhimdtransfer/qhimdtransfer.pro
+++ b/qhimdtransfer/qhimdtransfer.pro
@@ -49,8 +49,10 @@ HEADERS += qhimdaboutdialog.h \
qhimdformatdialog.h \
qhimduploaddialog.h \
qhimdmainwindow.h \
- qhimdmodel.h \
- qhimddetection.h
+ qhimddetection.h \
+ qmdtrack.h \
+ qmdmodel.h \
+ qmddevice.h
FORMS += qhimdaboutdialog.ui \
qhimdformatdialog.ui \
qhimduploaddialog.ui \
@@ -60,8 +62,10 @@ SOURCES += main.cpp \
qhimdformatdialog.cpp \
qhimduploaddialog.cpp \
qhimdmainwindow.cpp \
- qhimdmodel.cpp \
- qhimddetection.cpp
+ qhimddetection.cpp \
+ qmdtrack.cpp \
+ qmdmodel.cpp \
+ qmddevice.cpp
win32:SOURCES += qhimdwindetection.cpp
else:SOURCES += qhimddummydetection.cpp
RESOURCES += icons.qrc
@@ -77,6 +81,7 @@ mac:ICON = qhimdtransfer.icns
win32:TARGET = QHiMDTransfer
mac:TARGET = QHiMDTransfer
include(../libhimd/use_libhimd.pri)
+include(../libnetmd/use_libnetmd.prl)
# Installing stuff
translations.files = $$bracketAll(LANGUAGES, qhimdtransfer_,.qm)
diff --git a/qhimdtransfer/qhimduploaddialog.cpp b/qhimdtransfer/qhimduploaddialog.cpp
index 4df44ca..13f327e 100644
--- a/qhimdtransfer/qhimduploaddialog.cpp
+++ b/qhimdtransfer/qhimduploaddialog.cpp
@@ -42,7 +42,7 @@ void QHiMDUploadDialog::finished()
return;
}
-void QHiMDUploadDialog::starttrack(const QHiMDTrack & trk, const QString & title)
+void QHiMDUploadDialog::starttrack(const QMDTrack &trk, const QString & title)
{
tracknum = trk.tracknum() + 1;
m_ui->curtrack_label->setText(tr("current track: %1 - %2").arg(tracknum).arg(title));
@@ -64,6 +64,8 @@ void QHiMDUploadDialog::init(int trackcount, int totalblocks)
allfinished = 0;
m_ui->AllPBar->setRange(0, allblocks);
m_ui->AllPBar->reset();
+ // reset "canceled" variable, else if last upload was canceled next upload will be canceled automatically
+ canceled = false;
scount = fcount = 0;
m_ui->success_text->setText("");
diff --git a/qhimdtransfer/qhimduploaddialog.h b/qhimdtransfer/qhimduploaddialog.h
index 86bcd5c..ec7a4d2 100644
--- a/qhimdtransfer/qhimduploaddialog.h
+++ b/qhimdtransfer/qhimduploaddialog.h
@@ -2,7 +2,7 @@
#define QHIMDUPLOADDIALOG_H
#include <QtGui/QDialog>
-#include "qhimdmodel.h"
+#include "qmdtrack.h"
namespace Ui {
class QHiMDUploadDialog;
@@ -17,7 +17,7 @@ public:
bool upload_canceled() { return canceled; }
void init(int trackcount, int totalblocks);
- void starttrack(const QHiMDTrack & trk, const QString & title);
+ void starttrack(const QMDTrack & trk, const QString & title);
void blockTransferred();
void trackFailed(const QString & errmsg);
void trackSucceeded();
diff --git a/qhimdtransfer/qhimdwindetection.cpp b/qhimdtransfer/qhimdwindetection.cpp
index 1dc437a..db723ef 100644
--- a/qhimdtransfer/qhimdwindetection.cpp
+++ b/qhimdtransfer/qhimdwindetection.cpp
@@ -3,8 +3,6 @@
#include <QtGui/QWidget>
#include "qhimddetection.h"
-#define WINVER 0x0500
-
#include <windows.h>
#include <dbt.h>
#include <setupapi.h>
@@ -12,10 +10,10 @@
#include <ddk/ntddstor.h> // needed for handling storage devices
#include <ddk/cfgmgr32.h> // needed for CM_Get_Child function
-struct win_himd_device : himd_device {
- HANDLE devhandle;
- HDEVNOTIFY himdChange;
- };
+struct win_os_data : os_data {
+ HANDLE devhandle;
+ HDEVNOTIFY himdChange;
+ };
static const GUID my_GUID_IO_MEDIA_ARRIVAL =
{0xd07433c0, 0xa98e, 0x11d2, {0x91, 0x7a, 0x00, 0xa0, 0xc9, 0x06, 0x8f, 0xf3} };
@@ -23,6 +21,9 @@ static const GUID my_GUID_IO_MEDIA_ARRIVAL =
static const GUID my_GUID_IO_MEDIA_REMOVAL =
{0xd07433c1, 0xa98e, 0x11d2, {0x91, 0x7a, 0x00, 0xa0, 0xc9, 0x06, 0x8f, 0xf3} };
+static const GUID my_GUID_DEVINTERFACE_USB_DEVICE =
+ {0xa5dcbf10, 0x6530, 0x11d2, {0x90, 0x1f, 0x00, 0xc0,0x4f, 0xb9, 0x51, 0xed} };
+
static const int my_DBT_CUSTOMEVENT = 0x8006;
@@ -37,18 +38,20 @@ public:
void scan_for_himd_devices();
QHiMDWinDetection(QObject * parent = NULL);
~QHiMDWinDetection();
- win_himd_device *find_by_path(QString path);
+ //win_himd_device *find_by_path(QString path);
private:
HDEVNOTIFY hDevNotify;
- win_himd_device *find_by_handle(HANDLE devhandle);
- win_himd_device *win_dev_at(int idx);
+ HDEVNOTIFY listen_usbdev;
+ QMDDevice *find_by_handle(HANDLE devhandle);
void add_himddevice(QString path, QString name);
- void remove_himddevice(QString path);
+ virtual void remove_himddevice(QString path);
void add_himd(HANDLE devhandle);
void remove_himd(HANDLE devhandle);
HDEVNOTIFY register_mediaChange(HANDLE devhandle);
void unregister_mediaChange(HDEVNOTIFY himd_change);
+ HDEVNOTIFY register_usbDeviceNotification();
+ void unregister_usbDeviceNotification();
bool winEvent(MSG * msg, long * result);
};
@@ -58,17 +61,21 @@ QHiMDDetection * createDetection(QObject * parent)
return new QHiMDWinDetection(parent);
}
-QHiMDWinDetection::QHiMDWinDetection(QObject * parent)
+QHiMDWinDetection::QHiMDWinDetection(QObject * parent)
: QHiMDDetection(parent), QWidget(0)
{
// ask for Window ID to have Qt create the window.
(void)winId();
+ // register for usb device notifications
+ if((listen_usbdev = register_usbDeviceNotification()) == NULL)
+ qDebug() << "cannot register usb device notifications" << endl;
}
QHiMDWinDetection::~QHiMDWinDetection()
{
- while (!device_list.isEmpty())
- remove_himddevice(device_list.at(0)->path);
+ unregister_usbDeviceNotification();
+ clearDeviceList();
+ cleanup_netmd_list();
}
void QHiMDWinDetection::scan_for_himd_devices()
@@ -96,21 +103,19 @@ void QHiMDWinDetection::scan_for_himd_devices()
return;
}
-win_himd_device *QHiMDWinDetection::win_dev_at(int idx)
-{
- return static_cast<win_himd_device*>(device_list.at(idx));
-}
-
-win_himd_device *QHiMDWinDetection::find_by_path(QString path)
+QMDDevice *QHiMDWinDetection::find_by_handle(HANDLE devhandle)
{
- return static_cast<win_himd_device*>(QHiMDDetection::find_by_path(path));
-}
+ QMDDevice *mddev;
+ win_os_data *osd;
-win_himd_device *QHiMDWinDetection::find_by_handle(HANDLE devhandle)
-{
- for (int i = 0; i < device_list.size(); i++)
- if(win_dev_at(i)->devhandle == devhandle)
- return win_dev_at(i);
+ foreach(mddev, dlist)
+ {
+ if(mddev->deviceType() != HIMD_DEVICE)
+ continue;
+ osd = static_cast<win_os_data *>(mddev->pdata());
+ if(osd->devhandle == devhandle)
+ return mddev;
+ }
return NULL;
}
@@ -178,6 +183,7 @@ static bool identified(QString devpath, QString & name)
int vid = devpath.mid(devpath.indexOf("VID") + 4, 4).toInt(NULL,16);
int pid = devpath.mid(devpath.indexOf("PID") + 4, 4).toInt(NULL,16);
const char * devname = identify_usb_device(vid, pid);
+
if (devname)
{
name = devname;
@@ -191,7 +197,8 @@ void QHiMDWinDetection::add_himddevice(QString path, QString name)
if (find_by_path(path))
return;
- win_himd_device * new_device = new win_himd_device;
+ QHiMDDevice * new_device = new QHiMDDevice();
+ struct win_os_data pdata;
int k;
char drv[] = "\\\\.\\X:";
QByteArray device = "\\\\.\\PHYSICALDRIVE";
@@ -213,80 +220,93 @@ void QHiMDWinDetection::add_himddevice(QString path, QString name)
if(k != 0)
device.append(QString::number(sdn.DeviceNumber));
- new_device->devhandle = CreateFileA(device.data(), NULL , FILE_SHARE_READ, NULL,
+
+ pdata.devhandle = CreateFileA(device.data(), NULL , FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
- if(new_device->devhandle == INVALID_HANDLE_VALUE)
+ if(pdata.devhandle == INVALID_HANDLE_VALUE)
return;
- new_device->himdChange = register_mediaChange(new_device->devhandle);
- new_device->is_busy = false;
- new_device->path = path;
- new_device->recorder_name = name;
+ pdata.himdChange = register_mediaChange(pdata.devhandle);
+ new_device->setBusy(false);
+ new_device->setPath(path);
+ new_device->setName(name);
file[0] = path.at(0).toAscii();
if(OpenFile(file, &OFfile, OF_EXIST) != HFILE_ERROR)
- {
- new_device->md_inserted = true;
- emit himd_found(new_device->path);
- qDebug() << "himd device at " + new_device->path + " added (" + new_device->recorder_name + ")";
- }
+ pdata.md_inserted = true;
else
- {
- qDebug() << "himd device at " + new_device->path + " added (" + new_device->recorder_name + ")" + " ; without MD";
- new_device->md_inserted = false;
- }
+ pdata.md_inserted = false;
- device_list.append(new_device);
+ new_device->setPlatformData(pdata);
+ dlist.append(new_device);
+ emit deviceListChanged(dlist);
return;
-
}
void QHiMDWinDetection::remove_himddevice(QString path)
{
- win_himd_device * dev = find_by_path(path);
+ int index = -1;
+ win_os_data * data;
+ QHiMDDevice * dev = static_cast<QHiMDDevice *>(find_by_path(path));
+
if (!dev)
return;
- unregister_mediaChange(dev->himdChange);
+ index = dlist.indexOf(dev);
- if (dev->devhandle != NULL)
- CloseHandle(dev->devhandle);
+ if(dev->isOpen())
+ dev->close();
- emit himd_removed(dev->path);
+ if(dev->name() != "disc image") {
+ data = static_cast<win_os_data *>(dev->pdata());
+ if(data->himdChange != NULL)
+ unregister_mediaChange(data->himdChange);
- qDebug() << "himd device at " + dev->path + " removed (" + dev->recorder_name + ")";
+ if(data->devhandle != NULL)
+ CloseHandle(data->devhandle);
+ }
- device_list.removeAll(dev);
delete dev;
+ dev = NULL;
+
+ dlist.removeAt(index);
+
+ emit deviceListChanged(dlist);
}
void QHiMDWinDetection::add_himd(HANDLE devhandle)
{
- win_himd_device * dev = find_by_handle(devhandle);
+ win_os_data * data;
+ QMDDevice * dev = find_by_handle(devhandle);
if (!dev)
return;
- if(!dev->md_inserted)
+ data = static_cast<win_os_data *>(dev->pdata());
+
+ if(!data->md_inserted)
{
- dev->md_inserted = true;
- emit himd_found(dev->path);
- qDebug() << "himd device at " + dev->path + " : md inserted";
+ data->md_inserted = true;
}
return;
}
void QHiMDWinDetection::remove_himd(HANDLE devhandle)
{
- win_himd_device * dev = find_by_handle(devhandle);
+ win_os_data * data;
+ QMDDevice * dev = find_by_handle(devhandle);
+
if (!dev)
return;
- if(dev->md_inserted)
+ data = static_cast<win_os_data *>(dev->pdata());
+
+ if(dev->isOpen())
+ dev->close();
+
+ if(data->md_inserted)
{
- dev->md_inserted = false;
- emit himd_removed(dev->path);
- qDebug() << "himd device at " + dev->path + " : md removed";
+ data->md_inserted = false;
}
return;
}
@@ -311,9 +331,30 @@ void QHiMDWinDetection::unregister_mediaChange(HDEVNOTIFY himd_change)
UnregisterDeviceNotification(himd_change);
}
+HDEVNOTIFY QHiMDWinDetection::register_usbDeviceNotification()
+{
+ DEV_BROADCAST_DEVICEINTERFACE filter;
+
+ ZeroMemory(&filter, sizeof(filter));
+ filter.dbcc_size = sizeof(filter);
+ filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+ filter.dbcc_reserved = 0;
+ filter.dbcc_classguid = my_GUID_DEVINTERFACE_USB_DEVICE;
+
+ return RegisterDeviceNotification( this->winId(), &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
+
+}
+
+void QHiMDWinDetection::unregister_usbDeviceNotification()
+{
+ if(listen_usbdev != NULL)
+ UnregisterDeviceNotification(listen_usbdev);
+}
+
bool QHiMDWinDetection::winEvent(MSG * msg, long * result)
{
QString name, devID, path ;
+
if(msg->message == WM_DEVICECHANGE)
{
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR )msg->lParam;
@@ -335,6 +376,16 @@ bool QHiMDWinDetection::winEvent(MSG * msg, long * result)
}
}
}
+ else if(pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
+ {
+ PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
+ devID = QString::fromWCharArray(pDevInf->dbcc_name).toUpper();
+ /* only handle netmd devices, himd devices will be handled by DBT_DEVTYP_VOLUME */
+ if(identified(devID, name) && name.contains("NetMD)")) {
+ qDebug() << name << " detected, rescanning netmd devices" << endl;
+ rescan_netmd_devices();
+ }
+ }
break;
}
case DBT_DEVICEREMOVECOMPLETE :
@@ -346,6 +397,15 @@ bool QHiMDWinDetection::winEvent(MSG * msg, long * result)
qDebug() << "Message:DBT_DEVICEREMOVECOMPLETE for drive " + path;
remove_himddevice(path);
}
+ else if(pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
+ {
+ PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
+ devID = QString::fromWCharArray(pDevInf->dbcc_name).toUpper();
+ if(identified(devID, name) && name.contains("NetMD)")) {
+ qDebug() << name << " removed, rescanning netmd devices" << endl;
+ rescan_netmd_devices();
+ }
+ }
break;
}
case DBT_DEVICEQUERYREMOVE :
@@ -353,13 +413,13 @@ bool QHiMDWinDetection::winEvent(MSG * msg, long * result)
if(pHdr->dbch_devicetype & DBT_DEVTYP_HANDLE)
{
PDEV_BROADCAST_HANDLE pHdrh = (PDEV_BROADCAST_HANDLE)pHdr;
- win_himd_device *dev = find_by_handle(pHdrh->dbch_handle);
+ QMDDevice *dev = find_by_handle(pHdrh->dbch_handle);
if(!dev)
{
qDebug() << "Message:DBT_DEVICEQUERYREMOVE for unknown device " << pHdrh->dbch_handle;
break;
}
- if(dev->is_busy)
+ if(dev->isBusy())
{
*result = BROADCAST_QUERY_DENY;
qDebug() << "Message:DBT_DEVICEQUERYREMOVE for drive " + path + " denied: transfer in progress";
@@ -368,9 +428,24 @@ bool QHiMDWinDetection::winEvent(MSG * msg, long * result)
else
{
qDebug() << "Message:DBT_DEVICEQUERYREMOVE requested";
- remove_himddevice(dev->path);
+ remove_himddevice(dev->path());
}
}
+ else if(pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
+ {
+ PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
+ devID = QString::fromWCharArray(pDevInf->dbcc_name).toUpper();
+ if(identified(devID, name) && name.contains("NetMD)")) {
+ QMDDevice * dev = find_by_name(name);
+ if(!dev)
+ break;
+ if(dev->isBusy()) {
+ *result = BROADCAST_QUERY_DENY;
+ return true;
+ }
+ dev->close();
+ }
+ }
break;
}
case my_DBT_CUSTOMEVENT :
diff --git a/qhimdtransfer/qmddevice.cpp b/qhimdtransfer/qmddevice.cpp
new file mode 100644
index 0000000..eeb7e78
--- /dev/null
+++ b/qhimdtransfer/qmddevice.cpp
@@ -0,0 +1,480 @@
+#include <qmddevice.h>
+#include <QtGui/QMessageBox>
+#include <QtGui/QApplication>
+#include <QFile>
+#include <tlist.h>
+#include <fileref.h>
+#include <tfile.h>
+#include <tag.h>
+
+extern "C" {
+#include <sox.h>
+}
+
+/* common device members */
+QMDDevice::QMDDevice() : dev_type(NO_DEVICE)
+{
+}
+
+QMDDevice::~QMDDevice()
+{
+ close();
+}
+
+enum device_type QMDDevice::deviceType()
+{
+ return dev_type;
+}
+
+void QMDDevice::setPath(QString path)
+{
+ device_path = path;
+}
+
+QString QMDDevice::path()
+{
+ return device_path;
+}
+
+void QMDDevice::setName(QString name)
+{
+ recorder_name = name;
+}
+
+QString QMDDevice::name()
+{
+ return recorder_name;
+}
+
+void QMDDevice::setBusy(bool busy)
+{
+ is_busy = busy;
+}
+
+bool QMDDevice::isBusy()
+{
+ return is_busy;
+}
+
+void QMDDevice::setPlatformData(os_data pdata)
+{
+ osdata = pdata;
+}
+
+os_data * QMDDevice::pdata()
+{
+ os_data * data = &osdata;
+ return data;
+}
+
+QStringList QMDDevice::downloadableFileExtensions() const
+{
+ if(dev_type == NETMD_DEVICE)
+ return QStringList() << "wav";
+
+ if(dev_type == HIMD_DEVICE)
+ return QStringList() << "mp3";
+
+ return QStringList();
+}
+
+void QMDDevice::checkfile(QString UploadDirectory, QString &filename, QString extension)
+{
+ QFile f;
+ QString newname;
+ int i = 2;
+
+ f.setFileName(UploadDirectory + "/" + filename + extension);
+ while(f.exists())
+ {
+ newname = filename + " (" + QString::number(i) + ")";
+ f.setFileName(UploadDirectory + "/" + newname + extension);
+ i++;
+ }
+ if(!newname.isEmpty())
+ filename = newname;
+}
+
+
+/* netmd device members */
+QNetMDDevice::QNetMDDevice()
+{
+ dev_type = NETMD_DEVICE;
+ devh = NULL;
+ netmd = NULL;
+ is_open = false;
+}
+
+QNetMDDevice::~QNetMDDevice()
+{
+ close();
+}
+
+void QNetMDDevice::setUsbDevice(netmd_device * dev)
+{
+ netmd = dev;
+}
+
+QString QNetMDDevice::open()
+{
+ uint8_t i = 0;
+ netmd_error error;
+ char buffer[256];
+
+ if(!netmd)
+ return tr("netmd_device not set, use setUsbDevice(...) function first");
+
+ if((error = netmd_open(netmd, &devh)) != NETMD_NO_ERROR)
+ return tr("Error opening netmd: %1").arg(netmd_strerror(error));
+
+ netmd_initialize_disc_info(devh, ¤t_md);
+
+ /* generate track count first, needed by QNetMDTracksModel */
+ while(netmd_request_title(devh, i, buffer, sizeof(buffer)) >= 0)
+ i++;
+
+ trk_count = i;
+
+ is_open = true;
+ emit opened();
+ return QString();
+}
+
+void QNetMDDevice::close()
+{
+ if(!devh)
+ return;
+
+ netmd_clean_disc_info(¤t_md);
+ netmd_close(devh);
+ devh = NULL;
+
+ is_open = false;
+ trk_count = 0;
+ emit closed();
+}
+
+QString QNetMDDevice::discTitle()
+{
+ return QString(current_md.groups[0].name);
+}
+
+QNetMDTrack QNetMDDevice::netmdTrack(unsigned int trkindex)
+{
+ minidisc * disc = ¤t_md;
+
+ return QNetMDTrack(devh, disc, trkindex);
+}
+
+void QNetMDDevice::batchUpload(QMDTrackIndexList tlist, QString path)
+{
+ QMessageBox mdStatus;
+
+ mdStatus.setText(tr("netmd uploads are not implemented, yet\n will be comming soon"));
+ mdStatus.exec();
+}
+
+/* himd device members */
+
+QHiMDDevice::QHiMDDevice()
+{
+ dev_type = HIMD_DEVICE;
+ himd = NULL;
+ is_open = false;
+}
+
+QHiMDDevice::~QHiMDDevice()
+{
+ close();
+}
+
+QString QHiMDDevice::open()
+{
+ struct himderrinfo status;
+
+ if(!pdata()->md_inserted)
+ return tr("cannot open device, no disc");
+
+ if(himd)
+ return QString(); // already opened
+
+ himd = new struct himd;
+ if(himd_open(himd, device_path.toUtf8(), &status) < 0)
+ {
+ delete himd;
+ himd = NULL;
+ return QString::fromUtf8(status.statusmsg);
+ }
+
+ trk_count = himd_track_count(himd);
+ is_open = true;
+ emit opened();
+ return QString();
+}
+
+void QHiMDDevice::close()
+{
+ if(!himd)
+ return;
+
+ himd_close(himd);
+ delete himd;
+ himd = NULL;
+
+ is_open = false;
+ trk_count = 0;
+ emit closed();
+}
+
+QHiMDTrack QHiMDDevice::himdTrack(unsigned int trkindex)
+{
+ return QHiMDTrack(himd, trkindex);
+}
+
+QString QHiMDDevice::dumpmp3(const QHiMDTrack &trk, QString file)
+{
+ QString errmsg;
+ struct himd_mp3stream str;
+ struct himderrinfo status;
+ unsigned int len;
+ const unsigned char * data;
+ QFile f(file);
+
+ if(!f.open(QIODevice::ReadWrite))
+ {
+ return tr("Error opening file for MP3 output");
+ }
+ if(!(errmsg = trk.openMpegStream(&str)).isNull())
+ {
+ f.remove();
+ return tr("Error opening track: ") + errmsg;
+ }
+ while(himd_mp3stream_read_block(&str, &data, &len, NULL, &status) >= 0)
+ {
+ if(f.write((const char*)data,len) == -1)
+ {
+ errmsg = tr("Error writing audio data");
+ goto clean;
+ }
+ uploadDialog.blockTransferred();
+ QApplication::processEvents();
+ if(uploadDialog.upload_canceled())
+ {
+ errmsg = tr("upload aborted by the user");
+ goto clean;
+ }
+
+ }
+ if(status.status != HIMD_STATUS_AUDIO_EOF)
+ errmsg = tr("Error reading audio data: ") + status.statusmsg;
+
+clean:
+ f.close();
+ himd_mp3stream_close(&str);
+ if(!errmsg.isNull())
+ f.remove();
+ return errmsg;
+}
+
+static inline TagLib::String QStringToTagString(const QString & s)
+{
+ return TagLib::String(s.toUtf8().data(), TagLib::String::UTF8);
+}
+
+static void addid3tag(QString title, QString artist, QString album, QString file)
+{
+#ifdef Q_OS_WIN
+ TagLib::FileRef f(file.toStdWString().c_str());
+#else
+ TagLib::FileRef f(file.toUtf8().data());
+#endif
+ TagLib::Tag *t = f.tag();
+ t->setTitle(QStringToTagString(title));
+ t->setArtist(QStringToTagString(artist));
+ t->setAlbum(QStringToTagString(album));
+ t->setComment("*** imported from HiMD via QHiMDTransfer ***");
+ f.file()->save();
+}
+
+QString QHiMDDevice::dumpoma(const QHiMDTrack &track, QString file)
+{
+ QString errmsg;
+ struct himd_nonmp3stream str;
+ struct himderrinfo status;
+ unsigned int len;
+ const unsigned char * data;
+ QFile f(file);
+
+ if(!f.open(QIODevice::ReadWrite))
+ return tr("Error opening file for ATRAC output");
+
+ if(!(errmsg = track.openNonMpegStream(&str)).isNull())
+ {
+ f.remove();
+ return tr("Error opening track: ") + status.statusmsg;
+ }
+
+ if(f.write(track.makeEA3Header()) == -1)
+ {
+ errmsg = tr("Error writing header");
+ goto clean;
+ }
+ while(himd_nonmp3stream_read_block(&str, &data, &len, NULL, &status) >= 0)
+ {
+ if(f.write((const char*)data,len) == -1)
+ {
+ errmsg = tr("Error writing audio data");
+ goto clean;
+ }
+ uploadDialog.blockTransferred();
+ QApplication::processEvents();
+ if(uploadDialog.upload_canceled())
+ {
+ errmsg = QString("upload aborted by the user");
+ goto clean;
+ }
+ }
+ if(status.status != HIMD_STATUS_AUDIO_EOF)
+ errmsg = QString("Error reading audio data: ") + status.statusmsg;
+
+clean:
+ f.close();
+ himd_nonmp3stream_close(&str);
+
+ if(!errmsg.isNull())
+ f.remove();
+ return errmsg;
+}
+
+QString QHiMDDevice::dumppcm(const QHiMDTrack &track, QString file)
+{
+ struct himd_nonmp3stream str;
+ struct himderrinfo status;
+ unsigned int len, i;
+ int left, right;
+ int clipcount;
+ QString errmsg;
+ QFile f(file);
+ const unsigned char * data;
+ sox_format_t * out;
+ sox_sample_t soxbuf [HIMD_MAX_PCMFRAME_SAMPLES * 2];
+ sox_signalinfo_t signal_out;
+
+ signal_out.channels = 2;
+ signal_out.length = 0;
+ signal_out.precision = 16;
+ signal_out.rate = 44100;
+
+ if(!(out = sox_open_write(file.toUtf8(), &signal_out, NULL, NULL, NULL, NULL)))
+ return tr("Error opening file for WAV output");
+
+ if(!(errmsg = track.openNonMpegStream(&str)).isNull())
+ {
+ f.remove();
+ return tr("Error opening track: ") + status.statusmsg;
+ }
+
+ while(himd_nonmp3stream_read_block(&str, &data, &len, NULL, &status) >= 0)
+ {
+
+ for(i = 0; i < len/4; i++) {
+
+ left = data[i*4]*256+data[i*4+1];
+ right = data[i*4+2]*256+data[i*4+3];
+ if (left > 0x8000) left -= 0x10000;
+ if (right > 0x8000) right -= 0x10000;
+
+ soxbuf[i*2] = SOX_SIGNED_16BIT_TO_SAMPLE(left, clipcount);
+ soxbuf[i*2+1] = SOX_SIGNED_16BIT_TO_SAMPLE(right, clipcount);
+ (void)clipcount; /* suppess "is unused" warning */
+ }
+
+ if (sox_write(out, soxbuf, len/2) != len/2)
+ {
+ errmsg = tr("Error writing audio data");
+ goto clean;
+ }
+ uploadDialog.blockTransferred();
+ QApplication::processEvents();
+ if(uploadDialog.upload_canceled())
+ {
+ errmsg = QString("upload aborted by the user");
+ goto clean;
+ }
+ }
+ if(status.status != HIMD_STATUS_AUDIO_EOF)
+ errmsg = QString("Error reading audio data: ") + status.statusmsg;
+
+clean:
+ sox_close(out);
+ himd_nonmp3stream_close(&str);
+
+ if(!errmsg.isNull())
+ f.remove();
+ return errmsg;
+}
+
+void QHiMDDevice::upload(unsigned int trackidx, QString path)
+{
+ QString filename, errmsg;
+ QHiMDTrack track = himdTrack(trackidx);
+ QString title = track.title();
+
+ if(title.isNull())
+ filename = tr("Track %1").arg(track.tracknum()+1);
+ else
+ filename = track.artist() + " - " + title;
+
+ uploadDialog.starttrack(track, filename);
+ if (!track.copyprotected())
+ {
+ QString codec = track.codecname();
+ if (codec == "MPEG")
+ {
+ checkfile(path, filename, ".mp3");
+ errmsg = dumpmp3 (track, path + "/" + filename + ".mp3");
+ if(errmsg.isNull())
+ addid3tag (track.title(),track.artist(),track.album(), path + "/" +filename + ".mp3");
+ }
+ else if (codec == "LPCM")
+ {
+ checkfile(path, filename, ".wav");
+ errmsg = dumppcm (track, path + "/" + filename + ".wav");
+ }
+ else if (codec == "AT3+" || codec == "AT3 ")
+ {
+ checkfile(path, filename, ".oma");
+ errmsg = dumpoma (track, path + "/" + filename + ".oma");
+ }
+ }
+ else
+ errmsg = tr("upload disabled because of DRM encryption");
+
+ if(errmsg.isNull())
+ uploadDialog.trackSucceeded();
+ else
+ uploadDialog.trackFailed(errmsg);
+
+}
+
+void QHiMDDevice::batchUpload(QMDTrackIndexList tlist, QString path)
+{
+ int allblocks = 0;
+
+ setBusy(true);
+
+ for(int i = 0;i < tlist.length(); i++)
+ allblocks += himdTrack(tlist.at(i)).blockcount();
+
+ uploadDialog.init(tlist.length(), allblocks);
+
+ for(int i = 0; i < tlist.length(); i++) {
+ upload(tlist[i], path);
+ QApplication::processEvents();
+ if(uploadDialog.upload_canceled())
+ break;
+ }
+
+ uploadDialog.finished();
+ setBusy(false);
+}
diff --git a/qhimdtransfer/qmddevice.h b/qhimdtransfer/qmddevice.h
new file mode 100644
index 0000000..2e92102
--- /dev/null
+++ b/qhimdtransfer/qmddevice.h
@@ -0,0 +1,98 @@
+#ifndef QMDDEVICE_H
+#define QMDDEVICE_H
+
+#include <QString>
+#include <QStringList>
+#include <QMetaType>
+
+#include <qmdtrack.h>
+#include "qhimduploaddialog.h"
+
+enum device_type {
+ NO_DEVICE,
+ NETMD_DEVICE,
+ HIMD_DEVICE
+};
+
+struct os_data {
+ bool md_inserted;
+ virtual ~os_data(){}
+};
+
+class QMDDevice : public QObject {
+ Q_OBJECT
+ Q_DISABLE_COPY(QMDDevice)
+
+ QString recorder_name;
+ bool is_busy;
+ struct os_data osdata;
+protected:
+ QString device_path;
+ enum device_type dev_type;
+ bool is_open;
+ unsigned int trk_count;
+ QHiMDUploadDialog uploadDialog;
+public:
+ explicit QMDDevice(); //
+ virtual ~QMDDevice();
+ virtual enum device_type deviceType(); //
+ virtual void setPath(QString path); //
+ virtual QString path(); //
+ virtual void setName(QString name); //
+ virtual QString name(); //
+ virtual void setBusy(bool busy); //
+ virtual bool isBusy(); //
+ virtual QString open() {return QString();}
+ virtual void close() {}
+ virtual bool isOpen() {return is_open;}
+ virtual QString discTitle() {return QString();}
+ virtual void setPlatformData(struct os_data pdata); //
+ virtual struct os_data * pdata(); //
+ virtual QMDTrack track(unsigned int trkindex) {return QMDTrack();}
+ virtual int trackCount() {return trk_count;}
+ virtual QStringList downloadableFileExtensions() const; //
+ virtual void checkfile(QString UploadDirectory, QString &filename, QString extension);
+ virtual void batchUpload(QMDTrackIndexList tlist, QString path) {}
+ virtual void upload(unsigned int trackidx, QString path) {}
+
+signals:
+ void opened();
+ void closed();
+};
+
+class QNetMDDevice : public QMDDevice {
+
+ netmd_device * netmd;
+ netmd_dev_handle * devh;
+ minidisc current_md;
+public:
+ explicit QNetMDDevice();
+ virtual ~QNetMDDevice();
+ virtual void setUsbDevice(netmd_device * dev); //
+ virtual QString open(); //
+ virtual void close(); //
+ virtual QString discTitle(); //
+ virtual QNetMDTrack netmdTrack(unsigned int trkindex);
+ virtual void batchUpload(QMDTrackIndexList tlist, QString path);
+ virtual void upload(unsigned int trackidx, QString path) {}
+
+};
+
+class QHiMDDevice : public QMDDevice {
+
+ struct himd * himd;
+public:
+ explicit QHiMDDevice();
+ virtual ~QHiMDDevice();
+ virtual QString open(); //
+ virtual void close(); //
+ virtual QHiMDTrack himdTrack(unsigned int trkindex); //
+ QString dumpmp3(const QHiMDTrack &trk, QString file);
+ QString dumpoma(const QHiMDTrack & track, QString file);
+ QString dumppcm(const QHiMDTrack &track, QString file);
+ virtual void upload(unsigned int trackidx, QString path);
+ virtual void batchUpload(QMDTrackIndexList tlist, QString path);
+
+};
+
+#endif // QMDDEVICE_H
diff --git a/qhimdtransfer/qmdmodel.cpp b/qhimdtransfer/qmdmodel.cpp
new file mode 100644
index 0000000..abbdddc
--- /dev/null
+++ b/qhimdtransfer/qmdmodel.cpp
@@ -0,0 +1,358 @@
+#include <QtGui/QFont>
+#include <QtGui/QFontMetrics>
+#include <qmdmodel.h>
+
+
+enum hcolumnum {
+ ColId, ColTitle, ColArtist, ColAlbum, ColLength, ColCodec, ColUploadable,
+ LAST_hcolumnnum = ColUploadable
+};
+
+enum ncolumnum {
+ CoId, CoGroup, CoTitle, CoLength, CoCodec, CoUploadable,
+ LAST_ncolumnnum = CoUploadable
+};
+
+
+/* netmd tracks model */
+QVariant QNetMDTracksModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation != Qt::Horizontal)
+ return QVariant();
+
+ if(role == Qt::SizeHintRole)
+ {
+ static QFont f;
+ static QFontMetrics met(f);
+ switch((ncolumnum)section)
+ {
+ case CoId:
+ return QSize(met.width("9999")+5, 0);
+ case CoGroup:
+ case CoTitle:
+ case CoLength:
+ return QSize(met.width("9:99:99"), 0);
+ case CoCodec:
+ case CoUploadable:
+ /* Really use the header for the metric in these columns,
+ contents will be shorter */
+ return QAbstractListModel::headerData(section,orientation,role);
+ }
+ }
+
+ if(role == Qt::DisplayRole)
+ {
+ switch((ncolumnum)section)
+ {
+ case CoId:
+ return tr("Nr.");
+ case CoGroup:
+ return tr("Group");
+ case CoTitle:
+ return tr("Title");
+ case CoLength:
+ return tr("Length");
+ case CoCodec:
+ return tr("Format");
+ case CoUploadable:
+ return tr("Uploadable");
+ }
+ }
+ return QVariant();
+}
+
+QVariant QNetMDTracksModel::data(const QModelIndex & index, int role) const
+{
+ if(role == Qt::TextAlignmentRole &&
+ (index.column() == CoId || index.column() == CoLength))
+ return Qt::AlignRight;
+
+ if(index.row() >= rowCount())
+ return QVariant();
+
+ QNetMDTrack track = allTracks[index.row()];
+
+ if(role == Qt::CheckStateRole && index.column() == CoUploadable)
+ return track.copyprotected() ? Qt::Unchecked : Qt::Checked;
+
+ if(role == Qt::DisplayRole)
+ {
+ switch((ncolumnum)index.column())
+ {
+ case CoId:
+ return index.row() + 1;
+ case CoGroup:
+ return track.group();
+ case CoTitle:
+ return track.title();
+ case CoLength:
+ {
+ QTime t = track.duration();
+ if(t < QTime(1,0,0))
+ return t.toString("m:ss");
+ else
+ return t.toString("h:mm:ss");
+ }
+ case CoCodec:
+ return track.codecname();
+ case CoUploadable:
+ return QVariant(); /* Displayed by checkbox */
+ }
+ }
+ return QVariant();
+}
+
+int QNetMDTracksModel::rowCount(const QModelIndex &) const
+{
+ if(ndev == NULL)
+ return 0;
+
+ return ndev->trackCount();
+}
+
+int QNetMDTracksModel::columnCount(const QModelIndex &) const
+{
+ return LAST_ncolumnnum+1;
+}
+
+QString QNetMDTracksModel::open(QMDDevice * device)
+{
+ int i = 0;
+ QString ret = "error opening net device";
+
+ if(ndev != NULL)
+ close();
+
+ if(device->deviceType() == NETMD_DEVICE)
+ {
+ ndev = static_cast<QNetMDDevice *>(device);
+ ret = ndev->open();
+ }
+
+ if(!ret.isEmpty())
+ close();
+
+ /* fetch track info for all tracks first, getting track info inside data() function is very slow */
+ for(; i < ndev->trackCount(); i++)
+ allTracks.append(ndev->netmdTrack(i));
+
+ reset(); /* inform views that the model contents changed */
+ return ret;
+}
+
+bool QNetMDTracksModel::is_open()
+{
+ return ndev->isOpen();
+}
+
+void QNetMDTracksModel::close()
+{
+ if(ndev != NULL && ndev->isOpen())
+ ndev->close();
+
+ ndev = NULL;
+
+ allTracks.clear();
+ reset(); /* inform views that the model contents changed */
+}
+
+QNetMDTrack QNetMDTracksModel::track(int trkidx) const
+{
+ return ndev->netmdTrack(trkidx);
+}
+
+QNetMDTrackList QNetMDTracksModel::tracks(const QModelIndexList & modelindices) const
+{
+ QNetMDTrackList tracks;
+ QModelIndex index;
+
+ foreach(index, modelindices)
+ tracks.append(ndev->netmdTrack(index.row()));
+ return tracks;
+}
+
+QStringList QNetMDTracksModel::downloadableFileExtensions() const
+{
+ return ndev->downloadableFileExtensions();
+}
+
+
+/* himd tracks model */
+
+QVariant QHiMDTracksModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation != Qt::Horizontal)
+ return QVariant();
+
+ if(role == Qt::SizeHintRole)
+ {
+ static QFont f;
+ static QFontMetrics met(f);
+ switch((hcolumnum)section)
+ {
+ case ColId:
+ return QSize(met.width("9999")+5, 0);
+ case ColTitle:
+ case ColArtist:
+ case ColAlbum:
+ return QSize(25*met.averageCharWidth(), 0);
+ case ColLength:
+ return QSize(met.width("9:99:99"), 0);
+ case ColCodec:
+ case ColUploadable:
+ /* Really use the header for the metric in these columns,
+ contents will be shorter */
+ return QAbstractListModel::headerData(section,orientation,role);
+ }
+ }
+
+ if(role == Qt::DisplayRole)
+ {
+ switch((hcolumnum)section)
+ {
+ case ColId:
+ return tr("Nr.");
+ case ColTitle:
+ return tr("Title");
+ case ColArtist:
+ return tr("Artist");
+ case ColAlbum:
+ return tr("Album");
+ case ColLength:
+ return tr("Length");
+ case ColCodec:
+ return tr("Format");
+ case ColUploadable:
+ return tr("Uploadable");
+ }
+ }
+ return QVariant();
+}
+
+QVariant QHiMDTracksModel::data(const QModelIndex & index, int role) const
+{
+ if(role == Qt::TextAlignmentRole &&
+ (index.column() == ColId || index.column() == ColLength))
+ return Qt::AlignRight;
+
+ if(index.row() >= rowCount())
+ return QVariant();
+
+ QHiMDTrack track = hdev->himdTrack(index.row());
+
+ if(role == Qt::CheckStateRole && index.column() == ColUploadable)
+ return track.copyprotected() ? Qt::Unchecked : Qt::Checked;
+
+ if(role == Qt::DisplayRole)
+ {
+ switch((hcolumnum)index.column())
+ {
+ case ColId:
+ return index.row() + 1;
+ case ColTitle:
+ return track.title();
+ case ColArtist:
+ return track.artist();
+ case ColAlbum:
+ return track.album();
+ case ColLength:
+ {
+ QTime t = track.duration();
+ if(t < QTime(1,0,0))
+ return t.toString("m:ss");
+ else
+ return t.toString("h:mm:ss");
+ }
+ case ColCodec:
+ return track.codecname();
+ case ColUploadable:
+ return QVariant(); /* Displayed by checkbox */
+ }
+ }
+ return QVariant();
+}
+
+int QHiMDTracksModel::rowCount(const QModelIndex &) const
+{
+ if(hdev == NULL)
+ return 0;
+
+ return hdev->trackCount();
+}
+
+int QHiMDTracksModel::columnCount(const QModelIndex &) const
+{
+ return LAST_hcolumnnum+1;
+}
+
+QString QHiMDTracksModel::open(QMDDevice * device)
+{
+ QString ret = "error opening himd device";
+
+ if(hdev != NULL)
+ close();
+
+ if(device->deviceType() == HIMD_DEVICE)
+ {
+ hdev = static_cast<QHiMDDevice *>(device);
+ ret = hdev->open();
+ }
+
+ if(!ret.isEmpty())
+ close();
+
+ reset(); /* inform views that the model contents changed */
+ return ret;
+}
+
+bool QHiMDTracksModel::is_open()
+{
+ return hdev->isOpen();
+}
+
+void QHiMDTracksModel::close()
+{
+ if(hdev != NULL && hdev->isOpen())
+ hdev->close();
+
+ hdev = NULL;
+
+ reset(); /* inform views that the model contents changed */
+}
+
+QHiMDTrack QHiMDTracksModel::track(int trknum) const
+{
+ return hdev->himdTrack(trknum);
+}
+
+QHiMDTrackList QHiMDTracksModel::tracks(const QModelIndexList & modelindices) const
+{
+ QHiMDTrackList tracks;
+ QModelIndex index;
+
+ foreach(index, modelindices)
+ tracks.append(hdev->himdTrack(index.row()));
+ return tracks;
+}
+
+QStringList QHiMDTracksModel::downloadableFileExtensions() const
+{
+ return hdev->downloadableFileExtensions();
+}
+
+
+/* QFileSystemModel stuff */
+
+Qt::ItemFlags QHiMDFileSystemModel::flags(const QModelIndex &index) const
+{
+ if(!isDir(index) && !selectableExtensions.contains((fileInfo(index).suffix()), Qt::CaseInsensitive))
+ return Qt::NoItemFlags; //not selectable, not enabled (grayed out in the browser)
+
+ return QFileSystemModel::flags(index);
+}
+
+void QHiMDFileSystemModel::setSelectableExtensions(QStringList extensions)
+{
+ selectableExtensions = extensions;
+ reset();
+}
diff --git a/qhimdtransfer/qmdmodel.h b/qhimdtransfer/qmdmodel.h
new file mode 100644
index 0000000..9dd644e
--- /dev/null
+++ b/qhimdtransfer/qmdmodel.h
@@ -0,0 +1,80 @@
+#ifndef QHIMDMODEL_H
+#define QHIMDMODEL_H
+
+#include <QtCore/QAbstractListModel>
+
+#include <QtCore/QList>
+#include <QtCore/QStringList>
+#include <QtGui/QFileSystemModel>
+#include <qmdtrack.h>
+#include <qmddevice.h>
+
+class QMDTracksModel : public QAbstractListModel {
+ Q_OBJECT
+
+ QMDDevice * dev;
+public:
+ QMDTracksModel() : dev(NULL) {}
+ /* QAbstractListModel stuff */
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const {return QVariant();}
+ virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const {return QVariant();}
+ virtual int rowCount(const QModelIndex & parent = QModelIndex() ) const {return 0;}
+ virtual int columnCount(const QModelIndex & parent = QModelIndex() ) const {return 0;}
+ /* dummy data for unknown devices */
+ virtual QString open(QMDDevice *device = NULL) {return tr("no known device type specified");}
+ virtual bool is_open() {return false;}
+ virtual void close() {}
+ QStringList downloadableFileExtensions() const {return QStringList();}
+};
+
+class QNetMDTracksModel : public QMDTracksModel {
+ Q_OBJECT
+
+ QNetMDDevice * ndev;
+ QNetMDTrackList allTracks;
+public:
+ QNetMDTracksModel() {ndev = NULL;}
+ /* QAbstractListModel stuff */
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+ virtual int rowCount(const QModelIndex & parent = QModelIndex() ) const;
+ virtual int columnCount(const QModelIndex & parent = QModelIndex() ) const;
+ /* NetMD device stuff */
+ QString open(QMDDevice *device); /* returns null if OK, error message otherwise */
+ virtual bool is_open();
+ void close();
+ QNetMDTrack track(int trkidx) const;
+ virtual QNetMDTrackList tracks(const QModelIndexList & indices) const; // should be QMDTrackList later
+ QStringList downloadableFileExtensions() const;
+};
+
+class QHiMDTracksModel : public QMDTracksModel {
+ Q_OBJECT
+
+ QHiMDDevice * hdev;
+public:
+ QHiMDTracksModel() {hdev = NULL;}
+ /* QAbstractListModel stuff */
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+ virtual int rowCount(const QModelIndex & parent = QModelIndex() ) const;
+ virtual int columnCount(const QModelIndex & parent = QModelIndex() ) const;
+ /* HiMD containter stuff */
+ virtual QString open(QMDDevice *device); /* returns null if OK, error message otherwise */
+ virtual bool is_open();
+ virtual void close();
+ virtual QHiMDTrack track(int trackidx) const;
+ virtual QHiMDTrackList tracks(const QModelIndexList & indices) const; // should be QMDTrackList later
+ QStringList downloadableFileExtensions() const;
+};
+
+class QHiMDFileSystemModel : public QFileSystemModel {
+ Q_OBJECT
+
+ QStringList selectableExtensions;
+public:
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+ void setSelectableExtensions(QStringList extensions);
+};
+
+#endif
diff --git a/qhimdtransfer/qmdtrack.cpp b/qhimdtransfer/qmdtrack.cpp
new file mode 100644
index 0000000..84643f8
--- /dev/null
+++ b/qhimdtransfer/qmdtrack.cpp
@@ -0,0 +1,204 @@
+#include "qmdtrack.h"
+
+static QString get_himd_str(struct himd * himd, int idx)
+{
+ QString outstr;
+ char * str;
+ if(!idx)
+ return QString();
+ str = himd_get_string_utf8(himd, idx, NULL, NULL);
+ if(!str)
+ return QString();
+
+ outstr = QString::fromUtf8(str);
+ himd_free(str);
+ return outstr;
+}
+
+QHiMDTrack::QHiMDTrack(struct himd * himd, unsigned int trackindex) : himd(himd), trknum(trackindex)
+{
+ trackslot = himd_get_trackslot(himd, trackindex, NULL);
+ if(trackslot != 0)
+ if(himd_get_track_info(himd, trackslot, &ti, NULL) < 0)
+ trackslot = -1;
+}
+
+unsigned int QHiMDTrack::tracknum() const
+{
+ return trknum;
+}
+
+QString QHiMDTrack::title() const
+{
+ if(trackslot != 0)
+ return get_himd_str(himd, ti.title);
+ else
+ return QString();
+}
+
+QString QHiMDTrack::artist() const
+{
+ if(trackslot != 0)
+ return get_himd_str(himd, ti.artist);
+ else
+ return QString();
+}
+
+QString QHiMDTrack::album() const
+{
+ if(trackslot != 0)
+ return get_himd_str(himd, ti.album);
+ else
+ return QString();
+}
+
+QString QHiMDTrack::codecname() const
+{
+ if(trackslot != 0)
+ return himd_get_codec_name(&ti);
+ else
+ return QString();
+}
+
+QTime QHiMDTrack::duration() const
+{
+ QTime t;
+ if(trackslot != 0)
+ return t.addSecs(ti.seconds);
+ else
+ return t;
+}
+
+bool QHiMDTrack::copyprotected() const
+{
+ if(trackslot != 0)
+ return !himd_track_uploadable(himd, &ti);
+ return true;
+}
+
+int QHiMDTrack::blockcount() const
+{
+ if(trackslot != 0)
+ return himd_track_blocks(himd, &ti, NULL);
+ else
+ return 0;
+}
+
+QString QHiMDTrack::openMpegStream(struct himd_mp3stream * str) const
+{
+ struct himderrinfo status;
+ if(himd_mp3stream_open(himd, trackslot, str, &status) < 0)
+ return QString::fromUtf8(status.statusmsg);
+ return QString();
+}
+
+QString QHiMDTrack::openNonMpegStream(struct himd_nonmp3stream * str) const
+{
+ struct himderrinfo status;
+ if(himd_nonmp3stream_open(himd, trackslot, str, &status) < 0)
+ return QString::fromUtf8(status.statusmsg);
+ return QString();
+}
+
+QByteArray QHiMDTrack::makeEA3Header() const
+{
+ char header[EA3_FORMAT_HEADER_SIZE];
+ make_ea3_format_header(header, &ti.codec_info);
+ return QByteArray(header,EA3_FORMAT_HEADER_SIZE);
+}
+
+
+QNetMDTrack::QNetMDTrack(netmd_dev_handle * deviceh, minidisc * my_md, unsigned int trackindex)
+{
+ uint8_t g;
+ struct netmd_pair const *bitrate;
+ unsigned char bitrate_id;
+ unsigned char channel;
+ char *name, buffer[256];
+
+ devh = deviceh;
+ md = my_md;
+ trkindex = trackindex;
+
+ if(netmd_request_title(devh, trkindex, buffer, sizeof(buffer)) < 0)
+ {
+ trkindex = -1;
+ return; // no track with this trackindex
+ }
+
+ /* Figure out which group this track is in */
+ for( g = 1; g < md->group_count; g++ )
+ {
+ if( (md->groups[g].start <= trkindex+1U) && (md->groups[g].finish >= trkindex+1U ))
+ {
+ groupstring = QString(md->groups[g].name);
+ break;
+ }
+ }
+
+ netmd_request_track_time(devh, trkindex, &time);
+ netmd_request_track_flags(devh, trkindex, &flags);
+ netmd_request_track_bitrate(devh, trkindex, &bitrate_id, &channel);
+
+ bitrate = find_pair(bitrate_id, bitrates);
+
+ /* Skip 'LP:' prefix... the codec type shows up in the list anyway*/
+ name = strncmp( buffer, "LP:", 3 ) ? buffer : buffer+3 ;
+
+ titlestring = QString(name);
+ codecstring = QString(bitrate->name);
+}
+
+unsigned int QNetMDTrack::tracknum() const
+{
+ return (trkindex < 0 ? trkindex : trkindex + 1);
+}
+
+QString QNetMDTrack::group() const
+{
+ if(trkindex < 0)
+ return QString();
+
+ return groupstring;
+}
+
+QString QNetMDTrack::title() const
+{
+ if(trkindex < 0)
+ return QString();
+
+ return titlestring;
+}
+
+QString QNetMDTrack::codecname() const
+{
+ if(trkindex < 0)
+ return QString();
+
+ return codecstring;
+}
+
+QTime QNetMDTrack::duration() const
+{
+ QTime t;
+
+ if(trkindex < 0)
+ return t;
+
+ return t.addSecs( time.minute * 60 + time.second);
+}
+
+bool QNetMDTrack::copyprotected() const
+{
+ switch(flags)
+ {
+ case 0x00 : return false;
+ case 0x03 : return true;
+ default : return true; // return true if unknown
+ }
+}
+
+int QNetMDTrack::blockcount() const
+{
+ return 0; // not implemented, yet
+}
diff --git a/qhimdtransfer/qmdtrack.h b/qhimdtransfer/qmdtrack.h
new file mode 100644
index 0000000..c7f30ad
--- /dev/null
+++ b/qhimdtransfer/qmdtrack.h
@@ -0,0 +1,81 @@
+#ifndef QMDTRACK_H
+#define QMDTRACK_H
+
+#include <QtCore/QTime>
+#include "himd.h"
+#include "sony_oma.h"
+
+#ifdef Q_OS_WIN
+ #ifdef WINVER // WINVER needs to be 0x500 or later to make the windows autodetection mechanism work and it
+ #undef WINVER // must be defined correctly before including libusb.h (included from libnetmd.h), else it will be defined
+ #endif // in windef.h to 0x400
+ #define WINVER 0x500
+#endif
+
+extern "C" {
+#include <libnetmd.h>
+}
+
+class QMDTrack
+{
+public:
+ QMDTrack() {} // returns dummy data, implemented to have a common class name with common members
+ virtual unsigned int tracknum() const {return -1;}
+ virtual QString group() const {return QString();}
+ virtual QString title() const {return QString();}
+ virtual QString artist() const {return QString();}
+ virtual QString album() const {return QString();}
+ virtual QString codecname() const {return QString();}
+ virtual QTime duration() const {return QTime();}
+ virtual bool copyprotected() const {return true;}
+ virtual int blockcount() const {return 0;}
+};
+
+class QHiMDTrack : public QMDTrack{
+ struct himd * himd;
+ unsigned int trknum;
+ unsigned int trackslot;
+ struct trackinfo ti;
+public:
+ QHiMDTrack(struct himd * himd, unsigned int trackindex);
+ virtual unsigned int tracknum() const;
+ virtual QString title() const;
+ virtual QString artist() const;
+ virtual QString album() const;
+ virtual QString codecname() const;
+ virtual QTime duration() const;
+ virtual bool copyprotected() const;
+ virtual int blockcount() const;
+
+ QString openMpegStream(struct himd_mp3stream * str) const;
+ QString openNonMpegStream(struct himd_nonmp3stream * str) const;
+ QByteArray makeEA3Header() const;
+};
+
+class QNetMDTrack : public QMDTrack {
+ netmd_dev_handle * devh;
+ minidisc * md;
+ uint8_t trkindex;
+ struct netmd_track time;
+ unsigned char flags;
+ QString groupstring;
+ QString titlestring;
+ QString codecstring;
+
+public:
+ QNetMDTrack(netmd_dev_handle *deviceh, minidisc * my_md, unsigned int trackindex);
+ virtual unsigned int tracknum() const;
+ virtual QString group() const;
+ virtual QString title() const;
+ virtual QString codecname() const;
+ virtual QTime duration() const;
+ virtual bool copyprotected() const;
+ virtual int blockcount() const;
+};
+
+typedef QList<QMDTrack> QMDTrackList;
+typedef QList<QHiMDTrack> QHiMDTrackList;
+typedef QList<QNetMDTrack> QNetMDTrackList;
+typedef QList<unsigned int> QMDTrackIndexList;
+
+#endif // QMDTRACK_H
--
1.8.0.msysgit.0