diff --git a/JustAudio.pro b/JustAudio.pro index 87d0795..0ea749c 100644 --- a/JustAudio.pro +++ b/JustAudio.pro @@ -16,10 +16,21 @@ TEMPLATE = app SOURCES += main.cpp\ gui/ui.cpp\ gui/icon.cpp \ - io/aud_file.cpp + io/aud_file.cpp \ + io/conf.cpp \ + io/idm.cpp \ + io/int.cpp HEADERS += gui/ui.h\ gui/icon.h \ - io/aud_file.h + io/aud_file.h \ + io/conf.h \ + io/idm.h \ + io/int.h RESOURCES += icon_files.qrc + +RC_FILE = logo.rc + +DISTFILES += app_logo.ico \ + logo.rc diff --git a/app_logo.ico b/app_logo.ico new file mode 100644 index 0000000..72d8b75 Binary files /dev/null and b/app_logo.ico differ diff --git a/gui/icon.cpp b/gui/icon.cpp index 4e0b8b2..d8146bd 100644 --- a/gui/icon.cpp +++ b/gui/icon.cpp @@ -1,56 +1,64 @@ #include "icon.h" -Icon::Icon(IconType t, QWidget *parent) : QLabel(parent) +Icon::Icon(IconType t, QWidget *parent) : QToolButton(parent) { QRect rect = QApplication::desktop()->screenGeometry(); setMinimumHeight(rect.height() / 40); setMinimumWidth(rect.height() / 40); setCursor(Qt::PointingHandCursor); + setToolButtonStyle(Qt::ToolButtonIconOnly); + setPopupMode(QToolButton::InstantPopup); switch (t) { - case PAUSE_PLAY: stateChanged(QMediaPlayer::StoppedState); break; - case SETTINGS: loadImg(":/settings"); break; - case OPEN: loadImg(":/open"); break; + case PAUSE_PLAY: + { + stateChanged(QMediaPlayer::StoppedState); + setToolTip(tr("Pause/Play")); + + connect(this, SIGNAL(clicked()), this, SLOT(buttonClicked())); + + break; + } + case MENU: + { + loadImg(":/menu"); + setToolTip(tr("Menu")); + + break; + } + case OPEN: + { + loadImg(":/open"); + setToolTip(tr("Open File")); + + connect(this, SIGNAL(clicked()), this, SLOT(buttonClicked())); + + break; + } } type = t; } -void Icon::mouseReleaseEvent(QMouseEvent *event) +void Icon::buttonClicked() { - if (event->button() == Qt::LeftButton) + if (type == PAUSE_PLAY) { - switch (type) + if (playerState == QMediaPlayer::PlayingState) { - case PAUSE_PLAY: + emit pause(); + } + else { - if (playerState == QMediaPlayer::PlayingState) - { - emit pause(); - } - else - { - emit play(); - } - - break; - } - case SETTINGS: - { - emit settings(); - - break; - } - case OPEN: - { - emit open(); - - break; - } + emit play(); } } + else if (type == OPEN) + { + emit open(); + } } void Icon::paintEvent(QPaintEvent *) diff --git a/gui/icon.h b/gui/icon.h index 0c47c57..f0f56f8 100644 --- a/gui/icon.h +++ b/gui/icon.h @@ -2,7 +2,7 @@ #define ICON_H #include -#include +#include #include #include #include @@ -13,7 +13,7 @@ #include #include -class Icon : public QLabel +class Icon : public QToolButton { Q_OBJECT @@ -22,7 +22,7 @@ public: enum IconType { PAUSE_PLAY, - SETTINGS, + MENU, OPEN }; @@ -38,10 +38,13 @@ private: QMediaPlayer::State playerState; QString svgFile; - void mouseReleaseEvent(QMouseEvent *event); void paintEvent(QPaintEvent *); void loadImg(const QString &path); +private slots: + + void buttonClicked(); + signals: void pause(); diff --git a/gui/ui.cpp b/gui/ui.cpp index 8731e5f..c51e9ce 100644 --- a/gui/ui.cpp +++ b/gui/ui.cpp @@ -8,35 +8,34 @@ Ui::Ui(const QStringList &args, QWidget *parent) : QWidget(parent) fileName = new QLabel(this); slider = new QSlider(this); + menu = new QMenu(this); + trayIcon = new QSystemTrayIcon(QIcon(":/logo"), this); + settings = new Icon(Icon::MENU, this); pausePlay = new Icon(Icon::PAUSE_PLAY, this); - settings = new Icon(Icon::SETTINGS, this); open = new Icon(Icon::OPEN, this); player = new QMediaPlayer(this); ioDev = new AudFile(this); + conf = new Conf(this); pressed = false; - QFont fnt = fileName->font(); - QRect rect = QApplication::desktop()->screenGeometry(); + QFont fnt = fileName->font(); fnt.setBold(true); - setMinimumHeight(rect.height() / 6); - setMinimumWidth(rect.width() / 5); - setMaximumHeight(rect.height() / 6); - setMaximumWidth(rect.width() / 5); setStyleSheet("background-color:white;"); - fileName->setText(QApplication::applicationName()); + settings->setMenu(menu); + fileName->setText(tr("Ready")); fileName->setFont(fnt); slider->setOrientation(Qt::Horizontal); - slider->setMinimumWidth((rect.width() / 5) - 100); - btnLayout->addWidget(pausePlay, 0, Qt::AlignCenter); - btnLayout->addSpacing(rect.height() / 40); - btnLayout->addWidget(open, 0, Qt::AlignCenter); - btnLayout->addSpacing(rect.height() / 40); - btnLayout->addWidget(settings, 0, Qt::AlignCenter); - mainLayout->addWidget(fileName, 0, Qt::AlignCenter); - mainLayout->addWidget(slider, 0, Qt::AlignCenter); + trayIcon->show(); + conf->populateOptionsMenu(menu, this); + player->setVolume(conf->getVolume()); + btnLayout->addWidget(pausePlay); + btnLayout->addWidget(open); + btnLayout->addWidget(settings); + mainLayout->addWidget(fileName); + mainLayout->addWidget(slider); mainLayout->addWidget(btnWid, 0, Qt::AlignCenter); connect(pausePlay, SIGNAL(pause()), player, SLOT(pause())); @@ -44,10 +43,11 @@ Ui::Ui(const QStringList &args, QWidget *parent) : QWidget(parent) connect(open, SIGNAL(open()), this, SLOT(openDialog())); connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(error(QMediaPlayer::Error))); connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), pausePlay, SLOT(stateChanged(QMediaPlayer::State))); - connect(player, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64))); connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(posChanged(qint64))); + connect(player, SIGNAL(durationChanged(qint64)), this, SLOT(durChanged(qint64))); connect(slider, SIGNAL(sliderPressed()), this, SLOT(sliderPressed())); connect(slider, SIGNAL(sliderReleased()), this, SLOT(sliderReleased())); + connect(conf, SIGNAL(volume(int)), player, SLOT(setVolume(int))); if (args.size() > 1) { @@ -57,17 +57,30 @@ Ui::Ui(const QStringList &args, QWidget *parent) : QWidget(parent) void Ui::play(const QString &path) { - QFileInfo info(path); - - fileDir = info.path(); - - slider->setMinimum(0); - fileName->setText(info.fileName()); + player->blockSignals(true); player->stop(); - ioDev->close(); - ioDev->openFile(path); - player->setMedia(0, ioDev); - player->play(); + pausePlay->stateChanged(QMediaPlayer::StoppedState); + + if (ioDev->openFile(path)) + { + QFileInfo info(path); + + conf->setLastPath(info.path()); + fileName->setText(info.fileName()); + player->setMedia(0, ioDev); + slider->setValue(0); + slider->setMinimum(0); + pausePlay->stateChanged(QMediaPlayer::PlayingState); + player->play(); + + adjustSize(); + } + else + { + error(QMediaPlayer::ResourceError); + } + + player->blockSignals(false); } void Ui::openDialog() @@ -76,6 +89,7 @@ void Ui::openDialog() fileDialog.setFileMode(QFileDialog::ExistingFile); fileDialog.setNameFilter(tr("Audio Files (*.mp3 *.ogg *.wav *.flac)")); + fileDialog.setDirectory(conf->getLastPath()); if (fileDialog.exec()) { @@ -90,18 +104,26 @@ void Ui::error(QMediaPlayer::Error error) if (error == QMediaPlayer::NoError) { box.setText(tr("An unknown error has occured")); - } - else - { - box.setText(player->errorString()); - } - - if (error == QMediaPlayer::FormatError) - { box.setIcon(QMessageBox::Warning); } - else + else if (error == QMediaPlayer::FormatError) { + box.setText(tr("The format of the media resource isn't fully supported. Playback may still be possible.")); + box.setIcon(QMessageBox::Warning); + } + else if (error == QMediaPlayer::AccessDeniedError) + { + box.setText(tr("The appropriate permissions to play the media resource are not present")); + box.setIcon(QMessageBox::Critical); + } + else if (error == QMediaPlayer::ServiceMissingError) + { + box.setText(tr("A valid playback service was not found, playback cannot proceed.")); + box.setIcon(QMessageBox::Critical); + } + else if (error == QMediaPlayer::ResourceError) + { + box.setText(tr("Media resource couldn't be resolved.")); box.setIcon(QMessageBox::Critical); } @@ -124,20 +146,20 @@ void Ui::posChanged(qint64 pos) { if (!pressed) slider->setSliderPosition(pos); -// if (slider->sliderPosition() == slider->maximum()) -// { -// QTimer::singleShot(750, this, SLOT(nextFile())); -// } + if ((slider->sliderPosition() == slider->maximum()) && conf->nextFile()) + { + QTimer::singleShot(1000, this, SLOT(nextFile())); + } } -void Ui::durationChanged(qint64 len) +void Ui::durChanged(qint64 len) { slider->setMaximum(len); } void Ui::nextFile() { - QDir dir(fileDir); + QDir dir(conf->getLastPath()); QStringList filterList; @@ -155,7 +177,7 @@ void Ui::nextFile() if (pos < list.size()) { - play(fileDir + list[pos]); + play(conf->getLastPath() + QDir::separator() + list[pos]); } } } diff --git a/gui/ui.h b/gui/ui.h index 24534a1..e3b5b95 100644 --- a/gui/ui.h +++ b/gui/ui.h @@ -2,6 +2,7 @@ #define UI_H #include +#include #include #include #include @@ -9,18 +10,20 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include +#include +#include +#include +#include #include "icon.h" #include "../io/aud_file.h" +#include "../io/conf.h" class Ui : public QWidget { @@ -28,15 +31,17 @@ class Ui : public QWidget private: - QLabel *fileName; - QSlider *slider; - QMediaPlayer *player; - AudFile *ioDev; - Icon *pausePlay; - Icon *settings; - Icon *open; - QString fileDir; - bool pressed; + QLabel *fileName; + QSlider *slider; + QMediaPlayer *player; + AudFile *ioDev; + QToolButton *settings; + QSystemTrayIcon *trayIcon; + Conf *conf; + QMenu *menu; + Icon *pausePlay; + Icon *open; + bool pressed; private slots: @@ -44,7 +49,7 @@ private slots: void sliderPressed(); void sliderReleased(); void posChanged(qint64 pos); - void durationChanged(qint64 len); + void durChanged(qint64 len); void openDialog(); void nextFile(); void play(const QString &path); diff --git a/icon_files.qrc b/icon_files.qrc index e0580bf..df5f091 100644 --- a/icon_files.qrc +++ b/icon_files.qrc @@ -1,8 +1,9 @@ - svg/play-button.svg + svg/open.svg svg/pause.svg - svg/list.svg - svg/eject.svg + svg/play.svg + svg/menu.svg + app_logo.ico diff --git a/io/aud_file.cpp b/io/aud_file.cpp index e6d9727..50fa46b 100644 --- a/io/aud_file.cpp +++ b/io/aud_file.cpp @@ -12,12 +12,16 @@ AudFile::~AudFile() bool AudFile::openFile(const QString &path) { + close(); + setFileName(path); bool ret = open(QFile::ReadOnly); if (ret) { + offset = 0; + if (peek(3) == "ID3") { QByteArray header = read(10); @@ -43,15 +47,20 @@ bool AudFile::openFile(const QString &path) } offset += num; - - seek(0); } + + seek(0); } return ret; } -bool AudFile::seek(qint64 pos) +bool AudFile::seek(qint64 off) { - return QFile::seek(pos + offset); + return QFile::seek(offset + off); +} + +qint64 AudFile::size() const +{ + return QFile::size() - offset; } diff --git a/io/aud_file.h b/io/aud_file.h index 5e69d53..5ea927a 100644 --- a/io/aud_file.h +++ b/io/aud_file.h @@ -1,9 +1,11 @@ #ifndef AUD_FILE_H #define AUD_FILE_H +#include #include #include #include +#include class AudFile : public QFile { @@ -17,8 +19,9 @@ public: AudFile(QObject *parent = 0); - bool openFile(const QString &path); - bool seek(qint64 pos); + bool openFile(const QString &path); + bool seek(qint64 off); + qint64 size() const; ~AudFile(); }; diff --git a/io/conf.cpp b/io/conf.cpp new file mode 100644 index 0000000..fe62c99 --- /dev/null +++ b/io/conf.cpp @@ -0,0 +1,150 @@ +#include "io/conf.h" + +MenuItem::MenuItem(const QString &label, QWidget *widget, QObject *parent) : QWidgetAction(parent) +{ + str = label; + wid = widget; +} + +QWidget *MenuItem::createWidget(QWidget *parent) +{ + QWidget *widget = new QWidget(parent); + QHBoxLayout *layout = new QHBoxLayout(widget); + + layout->addWidget(new QLabel(str, parent)); + layout->addStretch(); + layout->addWidget(wid, 0, Qt::AlignRight); + + return widget; +} + +Conf::Conf(QObject *parent) : QObject(parent) +{ + QFile file(confPath(), this); + + QByteArray data; + + if (file.open(QFile::ReadOnly)) + { + data = file.readAll(); + } + + file.close(); + + Idm idm(data, this); + + idm.rdHeader(); + + QByteArray pathBa = idm.value(LAST_PATH); + QByteArray nextBa = idm.value(NEXT_FILE); + QByteArray volBa = idm.value(VOLUME); + + if (!pathBa.isEmpty()) lastPath = pathBa; + else lastPath = QDir::homePath(); + if (!nextBa.isEmpty()) nextFileState = (nextBa == "Y"); + else nextFileState = true; + if (!volBa.isEmpty()) volumeValue = rdInt(volBa); + else volumeValue = 50; +} + +void Conf::sync() +{ + Idm idm(this); + + idm.wrHeader(); + idm.insert(LAST_PATH, lastPath.toUtf8()); + idm.insert(VOLUME, wrInt(volumeValue)); + + if (nextFileState) idm.insert(NEXT_FILE, "Y"); + else idm.insert(NEXT_FILE, "N"); + + QFile file(confPath(), this); + + file.open(QFile::WriteOnly | QFile::Truncate); + file.write(idm.getBuff()); +} + +void Conf::populateOptionsMenu(QMenu *menu, QWidget *parent) +{ + QWidget *volWidget = new QWidget(parent); + QHBoxLayout *volLayout = new QHBoxLayout(volWidget); + QSlider *volSlider = new QSlider(parent); + QCheckBox *nextBox = new QCheckBox(parent); + + volSlider->setMinimum(0); + volSlider->setMaximum(100); + volSlider->setValue(getVolume()); + volSlider->setOrientation(Qt::Horizontal); + volLayout->addWidget(new QLabel("-")); + volLayout->addWidget(volSlider); + volLayout->addWidget(new QLabel("+")); + nextBox->setText(""); + nextBox->setChecked(nextFile()); + + connect(volSlider, SIGNAL(valueChanged(int)), this, SLOT(setVolume(int))); + connect(volSlider, SIGNAL(valueChanged(int)), this, SIGNAL(volume(int))); + connect(nextBox, SIGNAL(clicked(bool)), this, SLOT(setNextFile(bool))); + + menu->addAction(new MenuItem(tr("Volume"), volWidget, this)); + menu->addAction(new MenuItem(tr("Auto play next file in directory"), nextBox, this)); +} + +void Conf::setLastPath(const QString &path) +{ + lastPath = path; sync(); +} + +void Conf::setNextFile(bool state) +{ + nextFileState = state; sync(); +} + +void Conf::setVolume(int value) +{ + emit volume(value); + + volumeValue = value; sync(); +} + +QString Conf::getLastPath() +{ + if (!QDir(lastPath).exists()) + { + lastPath = QDir::homePath(); + } + + return lastPath; +} + +bool Conf::nextFile() +{ + return nextFileState; +} + +int Conf::getVolume() +{ + return volumeValue; +} + +QString Conf::confPath() +{ + QString path = QDir::homePath() + '/'; + +#ifndef Q_OS_WIN32 + + path.append("/.config/"); + +#else + + path.append("AppData/Local/"); + +#endif + + QDir dir; + + path.append(QApplication::applicationName() + '/'); + + dir.mkpath(path); + + return path + "conf.idm"; +} diff --git a/io/conf.h b/io/conf.h new file mode 100644 index 0000000..97e6ba9 --- /dev/null +++ b/io/conf.h @@ -0,0 +1,74 @@ +#ifndef CONF_H +#define CONF_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "idm.h" + +class MenuItem : public QWidgetAction +{ + Q_OBJECT + +private: + + QString str; + QWidget *wid; + + QWidget *createWidget(QWidget *parent); + +public: + + MenuItem(const QString &label, QWidget *widget, QObject *parent = 0); +}; + +class Conf : public QObject +{ + Q_OBJECT + +private: + + enum DataType + { + LAST_PATH = 1, + NEXT_FILE, + VOLUME + }; + + QString lastPath; + bool nextFileState; + int volumeValue; + + void sync(); + QString confPath(); + +public slots: + + void setLastPath(const QString &path); + void setNextFile(bool state); + void setVolume(int value); + +public: + + QString getLastPath(); + bool nextFile(); + void populateOptionsMenu(QMenu *menu, QWidget *parent); + int getVolume(); + + Conf(QObject *parent = 0); + +signals: + + void volume(int); +}; + +#endif // CONF_H diff --git a/io/idm.cpp b/io/idm.cpp new file mode 100644 index 0000000..7bd6794 --- /dev/null +++ b/io/idm.cpp @@ -0,0 +1,432 @@ +#include "idm.h" + +const QByteArray Idm::TAG = "IDM"; +const int Idm::MAX_MAJOR = 1; +const int Idm::MAX_MINOR = 0; + int Idm::DEFAULT_INT_SIZE = 3; + int Idm::DEFAULT_FLAGS = 1; // FIXED_KEY_LEN + int Idm::DEFAULT_KEY_LEN = 1; + int Idm::CURRENT_MAJOR = Idm::MAX_MAJOR; + int Idm::CURRENT_MINOR = Idm::MAX_MINOR; + +Idm::Idm(const QByteArray &data, QObject *parent) : QObject(parent) +{ + buffPtr = data; + + init(); +} + +Idm::Idm(QObject *parent) : QObject(parent) +{ + init(); +} + +void Idm::init() +{ + header = 0; + intSize = DEFAULT_INT_SIZE; + keyLen = DEFAULT_KEY_LEN; + flags = DEFAULT_FLAGS; +} + +void Idm::loadData(const QByteArray &data) +{ + op(RELOAD, data); +} + +QByteArray &Idm::getBuff() +{ + op(GET_BUFF, QByteArray(), QByteArray(), new QByteArray()); + + return buffPtr; +} + +bool Idm::rdHeader() +{ + return rdExHeader(buffPtr); +} + +bool Idm::rdExHeader(const QByteArray &data) +{ + bool ret; + + op(RD_HEADER, data, QByteArray(), 0, 0, 0, &ret); + + return ret; +} + +bool Idm::rdExHeader(const QByteArray &data, int &major, int &minor, int &intSz, int &flgs, int &keyLen) +{ + bool ret = false; + + if (data.startsWith(TAG)) + { + int pos = TAG.size(); + + major = rdInt(data.mid(pos++, 1)); + minor = rdInt(data.mid(pos++, 1)); + intSz = rdInt(data.mid(pos++, 1)); + keyLen = rdInt(data.mid(pos++, 1)); + flgs = rdInt(data.mid(pos, 4)); + + if ((major <= MAX_MAJOR) && (minor <= MAX_MINOR)) + { + ret = true; + } + } + + return ret; +} + +bool Idm::verifyExHeader(const QByteArray &data, int major, int minor) +{ + bool ret = false; + + if (data.startsWith(TAG) && (data.size() == 11)) + { + int pos = TAG.size(); + int ma = rdInt(data.mid(pos++, 1)); + int mi = rdInt(data.mid(pos++, 1)); + + ret = ((ma <= major) && (mi <= minor)); + } + + return ret; +} + +QByteArray Idm::buildHeader(int major, int minor, int intSz, int flgs, int keyLen) +{ + QByteArray ret = TAG; + + ret.append(wrInt(major, 1)); + ret.append(wrInt(minor, 1)); + ret.append(wrInt(intSz, 1)); + ret.append(wrInt(keyLen, 1)); + ret.append(wrInt(flgs, 4)); + + return ret; +} + +void Idm::setKeyLen(int len) +{ + op(SET_KEY_LEN, QByteArray(), QByteArray(), 0, len); +} + +void Idm::setFlags(int flgs) +{ + op(SET_FLAGS, QByteArray(), QByteArray(), 0, flgs); +} + +void Idm::wrHeader() +{ + op(WR_HEADER); +} + +void Idm::setIntSize(int bytes) +{ + op(SET_INT_SIZE, QByteArray(), QByteArray(), 0, bytes); +} + +void Idm::setVersion(int major, int minor) +{ + op(SET_VERSION, QByteArray(), QByteArray(), 0, major, minor); +} + +QByteArray Idm::rdData(int addr, int len, bool *ret) +{ + bool ok = false; + + if ((addr < buffPtr.size()) && (addr >= 0)) + { + if ((len + addr) <= buffPtr.size()) + { + ok = true; + } + } + + if (ret) *ret = ok; + + if (ok) + { + return QByteArray::fromRawData(buffPtr.data() + addr, len); + } + else + { + return QByteArray(); + } +} + +bool Idm::findKey(int &addr, int &dataLen, const QByteArray &key) +{ + bool ok = true; + bool found = false; + + while(addr < buffPtr.size() && ok) + { + int keySize; + + if (flags & FIXED_KEY_LEN) + { + keySize = keyLen; + } + else + { + keySize = rdInt(rdData(addr, intSize, &ok)); + + addr += intSize; + } + + if (ok) + { + if (key == rdData(addr, keySize, &ok)) + { + found = true; + } + + addr += keySize; + + if (ok) + { + dataLen = rdInt(rdData(addr, intSize, &ok)); + + addr += intSize; + + if (found && ok) + { + break; + } + else + { + addr += dataLen; + } + } + } + } + + return found; +} + +QByteArray Idm::value(const QByteArray &key) +{ + QByteArray ret; + + op(RD_VALUE, key, QByteArray(), &ret); + + return ret; +} + +QByteArray Idm::value(quint64 key) +{ + int keySize; + + if (flags & FIXED_KEY_LEN) keySize = keyLen; + else keySize = intSize; + + return value(wrInt(key, keySize)); +} + +quint64 Idm::intValue(const QByteArray &key) +{ + return rdInt(value(key)); +} + +quint64 Idm::intValue(quint64 key) +{ + return rdInt(value(key)); +} + +bool Idm::remove(const QByteArray &key) +{ + bool ret; + + op(RM_VALUE, key, QByteArray(), 0, 0, 0, &ret); + + return ret; +} + +bool Idm::remove(quint64 key) +{ + int keySize; + + if (flags & FIXED_KEY_LEN) keySize = keyLen; + else keySize = intSize; + + return remove(wrInt(key, keySize)); +} + +bool Idm::insert(const QByteArray &key, const QByteArray &data) +{ + bool ret; + + op(WR_VALUE, key, data, 0, 0, 0, &ret); + + return ret; +} + +bool Idm::insert(quint64 key, quint64 num) +{ + int keySize; + + if (flags & FIXED_KEY_LEN) keySize = keyLen; + else keySize = intSize; + + return insert(wrInt(key, keySize), wrInt(num, intSize)); +} + +bool Idm::insert(quint64 key, const QByteArray &data) +{ + int keySize; + + if (flags & FIXED_KEY_LEN) keySize = keyLen; + else keySize = intSize; + + return insert(wrInt(key, keySize), data); +} + +void Idm::op(Operation opr, + const QByteArray &inA, + const QByteArray &inB, + QByteArray *out, + int intA, + int intB, + bool *ok) +{ + QMutex m; + + m.lock(); + + switch(opr) + { + case SET_KEY_LEN: + { + keyLen = intA; break; + } + case SET_FLAGS: + { + flags = intA; break; + } + case GET_BUFF: + { + out = &buffPtr; break; + } + case RELOAD: + { + buffPtr = inA; break; + } + case SET_INT_SIZE: + { + intSize = intA; break; + } + case SET_VERSION: + { + CURRENT_MAJOR = intA; + CURRENT_MINOR = intB; + + break; + } + case WR_HEADER: + { + if (buffPtr.startsWith(TAG)) + { + int pos = TAG.size(); + + buffPtr.replace(pos++, 1, wrInt(CURRENT_MAJOR, 1)); + buffPtr.replace(pos++, 1, wrInt(CURRENT_MINOR, 1)); + buffPtr.replace(pos++, 1, wrInt(intSize, 1)); + buffPtr.replace(pos++, 1, wrInt(keyLen, 1)); + buffPtr.replace(pos++, 4, wrInt(flags, 4)); + } + else + { + buffPtr.insert(0, wrInt(flags, 4)); + buffPtr.insert(0, wrInt(keyLen, 1)); + buffPtr.insert(0, wrInt(intSize, 1)); + buffPtr.insert(0, wrInt(CURRENT_MINOR, 1)); + buffPtr.insert(0, wrInt(CURRENT_MAJOR, 1)); + buffPtr.insert(0, TAG); + } + + header = 8 + TAG.size(); + + break; + } + case RD_HEADER: + { + *ok = rdExHeader(inA, CURRENT_MAJOR, CURRENT_MINOR, intSize, flags, keyLen); + + if (*ok) header = 8 + TAG.size(); + + break; + } + case RD_VALUE: + { + int pos = header; + int len = 0; + + if (findKey(pos, len, inA)) + { + out->clear(); + out->append(buffPtr.mid(pos, len)); + } + + break; + } + case RM_VALUE: + { + int pos = header; + int len = 0; + + *ok = false; + + if (findKey(pos, len, inA)) + { + if (flags & FIXED_KEY_LEN) + { + pos -= keyLen + intSize; + len += keyLen + intSize; + } + else + { + pos -= inA.size() + (intSize * 2); + len += inA.size() + (intSize * 2); + } + + buffPtr.remove(pos, len); + + *ok = true; + } + + break; + } + case WR_VALUE: + { + *ok = false; + + remove(inA); + + if (flags & FIXED_KEY_LEN) + { + if (inA.size() == keyLen) + { + buffPtr.append(inA + wrInt(inB.size(), intSize) + inB); + + *ok = true; + } + } + else + { + if (!inA.isEmpty()) + { + buffPtr.append(wrInt(inA.size(), intSize) + inA); + buffPtr.append(wrInt(inB.size(), intSize) + inB); + + *ok = true; + } + } + + break; + } + } + + m.unlock(); +} diff --git a/io/idm.h b/io/idm.h new file mode 100644 index 0000000..67050f5 --- /dev/null +++ b/io/idm.h @@ -0,0 +1,92 @@ +#ifndef IDM_H +#define IDM_H + +#include +#include +#include + +#include "int.h" + +class Idm : public QObject +{ + Q_OBJECT + +public: + + enum Flags + { + FIXED_KEY_LEN = 1 + }; + + static const QByteArray TAG; + static const int MAX_MAJOR; + static const int MAX_MINOR; + static int CURRENT_MAJOR; + static int CURRENT_MINOR; + static int DEFAULT_INT_SIZE; + static int DEFAULT_FLAGS; + static int DEFAULT_KEY_LEN; + + static bool verifyExHeader(const QByteArray &data, int major, int minor); + static bool rdExHeader(const QByteArray &data, int &major, int &minor, int &intSz, int &flgs, int &keyLen); + static QByteArray buildHeader(int major, int minor, int intSz, int flgs, int keyLen); + + explicit Idm(const QByteArray &data, QObject *parent = 0); + explicit Idm(QObject *parent = 0); + + void setVersion(int major, int minor); + void setFlags(int flgs); + void setIntSize(int bytes); + void wrHeader(); + void setKeyLen(int len); + void loadData(const QByteArray &data); + bool insert(const QByteArray &key, const QByteArray &data); + bool insert(quint64 key, quint64 num); + bool insert(quint64 key, const QByteArray &data); + bool remove(const QByteArray &key); + bool remove(quint64 key); + bool rdHeader(); + bool rdExHeader(const QByteArray &data); + quint64 intValue(quint64 key); + quint64 intValue(const QByteArray &key); + QByteArray value(const QByteArray &key); + QByteArray value(quint64 key); + QByteArray &getBuff(); + +private: + + enum Operation + { + RELOAD, + GET_BUFF, + RD_HEADER, + WR_HEADER, + SET_KEY_LEN, + SET_FLAGS, + SET_INT_SIZE, + SET_VERSION, + RD_VALUE, + WR_VALUE, + RM_VALUE + }; + + QByteArray buffPtr; + int header; + int intSize; + int keyLen; + int flags; + + void op(Operation opr, + const QByteArray &inA = QByteArray(), + const QByteArray &inB = QByteArray(), + QByteArray *out = 0, + int intA = 0, + int intB = 0, + bool *ok = 0); + + void init(); + bool findKey(int &addr, int &dataLen, const QByteArray &key); + QByteArray rdData(int, int, bool *ok = 0); +}; + +#endif // IDM_H diff --git a/io/int.cpp b/io/int.cpp new file mode 100644 index 0000000..51b2f12 --- /dev/null +++ b/io/int.cpp @@ -0,0 +1,58 @@ +#include "int.h" + +quint64 rdInt(const QByteArray &data) +{ + quint64 out = 0; + quint64 outBit = 1; + + for (int i = data.size() - 1; i >= 0; --i) + { + int byte = data[i]; + + for (int inBit = 1; inBit <= 128; inBit *= 2, outBit *= 2) + { + if ((byte & inBit) != 0) out |= outBit; + } + } + + return out; +} + +float rdFloat(const QByteArray &data) +{ + return data.toFloat(); +} + +QByteArray wrInt(quint64 value, int intSize) +{ + QByteArray out; + quint64 inBit = 1; + + while (value != 0) + { + int byte = 0; + + for (int outBit = 1; outBit <= 128; outBit *= 2, inBit *= 2) + { + if (value & inBit) + { + byte |= outBit; + value ^= inBit; + } + } + + out.insert(0, byte); + } + + return out.rightJustified(intSize, 0); +} + +QByteArray wrInt(quint64 value) +{ + return wrInt(value, INT_SIZE); +} + +QByteArray wrFloat(float value) +{ + return QByteArray().setNum(value); +} diff --git a/io/int.h b/io/int.h new file mode 100644 index 0000000..c18ad02 --- /dev/null +++ b/io/int.h @@ -0,0 +1,15 @@ +#ifndef INT_H +#define INT_H + +#include +#include + +#define INT_SIZE 6 + +float rdFloat(const QByteArray &data); +quint64 rdInt(const QByteArray &data); +QByteArray wrInt(quint64 value); +QByteArray wrInt(quint64 value, int); +QByteArray wrFloat(float value); + +#endif // INT_H diff --git a/logo.rc b/logo.rc new file mode 100644 index 0000000..725c431 --- /dev/null +++ b/logo.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "app_logo.ico" diff --git a/svg/eject.svg b/svg/eject.svg deleted file mode 100644 index 55b047a..0000000 --- a/svg/eject.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/svg/list.svg b/svg/list.svg deleted file mode 100644 index f35883c..0000000 --- a/svg/list.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/svg/menu.svg b/svg/menu.svg new file mode 100644 index 0000000..f435b85 --- /dev/null +++ b/svg/menu.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/svg/open.svg b/svg/open.svg new file mode 100644 index 0000000..9406a3a --- /dev/null +++ b/svg/open.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/svg/pause.svg b/svg/pause.svg index fad0570..e7b21b1 100644 --- a/svg/pause.svg +++ b/svg/pause.svg @@ -1,41 +1,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/svg/play-button.svg b/svg/play-button.svg deleted file mode 100644 index 32fad65..0000000 --- a/svg/play-button.svg +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/svg/play.svg b/svg/play.svg new file mode 100644 index 0000000..bbdf169 --- /dev/null +++ b/svg/play.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file