FU Logo
  • Startseite
  • Kontakt
  • Impressum
  • Home
  • Listenauswahl
  • Anleitungen

Re: [linux-minidisc] implementing netmd support in the gui application

<-- thread -->
<-- date -->
  • From: Thomas Arp <manner.moe@gmx.de>
  • To: linux-minidisc@lists.fu-berlin.de
  • Date: Sat, 26 Jan 2013 22:14:19 +0100
  • Subject: Re: [linux-minidisc] implementing netmd support in the gui application

Hi,

as the patch for netmd support is really large, i splitted it into smaller patches. I didn't rewrite the whole thing, so most of these patches depends on the other ones. These patches are class by class and only the last few patches include the integration in the current source code and the removed functions i already moved to new classes before. Some files were removed/renamed and functions were moved to other classes, so compilation will fail until all patches are applied.
I just plitted the patch to simplify reviewing.

Thomas
>From 1ea60db8453049107249ae263de824b3dd2d7f27 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 20:47:53 +0100
Subject: [PATCH 1/7] implemented new class QNetMDTrack analogous to
 QHiMDTrack and put a base class QMDTrack over it holding
 common members

---
 qhimdtransfer/qmdtrack.cpp | 212 +++++++++++++++++++++++++++++++++++++++++++++
 qhimdtransfer/qmdtrack.h   |  88 +++++++++++++++++++
 2 files changed, 300 insertions(+)
 create mode 100644 qhimdtransfer/qmdtrack.cpp
 create mode 100644 qhimdtransfer/qmdtrack.h

diff --git a/qhimdtransfer/qmdtrack.cpp b/qhimdtransfer/qmdtrack.cpp
new file mode 100644
index 0000000..e3ea7d7
--- /dev/null
+++ b/qhimdtransfer/qmdtrack.cpp
@@ -0,0 +1,212 @@
+#include "qmdtrack.h"
+#include <QDebug>
+
+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;
+    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);
+    blocks = 0;
+}
+
+unsigned int QNetMDTrack::tracknum() const
+{
+    /* returns zero based track number, maybe this function should return a one based track number as shown in the treeview,
+     * trackindex -> zero based; tracknumber -> one based
+     */
+    return trkindex;
+}
+
+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
+    }
+}
+
+void QNetMDTrack::setBlocks(int cnt)
+{
+    blocks = cnt;
+}
+
+int QNetMDTrack::blockcount() const
+{
+    return blocks;
+}
diff --git a/qhimdtransfer/qmdtrack.h b/qhimdtransfer/qmdtrack.h
new file mode 100644
index 0000000..47f93f8
--- /dev/null
+++ b/qhimdtransfer/qmdtrack.h
@@ -0,0 +1,88 @@
+#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_extended.h>
+}
+
+/* define buffer size for netmd downloads */
+#define NETMD_RECV_BUF_SIZE 0x10000
+
+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;
+private:
+    int blocks;
+public:
+    unsigned char bitrate_id;
+    unsigned char channel;
+    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 void setBlocks(int cnt);
+    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

>From c6490daa23d305a3abe3c89c81d405f92e85d473 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 20:53:56 +0100
Subject: [PATCH 2/7] implemented new class QMDDevice with subclasses
 QNetMDDevice and QHiMDDevice holding information for
 each device and containing upload routines, also
 created additional libnetmd header file to get access
 to additional libnetmd functions

---
 libnetmd/libnetmd.pro        |   3 +-
 libnetmd/libnetmd_extended.h |  37 +++
 qhimdtransfer/qmddevice.cpp  | 619 +++++++++++++++++++++++++++++++++++++++++++
 qhimdtransfer/qmddevice.h    | 101 +++++++
 4 files changed, 759 insertions(+), 1 deletion(-)
 create mode 100644 libnetmd/libnetmd_extended.h
 create mode 100644 qhimdtransfer/qmddevice.cpp
 create mode 100644 qhimdtransfer/qmddevice.h

diff --git a/libnetmd/libnetmd.pro b/libnetmd/libnetmd.pro
index eb6a402..3319d85 100644
--- a/libnetmd/libnetmd.pro
+++ b/libnetmd/libnetmd.pro
@@ -5,7 +5,8 @@ CONFIG += staticlib link_pkgconfig create_prl console debug_and_release_target
 DEFINES += G_DISABLE_DEPRECATED=1
 
 PKGCONFIG += libusb-1.0
-HEADERS += common.h const.h error.h libnetmd.h log.h netmd_dev.h playercontrol.h secure.h trackinformation.h utils.h
+HEADERS += common.h const.h error.h libnetmd.h log.h netmd_dev.h playercontrol.h secure.h trackinformation.h utils.h \
+    libnetmd_extended.h
 SOURCES += common.c error.c libnetmd.c log.c netmd_dev.c playercontrol.c secure.c trackinformation.c utils.c
 LIBS    += -lgcrypt
 
diff --git a/libnetmd/libnetmd_extended.h b/libnetmd/libnetmd_extended.h
new file mode 100644
index 0000000..1eb74db
--- /dev/null
+++ b/libnetmd/libnetmd_extended.h
@@ -0,0 +1,37 @@
+/*
+ * include this header file to get access to additional libnetmd members
+ */
+
+#include "libnetmd.h"
+
+typedef struct {
+        unsigned char content[255];
+        size_t length;
+        size_t position;
+} netmd_response;
+
+/*
+ * additional members from secure.c
+ */
+
+void netmd_send_secure_msg(netmd_dev_handle *dev, unsigned char cmd, unsigned char *data, size_t data_size);
+netmd_error netmd_recv_secure_msg(netmd_dev_handle *dev, unsigned char cmd, netmd_response *response,
+                                  unsigned char expected_response_code);
+netmd_error netmd_secure_real_recv_track(netmd_dev_handle *dev, uint32_t length, FILE *file, size_t chunksize);
+void netmd_write_aea_header(char *name, uint32_t frames, unsigned char channel, FILE* f);
+void netmd_write_wav_header(unsigned char format, uint32_t bytes, FILE *f);
+
+/*
+ * additional members from utils.c
+ * XXX: do not include utils.h when using taglib, definition of min(a,b) is incomatible with definition of min(...) in taglib
+ */
+void netmd_check_response_bulk(netmd_response *response, const unsigned char* const expected,
+                               const size_t expected_length, netmd_error *error);
+void netmd_check_response_word(netmd_response *response, const uint16_t expected,
+                               netmd_error *error);
+void netmd_read_response_bulk(netmd_response *response, unsigned char* target,
+                              const size_t length, netmd_error *error);
+unsigned char *netmd_copy_word_to_buffer(unsigned char **buf, uint16_t value, int little_endian);
+unsigned char netmd_read(netmd_response *response);
+uint16_t netmd_read_word(netmd_response *response);
+uint32_t netmd_read_doubleword(netmd_response *response);
diff --git a/qhimdtransfer/qmddevice.cpp b/qhimdtransfer/qmddevice.cpp
new file mode 100644
index 0000000..be85492
--- /dev/null
+++ b/qhimdtransfer/qmddevice.cpp
@@ -0,0 +1,619 @@
+#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, &current_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(&current_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 = &current_md;
+
+    return QNetMDTrack(devh, disc, trkindex);
+}
+
+QString QNetMDDevice::upload_track_blocks(uint32_t length, FILE *file, size_t chunksize)
+{
+    /* this is a copy of netmd_secure_real_recv_track(...) function, but updates upload dialog progress bar */
+    uint32_t done = 0;
+    unsigned char *data;
+    int status;
+    netmd_error error = NETMD_NO_ERROR;
+    int transferred = 0;
+
+    data = (unsigned char *)malloc(chunksize);
+    while (done < length) {
+        if ((length - done) < chunksize) {
+            chunksize = length - done;
+        }
+
+        status = libusb_bulk_transfer((libusb_device_handle*)devh, 0x81, data, (int)chunksize, &transferred, 10000);
+
+        if (status >= 0) {
+            done += transferred;
+            fwrite(data, transferred, 1, file);
+            netmd_log(NETMD_LOG_DEBUG, "%.1f%%\n", (double)done/(double)length * 100);
+
+            uploadDialog.blockTransferred();
+            /* do not check for uploadDialog.upload_canceled() here, netmd device will remain busy if track upload hasn´t finished */
+        }
+        else if (status != -LIBUSB_ERROR_TIMEOUT) {
+            error = NETMD_USB_ERROR;
+        }
+    }
+    free(data);
+
+    return (error != NETMD_NO_ERROR) ? netmd_strerror(error) : QString();
+}
+
+void QNetMDDevice::upload(unsigned int trackidx, QString path)
+{
+    /* this is a copy of netmd_secure_recv_track(...) function, we need single block transfer function to make use of a progress bar,
+     * maybe we can change libnetmd to make use of a single chunk transfer function for this
+     */
+    QNetMDTrack track = netmdTrack(trackidx);
+    uint16_t track_id = trackidx;
+    unsigned char cmdhdr[] = {0x00, 0x10, 0x01};
+    unsigned char cmd[sizeof(cmdhdr) + sizeof(track_id)] = { 0 };
+    unsigned char *buf;
+    unsigned char codec;
+    uint32_t length;
+    netmd_response response;
+    netmd_error error;
+    QString filename, errmsg, filepath;
+    FILE * file;
+
+    // create filename first
+    if(track.title().isEmpty())
+        filename = tr("Track %1").arg(track.tracknum());
+    else
+        filename = track.title();
+
+    if(track.bitrate_id == NETMD_ENCODING_SP) {
+        checkfile(path, filename, ".aea");
+        filepath = path + "/" + filename + ".aea";
+    }
+    else {
+        checkfile(path, filename, ".wav");
+        filepath = path + "/" + filename + ".wav";
+    }
+
+    if(!(file = fopen(filepath.toUtf8().data(), "wb"))) {
+            errmsg = tr("cannot open file %1 for writing").arg(filepath);
+            goto clean;
+    }
+
+    buf = cmd;
+    memcpy(buf, cmdhdr, sizeof(cmdhdr));
+    buf += sizeof(cmdhdr);
+    netmd_copy_word_to_buffer(&buf, trackidx + 1U, 0);
+
+    netmd_send_secure_msg(devh, 0x30, cmd, sizeof(cmd));
+    error = netmd_recv_secure_msg(devh, 0x30, &response, NETMD_STATUS_INTERIM);
+    netmd_check_response_bulk(&response, cmdhdr, sizeof(cmdhdr), &error);
+    netmd_check_response_word(&response, track_id + 1U, &error);
+    codec = netmd_read(&response);
+    length = netmd_read_doubleword(&response);
+
+    /* initialize track.blockcount() needed by uploadDialog */
+    track.setBlocks(length%NETMD_RECV_BUF_SIZE ? length / NETMD_RECV_BUF_SIZE + 1 : length / NETMD_RECV_BUF_SIZE);
+    uploadDialog.starttrack(track, filename);
+    if (track.bitrate_id == NETMD_ENCODING_SP) {
+        netmd_write_aea_header(track.title().toUtf8().data(), codec, track.channel, file);
+    }
+    else {
+        netmd_write_wav_header(codec, length, file);
+    }
+
+    errmsg = upload_track_blocks(length, file, NETMD_RECV_BUF_SIZE);
+    if(!errmsg.isNull()) {
+        goto clean;
+    }
+
+    error = netmd_recv_secure_msg(devh, 0x30, &response, NETMD_STATUS_ACCEPTED);
+    netmd_check_response_bulk(&response, cmdhdr, sizeof(cmdhdr), &error);
+    netmd_read_response_bulk(&response, NULL, 2, &error);
+    netmd_check_response_word(&response, 0, &error);
+
+    if(error != NETMD_NO_ERROR)
+        errmsg = QString(netmd_strerror(error));
+
+clean:
+    if(errmsg.isNull())
+        uploadDialog.trackSucceeded();
+    else
+        uploadDialog.trackFailed(errmsg);
+
+    fclose(file);
+    if(!errmsg.isNull()) {
+        QFile f(filepath);
+        if(f.exists())
+            f.remove();
+    }
+}
+
+void QNetMDDevice::batchUpload(QMDTrackIndexList tlist, QString path)
+{
+    int allblocks = 0;
+
+    setBusy(true);
+
+    /* does not work yet, is there any way to get track length without recieving a complete track ?
+     * as far as i´ve tested device remains busy if download procedure hasn´t finished.
+     * progressbar for all tracks shows idle mode if maximum value is set to 0
+     */
+    for(int i = 0;i < tlist.length(); i++) {
+        allblocks += netmdTrack(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);
+}
+
+/* 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..3be6c36
--- /dev/null
+++ b/qhimdtransfer/qmddevice.h
@@ -0,0 +1,101 @@
+#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;
+private:
+    QString upload_track_blocks(uint32_t length, FILE *file, size_t chunksize);
+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;
+private:
+    QString dumpmp3(const QHiMDTrack &trk, QString file);
+    QString dumpoma(const QHiMDTrack & track, QString file);
+    QString dumppcm(const QHiMDTrack &track, QString file);
+public:
+    explicit QHiMDDevice();
+    virtual ~QHiMDDevice();
+    virtual QString open();  //
+    virtual void close();  //
+    virtual QHiMDTrack himdTrack(unsigned int trkindex);  //
+    virtual void upload(unsigned int trackidx, QString path);
+    virtual void batchUpload(QMDTrackIndexList tlist, QString path);
+
+};
+
+#endif // QMDDEVICE_H
-- 
1.8.0.msysgit.0

>From 4bb57c89772d8514f28816717991e035cbb96afc Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 20:57:33 +0100
Subject: [PATCH 3/7] implemented new class QNetMDTracksModel analogous to
 QHiMDTracksModel, renamed qhimdmodel.h/.cpp to
 qmdmodel.h/.cpp, QHiMDTrack class is already moved to
 qmdtrack.h/.cpp

---
 qhimdtransfer/qhimdmodel.cpp | 289 ----------------------------------
 qhimdtransfer/qhimdmodel.h   |  68 --------
 qhimdtransfer/qmdmodel.cpp   | 358 +++++++++++++++++++++++++++++++++++++++++++
 qhimdtransfer/qmdmodel.h     |  80 ++++++++++
 4 files changed, 438 insertions(+), 357 deletions(-)
 delete mode 100644 qhimdtransfer/qhimdmodel.cpp
 delete mode 100644 qhimdtransfer/qhimdmodel.h
 create mode 100644 qhimdtransfer/qmdmodel.cpp
 create mode 100644 qhimdtransfer/qmdmodel.h

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/qmdmodel.cpp b/qhimdtransfer/qmdmodel.cpp
new file mode 100644
index 0000000..04e67da
--- /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 ((ndev->name() != "SONY MZ-RH1 (NetMD)") && 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
-- 
1.8.0.msysgit.0

>From b7b5bd44f351be63550c0813aa94b4407ad1d004 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 21:03:39 +0100
Subject: [PATCH 4/7] changed QHiMDTrack parameter in
 QHiMDUploadDialog::starttrack() to QMDTrack, upload
 dialog can be used for netmd tracks, too. Also reset
 "canceled" variable in init() function

---
 qhimdtransfer/qhimduploaddialog.cpp | 11 ++++++++++-
 qhimdtransfer/qhimduploaddialog.h   |  4 ++--
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/qhimdtransfer/qhimduploaddialog.cpp b/qhimdtransfer/qhimduploaddialog.cpp
index 4df44ca..605c868 100644
--- a/qhimdtransfer/qhimduploaddialog.cpp
+++ b/qhimdtransfer/qhimduploaddialog.cpp
@@ -34,6 +34,13 @@ void QHiMDUploadDialog::finished()
     /* Prevent shrinking of the box when hiding the indicators */
     m_ui->current->setMinimumSize(m_ui->current->size());
     m_ui->TrkPBar->hide();
+    /* set AllPBar to 100% if it is not used during transfer,
+     * current netmd uploads doesn´t set the range correctly
+     */
+    if(m_ui->AllPBar->maximum() == 0) {
+        m_ui->AllPBar->setMaximum(1);
+        m_ui->AllPBar->setValue(1);
+    }
     m_ui->curtrack_label->hide();
 
     m_ui->cancel_button->hide();
@@ -42,7 +49,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 +71,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();
-- 
1.8.0.msysgit.0

>From f5339286763e297d673c0a18aedf598097720c21 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 21:07:48 +0100
Subject: [PATCH 5/7] implemented netmd autodetection at application start,
 also implemented autodetection during application
 runtime for windows using the new QMDDevice classes

---
 qhimdtransfer/qhimddetection.cpp    | 262 ++++++++++++++++++++++++++++++++----
 qhimdtransfer/qhimddetection.h      | 105 ++++++++++-----
 qhimdtransfer/qhimdwindetection.cpp | 203 +++++++++++++++++++---------
 3 files changed, 448 insertions(+), 122 deletions(-)

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..4a5915a 100644
--- a/qhimdtransfer/qhimddetection.h
+++ b/qhimdtransfer/qhimddetection.h
@@ -4,50 +4,95 @@
 #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);
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 :
-- 
1.8.0.msysgit.0

>From b9e2e22a813f3583a1e8f9d73e18a0baa2ec658c Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 21:11:58 +0100
Subject: [PATCH 6/7] changed QHiMDMainWindow to use the new classes and
 changed autodetection mechanism, also removed himd
 upload routines which are already implemented in the
 class QHiMDDevice

---
 qhimdtransfer/qhimdmainwindow.cpp | 446 +++++++++-----------------------------
 qhimdtransfer/qhimdmainwindow.h   |  30 +--
 qhimdtransfer/qhimdmainwindow.ui  |  18 +-
 3 files changed, 125 insertions(+), 369 deletions(-)

diff --git a/qhimdtransfer/qhimdmainwindow.cpp b/qhimdtransfer/qhimdmainwindow.cpp
index e2675d9..8c4d19f 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&)));
 }
@@ -236,8 +31,7 @@ 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.setNameFilters(QStringList() << "*.mp3" << "*.wav" << "*.oma" << "*.aea");
     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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;minidisc device (path):&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;disc title:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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">
-- 
1.8.0.msysgit.0

>From 0fab7c133c0414da600fe496878b0e4c13bb577e Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 21:16:23 +0100
Subject: [PATCH 7/7] changed qhimdtransfer project file to use all the
 changes for netmd integration

---
 qhimdtransfer/qhimdtransfer.pro | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

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)
-- 
1.8.0.msysgit.0

>From 22900b2c65dad92c3dd1c854e598c3f86c846daf Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 26 Jan 2013 21:31:56 +0100
Subject: [PATCH 8/8] removed unused include <QMetaType>

---
 qhimdtransfer/qmddevice.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/qhimdtransfer/qmddevice.h b/qhimdtransfer/qmddevice.h
index 3be6c36..b7f3a97 100644
--- a/qhimdtransfer/qmddevice.h
+++ b/qhimdtransfer/qmddevice.h
@@ -3,7 +3,6 @@
 
 #include <QString>
 #include <QStringList>
-#include <QMetaType>
 
 #include <qmdtrack.h>
 #include "qhimduploaddialog.h"
-- 
1.8.0.msysgit.0

<-- thread -->
<-- date -->
  • References:
    • Re: [linux-minidisc] implementing netmd support in the gui application
      • From: Thomas Arp <manner.moe@gmx.de>
    • Re: [linux-minidisc] implementing netmd support in the gui application
      • From: Thomas Arp <manner.moe@gmx.de>
    • Re: [linux-minidisc] implementing netmd support in the gui application
      • From: Thomas Arp <manner.moe@gmx.de>
  • linux-minidisc - January 2013 - Archives indexes sorted by:
    [ thread ] [ subject ] [ author ] [ date ]
  • Complete archive of the linux-minidisc mailing list
  • More info on this list...

Hilfe

  • FAQ
  • Dienstbeschreibung
  • ZEDAT Beratung
  • postmaster@lists.fu-berlin.de

Service-Navigation

  • Startseite
  • Listenauswahl

Einrichtung Mailingliste

  • ZEDAT-Portal
  • Mailinglisten Portal