Reorganized project to avoid the ".pro not found" by having all the
pro files in the same directory. With this change the android library now builds properly. This also fixes the parallel compilation problem that happened when building using +8 cores.
35
android/android.pro
Normal file
@@ -0,0 +1,35 @@
|
||||
include(../config.pri)
|
||||
include(../common/defines.pri)
|
||||
|
||||
TARGET = qcma_android
|
||||
TEMPLATE=app
|
||||
LIBS += -L../common -lqcma_common
|
||||
|
||||
# this library needs to link statically their deps but Qt doesn't pass --static to PKGCONFIG
|
||||
QMAKE_CXXFLAGS += $$system(pkg-config --static --cflags libvitamtp libavformat libavcodec libavutil libswscale)
|
||||
LIBS += $$system(pkg-config --static --libs libvitamtp libavformat libavcodec libavutil libswscale)
|
||||
|
||||
SOURCES += \
|
||||
main_android.cpp
|
||||
# headlessmanager.cpp
|
||||
|
||||
#HEADERS += \
|
||||
# headlessmanager.h
|
||||
|
||||
DISTFILES += \
|
||||
../android-src/gradle/wrapper/gradle-wrapper.jar \
|
||||
../android-src/AndroidManifest.xml \
|
||||
../android-src/gradlew.bat \
|
||||
../android-src/res/values/libs.xml \
|
||||
../android-src/build.gradle \
|
||||
../android-src/gradle/wrapper/gradle-wrapper.properties \
|
||||
../android-src/gradlew \
|
||||
android-src/gradle/wrapper/gradle-wrapper.jar \
|
||||
android-src/AndroidManifest.xml \
|
||||
android-src/gradlew.bat \
|
||||
android-src/res/values/libs.xml \
|
||||
android-src/build.gradle \
|
||||
android-src/gradle/wrapper/gradle-wrapper.properties \
|
||||
android-src/gradlew
|
||||
|
||||
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android-src
|
191
android/headlessmanager.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmaclient.h"
|
||||
#include "cmautils.h"
|
||||
#include "sqlitedb.h"
|
||||
#include "qlistdb.h"
|
||||
#include "headlessmanager.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QSettings>
|
||||
#include <QTextStream>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <vitamtp.h>
|
||||
|
||||
int HeadlessManager::sighup_fd[2];
|
||||
int HeadlessManager::sigterm_fd[2];
|
||||
|
||||
HeadlessManager::HeadlessManager(QObject *obj_parent) :
|
||||
QObject(obj_parent)
|
||||
{
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighup_fd))
|
||||
qFatal("Couldn't create HUP socketpair");
|
||||
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigterm_fd))
|
||||
qFatal("Couldn't create TERM socketpair");
|
||||
|
||||
sn_hup = new QSocketNotifier(sighup_fd[1], QSocketNotifier::Read, this);
|
||||
connect(sn_hup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
|
||||
sn_term = new QSocketNotifier(sigterm_fd[1], QSocketNotifier::Read, this);
|
||||
connect(sn_term, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
|
||||
}
|
||||
|
||||
HeadlessManager::~HeadlessManager()
|
||||
{
|
||||
VitaMTP_Cleanup();
|
||||
delete m_db;
|
||||
}
|
||||
|
||||
void HeadlessManager::refreshDatabase()
|
||||
{
|
||||
if(m_db->load()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream(stdout) << "Database scan has started" << endl;
|
||||
|
||||
if(!m_db->rescan()) {
|
||||
qWarning("No PS Vita system has been registered");
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessManager::start()
|
||||
{
|
||||
if(VitaMTP_Init() < 0) {
|
||||
qCritical("Cannot initialize VitaMTP library");
|
||||
return;
|
||||
}
|
||||
|
||||
if(QSettings().value("useMemoryStorage", true).toBool()) {
|
||||
m_db = new QListDB();
|
||||
} else {
|
||||
m_db = new SQLiteDB();
|
||||
}
|
||||
|
||||
// initializing database for the first use
|
||||
refreshDatabase();
|
||||
|
||||
// send a signal when the update is finished
|
||||
connect(m_db, SIGNAL(updated(int)), this, SIGNAL(databaseUpdated(int)));
|
||||
|
||||
thread_count = 0;
|
||||
qDebug("Starting cma threads");
|
||||
CmaClient *client;
|
||||
QSettings settings;
|
||||
|
||||
if(!settings.value("disableUSB", false).toBool()) {
|
||||
|
||||
if(!belongsToGroup("vitamtp"))
|
||||
qCritical() << tr("This user doesn't belong to the vitamtp group, there could be a problem while reading the USB bus.");
|
||||
|
||||
usb_thread = new QThread();
|
||||
client = new CmaClient(m_db);
|
||||
usb_thread->setObjectName("usb_thread");
|
||||
connect(usb_thread, SIGNAL(started()), client, SLOT(connectUsb()));
|
||||
connect(client, SIGNAL(finished()), usb_thread, SLOT(quit()), Qt::DirectConnection);
|
||||
connect(usb_thread, SIGNAL(finished()), usb_thread, SLOT(deleteLater()));
|
||||
connect(usb_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
|
||||
connect(usb_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
|
||||
|
||||
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||
|
||||
client->moveToThread(usb_thread);
|
||||
usb_thread->start();
|
||||
thread_count++;
|
||||
}
|
||||
|
||||
if(!settings.value("disableWireless", false).toBool()) {
|
||||
CmaBroadcast *broadcast = new CmaBroadcast(this);
|
||||
wireless_thread = new QThread();
|
||||
client = new CmaClient(m_db, broadcast);
|
||||
wireless_thread->setObjectName("wireless_thread");
|
||||
connect(wireless_thread, SIGNAL(started()), client, SLOT(connectWireless()));
|
||||
connect(client, SIGNAL(finished()), wireless_thread, SLOT(quit()), Qt::DirectConnection);
|
||||
connect(wireless_thread, SIGNAL(finished()), wireless_thread, SLOT(deleteLater()));
|
||||
connect(wireless_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
|
||||
connect(wireless_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
|
||||
|
||||
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||
|
||||
client->moveToThread(wireless_thread);
|
||||
wireless_thread->start();
|
||||
thread_count++;
|
||||
}
|
||||
|
||||
if(thread_count == 0) {
|
||||
qCritical("You must enable at least USB or Wireless monitoring");
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessManager::receiveMessage(QString message)
|
||||
{
|
||||
QTextStream(stdout) << message << endl;
|
||||
}
|
||||
|
||||
void HeadlessManager::stop()
|
||||
{
|
||||
if(CmaClient::stop() < 0) {
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessManager::threadStopped()
|
||||
{
|
||||
mutex.lock();
|
||||
if(--thread_count == 0) {
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void HeadlessManager::hupSignalHandler(int)
|
||||
{
|
||||
char a = 1;
|
||||
::write(sighup_fd[0], &a, sizeof(a));
|
||||
}
|
||||
|
||||
void HeadlessManager::termSignalHandler(int)
|
||||
{
|
||||
char a = 1;
|
||||
::write(sigterm_fd[0], &a, sizeof(a));
|
||||
}
|
||||
|
||||
void HeadlessManager::handleSigTerm()
|
||||
{
|
||||
sn_term->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sigterm_fd[1], &tmp, sizeof(tmp));
|
||||
|
||||
stop();
|
||||
|
||||
sn_term->setEnabled(true);
|
||||
}
|
||||
|
||||
void HeadlessManager::handleSigHup()
|
||||
{
|
||||
sn_hup->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sighup_fd[1], &tmp, sizeof(tmp));
|
||||
|
||||
refreshDatabase();
|
||||
|
||||
sn_hup->setEnabled(true);
|
||||
}
|
76
android/headlessmanager.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESSMANAGER_H
|
||||
#define HEADLESSMANAGER_H
|
||||
|
||||
#include "database.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QSocketNotifier>
|
||||
|
||||
class HeadlessManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HeadlessManager(QObject *parent = 0);
|
||||
~HeadlessManager();
|
||||
|
||||
void start();
|
||||
|
||||
// unix signal handlers
|
||||
static void hupSignalHandler(int);
|
||||
static void termSignalHandler(int);
|
||||
|
||||
private:
|
||||
int thread_count;
|
||||
QMutex mutex;
|
||||
|
||||
Database *m_db;
|
||||
|
||||
QThread *usb_thread;
|
||||
QThread *wireless_thread;
|
||||
|
||||
// signal handling
|
||||
static int sighup_fd[2];
|
||||
static int sigterm_fd[2];
|
||||
|
||||
QSocketNotifier *sn_hup;
|
||||
QSocketNotifier *sn_term;
|
||||
|
||||
signals:
|
||||
void stopped();
|
||||
void databaseUpdated(int count);
|
||||
|
||||
public slots:
|
||||
void refreshDatabase();
|
||||
void stop();
|
||||
|
||||
// Qt signal handlers
|
||||
void handleSigHup();
|
||||
void handleSigTerm();
|
||||
|
||||
private slots:
|
||||
void threadStopped();
|
||||
void receiveMessage(QString message);
|
||||
};
|
||||
|
||||
#endif // HEADLESSMANAGER_H
|
122
android/main_android.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QLibraryInfo>
|
||||
#include <QLocale>
|
||||
#include <QStringList>
|
||||
#include <QTextCodec>
|
||||
#include <QThread>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <vitamtp.h>
|
||||
|
||||
#include "headlessmanager.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
static void noDebugOutput(QtMsgType type, const QMessageLogContext &, const QString & msg)
|
||||
{
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
const char *message = localMsg.constData();
|
||||
#else
|
||||
static void noDebugOutput(QtMsgType type, const char *message)
|
||||
{
|
||||
#endif
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
fprintf(stderr, "Warning: %s\n", message);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
fprintf(stderr, "Critical: %s\n", message);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
fprintf(stderr, "Fatal: %s\n", message);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
// FIXME: libmtp sends SIGPIPE if a socket write fails crashing the whole app
|
||||
// the proper fix is to libmtp to handle the cancel properly or ignoring
|
||||
// SIGPIPE on the socket
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if(app.arguments().contains("--with-debug")) {
|
||||
VitaMTP_Set_Logging(VitaMTP_DEBUG);
|
||||
} else if(app.arguments().contains("--verbose")) {
|
||||
VitaMTP_Set_Logging(VitaMTP_VERBOSE);
|
||||
} else {
|
||||
VitaMTP_Set_Logging(VitaMTP_NONE);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
qInstallMessageHandler(noDebugOutput);
|
||||
#else
|
||||
qInstallMsgHandler(noDebugOutput);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
|
||||
QTextStream(stdout) << "Starting Qcma " << QCMA_VER << endl;
|
||||
|
||||
QTranslator translator;
|
||||
QString locale = QLocale().system().name();
|
||||
qDebug() << "Current locale:" << locale;
|
||||
|
||||
if(app.arguments().contains("--set-locale")) {
|
||||
int index = app.arguments().indexOf("--set-locale");
|
||||
if(index + 1 < app.arguments().length()) {
|
||||
qDebug("Enforcing locale: %s", app.arguments().at(index + 1).toUtf8().data());
|
||||
locale = app.arguments().at(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(translator.load("qcma_" + locale, ":/resources/translations")) {
|
||||
app.installTranslator(&translator);
|
||||
} else {
|
||||
qWarning() << "Cannot load translation for locale:" << locale;
|
||||
}
|
||||
|
||||
QTranslator system_translator;
|
||||
system_translator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||
app.installTranslator(&system_translator);
|
||||
|
||||
qDebug("Starting main thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
|
||||
|
||||
// set the organization/application for QSettings to work properly
|
||||
app.setOrganizationName("codestation");
|
||||
app.setApplicationName("qcma");
|
||||
|
||||
//HeadlessManager manager;
|
||||
|
||||
// receive the message from another process
|
||||
//QObject::connect(&app, SIGNAL(messageAvailable(QString)), &manager, SLOT(receiveMessage(QString)));
|
||||
|
||||
//manager.start();
|
||||
|
||||
return app.exec();
|
||||
}
|
1
android/qtandroidservice.cpp
Normal file
@@ -0,0 +1 @@
|
||||
|
36
appindicator/appindicator.pro
Normal file
@@ -0,0 +1,36 @@
|
||||
include(../config.pri)
|
||||
include(../gui/defines.pri)
|
||||
|
||||
TARGET = qcma_appindicator
|
||||
TEMPLATE = lib
|
||||
CONFIG += plugin link_pkgconfig
|
||||
DEFINES += QCMA_TRAYINDICATOR_LIBRARY
|
||||
QT += gui widgets
|
||||
|
||||
QT_CONFIG -= no-pkg-config
|
||||
|
||||
PKGCONFIG = appindicator-0.1 libnotify
|
||||
|
||||
SOURCES += \
|
||||
unityindicator.cpp
|
||||
|
||||
HEADERS += \
|
||||
trayindicator.h \
|
||||
unityindicator.h
|
||||
|
||||
CXXFLAGS_WARNINGS = -Wall -Wextra -Wshadow -Wcast-align -Wctor-dtor-privacy \
|
||||
-Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations \
|
||||
-Wmissing-include-dirs -Woverloaded-virtual -Wredundant-decls \
|
||||
-Wstrict-overflow=5 -Wundef -Wno-unused -Wno-missing-field-initializers \
|
||||
-Wno-format-nonliteral
|
||||
|
||||
QMAKE_CXXFLAGS += -Wno-write-strings -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS $$CXXFLAGS_WARNINGS
|
||||
|
||||
DATADIR = $$PREFIX/share
|
||||
|
||||
actions64.path = $$DATADIR/icons/hicolor/64x64/actions
|
||||
actions64.files += resources/images/qcma_on.png
|
||||
actions64.files += resources/images/qcma_off.png
|
||||
|
||||
target.path = /usr/lib/qcma
|
||||
INSTALLS += target actions64
|
1
appindicator/trayindicator.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../gui/trayindicator.h
|
201
appindicator/unityindicator.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "unityindicator.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QStandardPaths>
|
||||
#else
|
||||
#include <QDesktopServices>
|
||||
#define QStandardPaths QDesktopServices
|
||||
#define writableLocation storageLocation
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QVector>
|
||||
|
||||
#undef signals
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <libnotify/notify.h>
|
||||
|
||||
void optionsIndicator(GtkMenu *menu, gpointer data);
|
||||
void reloadIndicator(GtkMenu *menu, gpointer data);
|
||||
void backupIndicator(GtkMenu *menu, gpointer data);
|
||||
void aboutIndicator(GtkMenu *menu, gpointer data);
|
||||
void aboutQtIndicator(GtkMenu *menu, gpointer data);
|
||||
void quitIndicator(GtkMenu *menu, gpointer data);
|
||||
}
|
||||
|
||||
#define signals public
|
||||
|
||||
UnityIndicator::UnityIndicator(QWidget *obj_parent) :
|
||||
TrayIndicator(obj_parent)
|
||||
{
|
||||
notify_init("qcma");
|
||||
}
|
||||
|
||||
UnityIndicator::~UnityIndicator()
|
||||
{
|
||||
notify_uninit();
|
||||
for(QVector<QPair<gpointer, gulong> >::iterator it = m_handlers.begin(); it != m_handlers.end(); ++it)
|
||||
{
|
||||
g_signal_handler_disconnect(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void optionsIndicator(GtkMenu *, gpointer data)
|
||||
{
|
||||
UnityIndicator *m_this = reinterpret_cast<UnityIndicator *>(data);
|
||||
emit m_this->openConfig();
|
||||
}
|
||||
|
||||
void reloadIndicator(GtkMenu *, gpointer data)
|
||||
{
|
||||
UnityIndicator *m_this = reinterpret_cast<UnityIndicator *>(data);
|
||||
emit m_this->refreshDatabase();
|
||||
}
|
||||
|
||||
void backupIndicator(GtkMenu *, gpointer data)
|
||||
{
|
||||
UnityIndicator *m_this = reinterpret_cast<UnityIndicator *>(data);
|
||||
emit m_this->openManager();
|
||||
}
|
||||
|
||||
void aboutIndicator(GtkMenu *, gpointer data)
|
||||
{
|
||||
UnityIndicator *m_this = reinterpret_cast<UnityIndicator *>(data);
|
||||
emit m_this->showAboutDialog();
|
||||
}
|
||||
|
||||
void aboutQtIndicator(GtkMenu *, gpointer data)
|
||||
{
|
||||
UnityIndicator *m_this = reinterpret_cast<UnityIndicator *>(data);
|
||||
emit m_this->showAboutQt();
|
||||
}
|
||||
|
||||
void quitIndicator(GtkMenu *, gpointer data)
|
||||
{
|
||||
UnityIndicator *m_this = reinterpret_cast<UnityIndicator *>(data);
|
||||
emit m_this->stopServer();
|
||||
}
|
||||
|
||||
void UnityIndicator::init()
|
||||
{
|
||||
GtkWidget *menu = gtk_menu_new();
|
||||
|
||||
GtkWidget *options = gtk_menu_item_new_with_label(qPrintable(tr("Settings")));
|
||||
GtkWidget *reload = gtk_menu_item_new_with_label(qPrintable(tr("Refresh database")));
|
||||
GtkWidget *backup = gtk_menu_item_new_with_label(qPrintable(tr("Backup Manager")));
|
||||
GtkWidget *separator1 = gtk_separator_menu_item_new();
|
||||
GtkWidget *about = gtk_menu_item_new_with_label(qPrintable(tr("About QCMA")));
|
||||
GtkWidget *about_qt = gtk_menu_item_new_with_label(qPrintable(tr("About Qt")));
|
||||
GtkWidget *separator2 = gtk_separator_menu_item_new();
|
||||
GtkWidget *quit = gtk_menu_item_new_with_label(qPrintable(tr("Quit")));
|
||||
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), options);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), reload);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), backup);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator1);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), about);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), about_qt);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator2);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), quit);
|
||||
|
||||
gulong gobject_handler;
|
||||
gobject_handler = g_signal_connect(options, "activate", G_CALLBACK(optionsIndicator), this);
|
||||
m_handlers.append(QPair<gpointer, gulong>(options, gobject_handler));
|
||||
gobject_handler = g_signal_connect(reload, "activate", G_CALLBACK(reloadIndicator), this);
|
||||
m_handlers.append(QPair<gpointer, gulong>(reload, gobject_handler));
|
||||
gobject_handler = g_signal_connect(backup, "activate", G_CALLBACK(backupIndicator), this);
|
||||
m_handlers.append(QPair<gpointer, gulong>(backup, gobject_handler));
|
||||
gobject_handler = g_signal_connect(about, "activate", G_CALLBACK(aboutIndicator), this);
|
||||
m_handlers.append(QPair<gpointer, gulong>(about, gobject_handler));
|
||||
gobject_handler = g_signal_connect(about_qt, "activate", G_CALLBACK(aboutQtIndicator), this);
|
||||
m_handlers.append(QPair<gpointer, gulong>(about_qt, gobject_handler));
|
||||
gobject_handler = g_signal_connect(quit, "activate", G_CALLBACK(quitIndicator), this);
|
||||
m_handlers.append(QPair<gpointer, gulong>(quit, gobject_handler));
|
||||
|
||||
gtk_widget_show(options);
|
||||
gtk_widget_show(reload);
|
||||
gtk_widget_show(backup);
|
||||
gtk_widget_show(separator1);
|
||||
gtk_widget_show(about);
|
||||
gtk_widget_show(about_qt);
|
||||
gtk_widget_show(separator2);
|
||||
gtk_widget_show(quit);
|
||||
|
||||
m_indicator = app_indicator_new(
|
||||
"qcma-appindicator",
|
||||
"qcma-messages",
|
||||
APP_INDICATOR_CATEGORY_APPLICATION_STATUS
|
||||
);
|
||||
|
||||
QString icon_path;
|
||||
QString icon_name = "share/icons/hicolor/64x64/actions/qcma_on.png";
|
||||
|
||||
if(QFile("/usr/" + icon_name).exists())
|
||||
icon_path = QFileInfo("/usr/" + icon_name).absolutePath();
|
||||
else if(QFile("/usr/local" + icon_name).exists())
|
||||
icon_path = QFileInfo("/usr/" + icon_name).absolutePath();
|
||||
|
||||
if(!icon_path.isEmpty())
|
||||
{
|
||||
qDebug() << "Using " << icon_path << " as icon theme path";
|
||||
app_indicator_set_icon_theme_path(m_indicator, qPrintable(icon_path));
|
||||
}
|
||||
else
|
||||
qWarning() << "Cannot find qcma icons.";
|
||||
|
||||
app_indicator_set_status(m_indicator, APP_INDICATOR_STATUS_ACTIVE);
|
||||
app_indicator_set_menu(m_indicator, GTK_MENU(menu));
|
||||
}
|
||||
|
||||
bool UnityIndicator::isVisible()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnityIndicator::setIcon(const QString &icon)
|
||||
{
|
||||
app_indicator_set_icon_full(m_indicator, qPrintable(icon), "icon");
|
||||
}
|
||||
|
||||
void UnityIndicator::show()
|
||||
{
|
||||
}
|
||||
|
||||
void UnityIndicator::hide()
|
||||
{
|
||||
}
|
||||
|
||||
void UnityIndicator::showMessage(const QString &title, const QString &message)
|
||||
{
|
||||
NotifyNotification *notif = notify_notification_new(qPrintable(title), qPrintable(message), "dialog-information");
|
||||
notify_notification_show(notif, NULL);
|
||||
g_object_unref(G_OBJECT(notif));
|
||||
}
|
||||
|
||||
// exported library function
|
||||
TrayIndicator *createTrayIndicator(QWidget *parent)
|
||||
{
|
||||
return new UnityIndicator(parent);
|
||||
}
|
54
appindicator/unityindicator.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UNITYINDICATOR_H
|
||||
#define UNITYINDICATOR_H
|
||||
|
||||
#include "trayindicator.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#undef signals
|
||||
|
||||
extern "C" {
|
||||
#include <libappindicator/app-indicator.h>
|
||||
#include <gtk/gtk.h>
|
||||
}
|
||||
|
||||
#define signals public
|
||||
|
||||
class UnityIndicator : public TrayIndicator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UnityIndicator(QWidget *parent = 0);
|
||||
~UnityIndicator();
|
||||
void init();
|
||||
void setIcon(const QString &icon);
|
||||
bool isVisible();
|
||||
void show();
|
||||
void hide();
|
||||
void showMessage(const QString &title, const QString &message);
|
||||
|
||||
private:
|
||||
AppIndicator *m_indicator;
|
||||
QVector<QPair<gpointer, gulong> > m_handlers;
|
||||
};
|
||||
|
||||
#endif // UNITYINDICATOR_H
|
30
cli/cli.pro
Normal file
@@ -0,0 +1,30 @@
|
||||
include(../config.pri)
|
||||
include(../common/defines.pri)
|
||||
|
||||
TARGET = qcma_cli
|
||||
TEMPLATE += app
|
||||
QT += network sql
|
||||
LIBS += -L../common -lqcma_common
|
||||
|
||||
SOURCES += \
|
||||
main_cli.cpp \
|
||||
singlecoreapplication.cpp \
|
||||
headlessmanager.cpp
|
||||
|
||||
HEADERS += \
|
||||
singlecoreapplication.h \
|
||||
headlessmanager.h
|
||||
|
||||
|
||||
# find packages using pkg-config
|
||||
QT_CONFIG -= no-pkg-config
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG = libvitamtp libavformat libavcodec libavutil libswscale
|
||||
|
||||
# Linux-only config
|
||||
unix:!macx {
|
||||
man_cli.files = qcma_cli.1
|
||||
man_cli.path = $$MANDIR
|
||||
target.path = $$BINDIR
|
||||
INSTALLS += target man_cli
|
||||
}
|
191
cli/headlessmanager.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmaclient.h"
|
||||
#include "cmautils.h"
|
||||
#include "sqlitedb.h"
|
||||
#include "qlistdb.h"
|
||||
#include "headlessmanager.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QSettings>
|
||||
#include <QTextStream>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <vitamtp.h>
|
||||
|
||||
int HeadlessManager::sighup_fd[2];
|
||||
int HeadlessManager::sigterm_fd[2];
|
||||
|
||||
HeadlessManager::HeadlessManager(QObject *obj_parent) :
|
||||
QObject(obj_parent)
|
||||
{
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighup_fd))
|
||||
qFatal("Couldn't create HUP socketpair");
|
||||
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigterm_fd))
|
||||
qFatal("Couldn't create TERM socketpair");
|
||||
|
||||
sn_hup = new QSocketNotifier(sighup_fd[1], QSocketNotifier::Read, this);
|
||||
connect(sn_hup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
|
||||
sn_term = new QSocketNotifier(sigterm_fd[1], QSocketNotifier::Read, this);
|
||||
connect(sn_term, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
|
||||
}
|
||||
|
||||
HeadlessManager::~HeadlessManager()
|
||||
{
|
||||
VitaMTP_Cleanup();
|
||||
delete m_db;
|
||||
}
|
||||
|
||||
void HeadlessManager::refreshDatabase()
|
||||
{
|
||||
if(m_db->load()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream(stdout) << "Database scan has started" << endl;
|
||||
|
||||
if(!m_db->rescan()) {
|
||||
qWarning("No PS Vita system has been registered");
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessManager::start()
|
||||
{
|
||||
if(VitaMTP_Init() < 0) {
|
||||
qCritical("Cannot initialize VitaMTP library");
|
||||
return;
|
||||
}
|
||||
|
||||
if(QSettings().value("useMemoryStorage", true).toBool()) {
|
||||
m_db = new QListDB();
|
||||
} else {
|
||||
m_db = new SQLiteDB();
|
||||
}
|
||||
|
||||
// initializing database for the first use
|
||||
refreshDatabase();
|
||||
|
||||
// send a signal when the update is finished
|
||||
connect(m_db, SIGNAL(updated(int)), this, SIGNAL(databaseUpdated(int)));
|
||||
|
||||
thread_count = 0;
|
||||
qDebug("Starting cma threads");
|
||||
CmaClient *client;
|
||||
QSettings settings;
|
||||
|
||||
if(!settings.value("disableUSB", false).toBool()) {
|
||||
|
||||
if(!belongsToGroup("vitamtp"))
|
||||
qCritical() << tr("This user doesn't belong to the vitamtp group, there could be a problem while reading the USB bus.");
|
||||
|
||||
usb_thread = new QThread();
|
||||
client = new CmaClient(m_db);
|
||||
usb_thread->setObjectName("usb_thread");
|
||||
connect(usb_thread, SIGNAL(started()), client, SLOT(connectUsb()));
|
||||
connect(client, SIGNAL(finished()), usb_thread, SLOT(quit()), Qt::DirectConnection);
|
||||
connect(usb_thread, SIGNAL(finished()), usb_thread, SLOT(deleteLater()));
|
||||
connect(usb_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
|
||||
connect(usb_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
|
||||
|
||||
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||
|
||||
client->moveToThread(usb_thread);
|
||||
usb_thread->start();
|
||||
thread_count++;
|
||||
}
|
||||
|
||||
if(!settings.value("disableWireless", false).toBool()) {
|
||||
CmaBroadcast *broadcast = new CmaBroadcast(this);
|
||||
wireless_thread = new QThread();
|
||||
client = new CmaClient(m_db, broadcast);
|
||||
wireless_thread->setObjectName("wireless_thread");
|
||||
connect(wireless_thread, SIGNAL(started()), client, SLOT(connectWireless()));
|
||||
connect(client, SIGNAL(finished()), wireless_thread, SLOT(quit()), Qt::DirectConnection);
|
||||
connect(wireless_thread, SIGNAL(finished()), wireless_thread, SLOT(deleteLater()));
|
||||
connect(wireless_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
|
||||
connect(wireless_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
|
||||
|
||||
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||
|
||||
client->moveToThread(wireless_thread);
|
||||
wireless_thread->start();
|
||||
thread_count++;
|
||||
}
|
||||
|
||||
if(thread_count == 0) {
|
||||
qCritical("You must enable at least USB or Wireless monitoring");
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessManager::receiveMessage(QString message)
|
||||
{
|
||||
QTextStream(stdout) << message << endl;
|
||||
}
|
||||
|
||||
void HeadlessManager::stop()
|
||||
{
|
||||
if(CmaClient::stop() < 0) {
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessManager::threadStopped()
|
||||
{
|
||||
mutex.lock();
|
||||
if(--thread_count == 0) {
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void HeadlessManager::hupSignalHandler(int)
|
||||
{
|
||||
char a = 1;
|
||||
::write(sighup_fd[0], &a, sizeof(a));
|
||||
}
|
||||
|
||||
void HeadlessManager::termSignalHandler(int)
|
||||
{
|
||||
char a = 1;
|
||||
::write(sigterm_fd[0], &a, sizeof(a));
|
||||
}
|
||||
|
||||
void HeadlessManager::handleSigTerm()
|
||||
{
|
||||
sn_term->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sigterm_fd[1], &tmp, sizeof(tmp));
|
||||
|
||||
stop();
|
||||
|
||||
sn_term->setEnabled(true);
|
||||
}
|
||||
|
||||
void HeadlessManager::handleSigHup()
|
||||
{
|
||||
sn_hup->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sighup_fd[1], &tmp, sizeof(tmp));
|
||||
|
||||
refreshDatabase();
|
||||
|
||||
sn_hup->setEnabled(true);
|
||||
}
|
76
cli/headlessmanager.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEADLESSMANAGER_H
|
||||
#define HEADLESSMANAGER_H
|
||||
|
||||
#include "database.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QSocketNotifier>
|
||||
|
||||
class HeadlessManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HeadlessManager(QObject *parent = 0);
|
||||
~HeadlessManager();
|
||||
|
||||
void start();
|
||||
|
||||
// unix signal handlers
|
||||
static void hupSignalHandler(int);
|
||||
static void termSignalHandler(int);
|
||||
|
||||
private:
|
||||
int thread_count;
|
||||
QMutex mutex;
|
||||
|
||||
Database *m_db;
|
||||
|
||||
QThread *usb_thread;
|
||||
QThread *wireless_thread;
|
||||
|
||||
// signal handling
|
||||
static int sighup_fd[2];
|
||||
static int sigterm_fd[2];
|
||||
|
||||
QSocketNotifier *sn_hup;
|
||||
QSocketNotifier *sn_term;
|
||||
|
||||
signals:
|
||||
void stopped();
|
||||
void databaseUpdated(int count);
|
||||
|
||||
public slots:
|
||||
void refreshDatabase();
|
||||
void stop();
|
||||
|
||||
// Qt signal handlers
|
||||
void handleSigHup();
|
||||
void handleSigTerm();
|
||||
|
||||
private slots:
|
||||
void threadStopped();
|
||||
void receiveMessage(QString message);
|
||||
};
|
||||
|
||||
#endif // HEADLESSMANAGER_H
|
165
cli/main_cli.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Q_OS_WIN32
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLibraryInfo>
|
||||
#include <QLocale>
|
||||
#include <QStringList>
|
||||
#include <QTextCodec>
|
||||
#include <QThread>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <vitamtp.h>
|
||||
|
||||
#include "singlecoreapplication.h"
|
||||
#include "headlessmanager.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
static void noDebugOutput(QtMsgType type, const QMessageLogContext &, const QString & msg)
|
||||
{
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
const char *message = localMsg.constData();
|
||||
#else
|
||||
static void noDebugOutput(QtMsgType type, const char *message)
|
||||
{
|
||||
#endif
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
fprintf(stderr, "Warning: %s\n", message);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
fprintf(stderr, "Critical: %s\n", message);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
fprintf(stderr, "Fatal: %s\n", message);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static bool setup_handlers()
|
||||
{
|
||||
struct sigaction hup, term;
|
||||
|
||||
hup.sa_handler = HeadlessManager::hupSignalHandler;
|
||||
sigemptyset(&hup.sa_mask);
|
||||
hup.sa_flags = 0;
|
||||
hup.sa_flags |= SA_RESTART;
|
||||
|
||||
if (sigaction(SIGHUP, &hup, NULL) != 0) {
|
||||
qCritical("SIGHUP signal handle failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
term.sa_handler = HeadlessManager::termSignalHandler;
|
||||
sigemptyset(&term.sa_mask);
|
||||
term.sa_flags |= SA_RESTART;
|
||||
|
||||
if (sigaction(SIGTERM, &term, NULL) != 0) {
|
||||
qCritical("SIGTERM signal handle failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sigaction(SIGINT, &term, NULL) != 0) {
|
||||
qCritical("SIGINT signal handle failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(SingleCoreApplication::sendMessage("Another instance of Qcma tried to start")) {
|
||||
QTextStream(stdout) << "An instance of Qcma is already running" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SingleCoreApplication app(argc, argv);
|
||||
|
||||
// FIXME: libmtp sends SIGPIPE if a socket write fails crashing the whole app
|
||||
// the proper fix is to libmtp to handle the cancel properly or ignoring
|
||||
// SIGPIPE on the socket
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if(!setup_handlers())
|
||||
return 1;
|
||||
|
||||
if(app.arguments().contains("--with-debug")) {
|
||||
VitaMTP_Set_Logging(VitaMTP_DEBUG);
|
||||
} else if(app.arguments().contains("--verbose")) {
|
||||
VitaMTP_Set_Logging(VitaMTP_VERBOSE);
|
||||
} else {
|
||||
VitaMTP_Set_Logging(VitaMTP_NONE);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
qInstallMessageHandler(noDebugOutput);
|
||||
#else
|
||||
qInstallMsgHandler(noDebugOutput);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
|
||||
QTextStream(stdout) << "Starting Qcma " << QCMA_VER << endl;
|
||||
|
||||
QTranslator translator;
|
||||
QString locale = QLocale().system().name();
|
||||
qDebug() << "Current locale:" << locale;
|
||||
|
||||
if(app.arguments().contains("--set-locale")) {
|
||||
int index = app.arguments().indexOf("--set-locale");
|
||||
if(index + 1 < app.arguments().length()) {
|
||||
qDebug("Enforcing locale: %s", app.arguments().at(index + 1).toUtf8().data());
|
||||
locale = app.arguments().at(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(translator.load("qcma_" + locale, ":/resources/translations")) {
|
||||
app.installTranslator(&translator);
|
||||
} else {
|
||||
qWarning() << "Cannot load translation for locale:" << locale;
|
||||
}
|
||||
|
||||
QTranslator system_translator;
|
||||
system_translator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||
app.installTranslator(&system_translator);
|
||||
|
||||
qDebug("Starting main thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
|
||||
|
||||
// set the organization/application for QSettings to work properly
|
||||
app.setOrganizationName("codestation");
|
||||
app.setApplicationName("qcma");
|
||||
|
||||
HeadlessManager manager;
|
||||
|
||||
// receive the message from another process
|
||||
QObject::connect(&app, SIGNAL(messageAvailable(QString)), &manager, SLOT(receiveMessage(QString)));
|
||||
|
||||
manager.start();
|
||||
|
||||
return app.exec();
|
||||
}
|
33
cli/qcma_cli.1
Normal file
@@ -0,0 +1,33 @@
|
||||
.TH QCMA-CLI 1 "MARCH 2015"
|
||||
.SH NAME
|
||||
qcma-cli \- Content manager for the PlayStation Vita
|
||||
.SH SYNOPSIS
|
||||
.B qcma_cli \fR[options]
|
||||
|
||||
.TP
|
||||
.B \-\-verbose
|
||||
print detailed output
|
||||
|
||||
.TP
|
||||
.B \-\-with-debug
|
||||
print very verbose output (including hexdump transfers)
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBqcma_cli\fR is a cross-platform application to provide an Open Source implementation
|
||||
of the original Content Manager Assistant that comes with the PS Vita.
|
||||
.TP
|
||||
Qcma will let you backup your games, songs, photos & videos via USB or wireless.
|
||||
|
||||
.SH SIGNALS
|
||||
You can control \fBqcma_cli\fR using signals, i.e. using the \fBkill\fR command to send a signal to the process.
|
||||
|
||||
.TP
|
||||
.B SIGHUP
|
||||
Refreshes the database.
|
||||
|
||||
.TP
|
||||
.B SIGTERM or SIGINT
|
||||
Shuts down the process but waits until the current event is finished.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.I /usr/share/doc/qcma/README.md
|
69
cli/singlecoreapplication.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "singlecoreapplication.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
const int SingleCoreApplication::timeout = 500;
|
||||
const QString SingleCoreApplication::SHARED_KEY = "QCMA_KEY";
|
||||
|
||||
SingleCoreApplication::SingleCoreApplication(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
server = new QLocalServer(this);
|
||||
connect(server, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
|
||||
QLocalServer::removeServer(SHARED_KEY);
|
||||
server->listen(SHARED_KEY);
|
||||
}
|
||||
|
||||
void SingleCoreApplication::receiveMessage()
|
||||
{
|
||||
QLocalSocket *socket = server->nextPendingConnection();
|
||||
|
||||
if(!socket->waitForReadyRead(timeout)) {
|
||||
qDebug() << socket->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray byteArray = socket->readAll();
|
||||
QString message = QString::fromUtf8(byteArray.constData());
|
||||
emit messageAvailable(message);
|
||||
socket->disconnectFromServer();
|
||||
}
|
||||
|
||||
bool SingleCoreApplication::sendMessage(const QString &message)
|
||||
{
|
||||
QLocalSocket socket;
|
||||
socket.connectToServer(SHARED_KEY, QIODevice::WriteOnly);
|
||||
|
||||
if(!socket.waitForConnected(timeout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
socket.write(message.toUtf8());
|
||||
|
||||
if(!socket.waitForBytesWritten(timeout)) {
|
||||
qDebug() << socket.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
socket.disconnectFromServer();
|
||||
return true;
|
||||
}
|
50
cli/singlecoreapplication.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SINGLECOREAPPLICATION_H
|
||||
#define SINGLECOREAPPLICATION_H
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QLocalSocket>
|
||||
#include <QLocalServer>
|
||||
#include <QSharedMemory>
|
||||
|
||||
class SingleCoreApplication : public QCoreApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SingleCoreApplication(int &argc, char **argv);
|
||||
|
||||
static bool sendMessage(const QString &message);
|
||||
|
||||
private:
|
||||
QLocalServer *server;
|
||||
|
||||
static const int timeout;
|
||||
static const QString SHARED_KEY;
|
||||
|
||||
signals:
|
||||
void messageAvailable(QString message);
|
||||
|
||||
|
||||
public slots:
|
||||
void receiveMessage();
|
||||
};
|
||||
|
||||
#endif // SINGLECOREAPPLICATION_H
|
267
common/avdecoder.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmautils.h"
|
||||
#include "avdecoder.h"
|
||||
#include "database.h"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QFile>
|
||||
#include <QImage>
|
||||
#include <QSettings>
|
||||
|
||||
AVDecoder::AvInit init;
|
||||
|
||||
AVDecoder::AVDecoder() :
|
||||
pFormatCtx(NULL), pCodecCtx(NULL), av_stream(NULL), av_codec(NULL), stream_index(-1)
|
||||
{
|
||||
}
|
||||
|
||||
AVDecoder::~AVDecoder()
|
||||
{
|
||||
if(pCodecCtx) {
|
||||
avcodec_close(pCodecCtx);
|
||||
}
|
||||
if(pFormatCtx) {
|
||||
avformat_close_input(&pFormatCtx);
|
||||
}
|
||||
}
|
||||
|
||||
bool AVDecoder::open(const QString filename)
|
||||
{
|
||||
if(avformat_open_input(&pFormatCtx, QFile::encodeName(filename).constData(), NULL, NULL) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(avformat_find_stream_info(pFormatCtx, NULL) < 0) {
|
||||
avformat_close_input(&pFormatCtx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AVDecoder::loadCodec(codec_type codec)
|
||||
{
|
||||
AVDictionary *opts = NULL;
|
||||
|
||||
if((stream_index = av_find_best_stream(pFormatCtx, (AVMediaType)codec, -1, -1, &av_codec, 0)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
av_stream = pFormatCtx->streams[stream_index];
|
||||
pCodecCtx = av_stream->codec;
|
||||
|
||||
if(avcodec_open2(pCodecCtx, av_codec, &opts) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *AVDecoder::getMetadataEntry(const char *key, const char *default_value)
|
||||
{
|
||||
AVDictionaryEntry *entry;
|
||||
|
||||
if((entry = av_dict_get(pFormatCtx->metadata, key, NULL, 0)) != NULL) {
|
||||
return entry->value;
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
void AVDecoder::getAudioMetadata(metadata_t &metadata)
|
||||
{
|
||||
metadata.data.music.artist = strdup(getMetadataEntry("artist", ""));
|
||||
metadata.data.music.album = strdup(getMetadataEntry("album", ""));
|
||||
metadata.data.music.title = strdup(getMetadataEntry("title", ""));
|
||||
|
||||
if(loadCodec(CODEC_AUDIO)) {
|
||||
metadata.data.music.tracks->data.track_audio.bitrate = pCodecCtx->bit_rate;
|
||||
} else {
|
||||
metadata.data.music.tracks->data.track_audio.bitrate = pFormatCtx->bit_rate;
|
||||
}
|
||||
}
|
||||
|
||||
void AVDecoder::getVideoMetadata(metadata_t &metadata)
|
||||
{
|
||||
metadata.data.video.copyright = strdup(getMetadataEntry("copyright", ""));
|
||||
metadata.data.video.explanation = strdup(getMetadataEntry("comments", ""));
|
||||
metadata.data.video.title = strdup(getMetadataEntry("title", metadata.name));
|
||||
|
||||
if(loadCodec(CODEC_VIDEO)) {
|
||||
metadata.data.video.tracks->data.track_video.width = pCodecCtx->width;
|
||||
metadata.data.video.tracks->data.track_video.height = pCodecCtx->height;
|
||||
metadata.data.video.tracks->data.track_video.bitrate = pCodecCtx->bit_rate;
|
||||
metadata.data.video.tracks->data.track_video.duration = pFormatCtx->duration / 1000;
|
||||
|
||||
if(strcmp(av_codec->name, "h264") == 0) {
|
||||
metadata.data.video.tracks->data.track_video.codecType = CODEC_TYPE_AVC;
|
||||
} else if(strcmp(av_codec->name, "mpeg4") == 0) {
|
||||
metadata.data.video.tracks->data.track_video.codecType = CODEC_TYPE_MPEG4;
|
||||
} else {
|
||||
metadata.data.video.tracks->data.track_video.codecType = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray AVDecoder::getAudioThumbnail(int width, int height)
|
||||
{
|
||||
QByteArray data;
|
||||
|
||||
if(!loadCodec(CODEC_VIDEO)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
AVPacket pkt;
|
||||
if(av_read_frame(pFormatCtx, &pkt) >= 0) {
|
||||
// first frame == first thumbnail (hopefully)
|
||||
QBuffer imgbuffer(&data);
|
||||
imgbuffer.open(QIODevice::WriteOnly);
|
||||
QImage img = QImage::fromData(QByteArray((const char *)pkt.data, pkt.size));
|
||||
QImage result = img.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
result.save(&imgbuffer, "JPEG");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
AVFrame *AVDecoder::getDecodedFrame(AVCodecContext *codec_ctx, int frame_stream_index)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
|
||||
AVFrame *pFrame = av_frame_alloc();
|
||||
#else
|
||||
AVFrame *pFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
|
||||
AVPacket packet;
|
||||
int frame_finished = 0;
|
||||
|
||||
while(!frame_finished && av_read_frame(pFormatCtx, &packet)>=0) {
|
||||
if(packet.stream_index == frame_stream_index) {
|
||||
avcodec_decode_video2(codec_ctx, pFrame, &frame_finished, &packet);
|
||||
}
|
||||
av_free_packet(&packet);
|
||||
}
|
||||
|
||||
if(frame_finished) {
|
||||
return pFrame;
|
||||
} else {
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
|
||||
av_frame_free(&pFrame);
|
||||
#else
|
||||
av_free(pFrame);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray AVDecoder::getVideoThumbnail(int width, int height)
|
||||
{
|
||||
QByteArray data;
|
||||
AVFrame *pFrame;
|
||||
|
||||
int percentage = QSettings().value("videoThumbnailSeekPercentage", 30).toInt();
|
||||
|
||||
if(!loadCodec(CODEC_VIDEO)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
qint64 seek_pos = pFormatCtx->duration * percentage / (AV_TIME_BASE * 100);
|
||||
qint64 frame = av_rescale(seek_pos, av_stream->time_base.den, av_stream->time_base.num);
|
||||
|
||||
if(avformat_seek_file(pFormatCtx, stream_index, 0, frame, frame, AVSEEK_FLAG_FRAME) < 0) {
|
||||
avcodec_close(pCodecCtx);
|
||||
return data;
|
||||
}
|
||||
|
||||
if((pFrame = getDecodedFrame(pCodecCtx, stream_index)) == NULL) {
|
||||
avcodec_close(pCodecCtx);
|
||||
return data;
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
|
||||
AVFrame *pFrameRGB = av_frame_alloc();
|
||||
#else
|
||||
AVFrame *pFrameRGB = avcodec_alloc_frame();
|
||||
#endif
|
||||
|
||||
int numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
|
||||
uint8_t *buffer = (uint8_t *)av_malloc(numBytes);
|
||||
|
||||
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
|
||||
|
||||
SwsContext *sws_ctx = sws_getContext(
|
||||
pCodecCtx->width,
|
||||
pCodecCtx->height,
|
||||
pCodecCtx->pix_fmt,
|
||||
pCodecCtx->width,
|
||||
pCodecCtx->height,
|
||||
PIX_FMT_RGB24,
|
||||
SWS_BICUBIC,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if(!sws_ctx) {
|
||||
avcodec_close(pCodecCtx);
|
||||
return data;
|
||||
}
|
||||
|
||||
sws_scale(
|
||||
sws_ctx,
|
||||
pFrame->data,
|
||||
pFrame->linesize,
|
||||
0,
|
||||
pCodecCtx->height,
|
||||
pFrameRGB->data,
|
||||
pFrameRGB->linesize
|
||||
);
|
||||
|
||||
QImage image(pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB888);
|
||||
|
||||
for(int y = 0, h = pCodecCtx->height, w = pCodecCtx->width; y < h; y++) {
|
||||
memcpy(image.scanLine(y), pFrameRGB->data[0] + y * pFrameRGB->linesize[0], w * 3);
|
||||
}
|
||||
|
||||
QBuffer imgbuffer(&data);
|
||||
imgbuffer.open(QIODevice::WriteOnly);
|
||||
QImage result = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
result.save(&imgbuffer, "JPEG");
|
||||
|
||||
av_free(buffer);
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
|
||||
av_frame_free(&pFrameRGB);
|
||||
av_frame_free(&pFrame);
|
||||
#else
|
||||
av_free(pFrameRGB);
|
||||
av_free(pFrame);
|
||||
#endif
|
||||
|
||||
avcodec_close(pCodecCtx);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void AVDecoder::close()
|
||||
{
|
||||
avformat_close_input(&pFormatCtx);
|
||||
pFormatCtx = NULL;
|
||||
}
|
91
common/avdecoder.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AVDECODER_H
|
||||
#define AVDECODER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libavutil/mathematics.h>
|
||||
}
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
class AVDecoder
|
||||
{
|
||||
public:
|
||||
AVDecoder();
|
||||
~AVDecoder();
|
||||
|
||||
enum codec_type {CODEC_VIDEO = AVMEDIA_TYPE_VIDEO, CODEC_AUDIO = AVMEDIA_TYPE_AUDIO};
|
||||
|
||||
bool open(const QString filename);
|
||||
void close();
|
||||
bool loadCodec(codec_type codec);
|
||||
|
||||
QByteArray getAudioThumbnail(int width, int height);
|
||||
QByteArray getVideoThumbnail(int width, int height);
|
||||
void getAudioMetadata(metadata_t &metadata);
|
||||
void getVideoMetadata(metadata_t &metadata);
|
||||
const char *getMetadataEntry(const char *key, const char *default_value = NULL);
|
||||
|
||||
inline int getWidth() {
|
||||
return pCodecCtx->width;
|
||||
}
|
||||
|
||||
inline int getHeight() {
|
||||
return pCodecCtx->height;
|
||||
}
|
||||
|
||||
inline int getDuration() {
|
||||
return pFormatCtx->duration / 1000;
|
||||
}
|
||||
|
||||
inline int getBitrate() {
|
||||
return pCodecCtx->bit_rate;
|
||||
}
|
||||
|
||||
// simulate a static constructor to initialize libav only once
|
||||
class AvInit
|
||||
{
|
||||
public:
|
||||
AvInit() {
|
||||
av_register_all();
|
||||
// hide warning logs
|
||||
av_log_set_level(AV_LOG_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
static AvInit init;
|
||||
|
||||
private:
|
||||
AVFrame *getDecodedFrame(AVCodecContext *pCodecCtx, int stream_index);
|
||||
|
||||
AVFormatContext *pFormatCtx;
|
||||
AVCodecContext *pCodecCtx;
|
||||
AVStream *av_stream;
|
||||
AVCodec *av_codec;
|
||||
int stream_index;
|
||||
};
|
||||
|
||||
#endif // AVDECODER_H
|
132
common/capability.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "capability.h"
|
||||
#include "cmautils.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QHostInfo>
|
||||
#include <QSettings>
|
||||
|
||||
DeviceCapability::DeviceCapability() :
|
||||
vita_info()
|
||||
{
|
||||
}
|
||||
|
||||
bool DeviceCapability::exchangeInfo(vita_device_t *device)
|
||||
{
|
||||
if(VitaMTP_GetVitaInfo(device, &vita_info) != PTP_RC_OK) {
|
||||
qWarning("Cannot retreve device information.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(vita_info.protocolVersion > VITAMTP_PROTOCOL_MAX_VERSION) {
|
||||
qWarning("Vita wants protocol version %08d while we only support %08d. Attempting to continue.",
|
||||
vita_info.protocolVersion, VITAMTP_PROTOCOL_MAX_VERSION);
|
||||
}
|
||||
|
||||
QString hostname = QHostInfo::localHostName();
|
||||
|
||||
int protocol_version = ::getVitaProtocolVersion();
|
||||
|
||||
qDebug() << "Sending Qcma protocol version:" << protocol_version;
|
||||
|
||||
const initiator_info_t *pc_info = VitaMTP_Data_Initiator_New(hostname.toUtf8().data(), protocol_version);
|
||||
|
||||
// Next, we send the client's (this program) info (discard the const here)
|
||||
if(VitaMTP_SendInitiatorInfo(device, (initiator_info_t *)pc_info) != PTP_RC_OK) {
|
||||
qWarning("Cannot send host information.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(vita_info.protocolVersion >= VITAMTP_PROTOCOL_FW_2_10) {
|
||||
// Get the device's capabilities
|
||||
capability_info_t *vita_capabilities;
|
||||
|
||||
if(VitaMTP_GetVitaCapabilityInfo(device, &vita_capabilities) != PTP_RC_OK) {
|
||||
qWarning("Failed to get capability information from Vita.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: vitamtp needs to send the full metadata info to know the expected format
|
||||
// of thumbnails, for example. Until then lets discard the received info.
|
||||
|
||||
VitaMTP_Data_Free_Capability(vita_capabilities);
|
||||
// Send the host's capabilities
|
||||
capability_info_t *pc_capabilities = generate_pc_capability_info();
|
||||
|
||||
if(VitaMTP_SendPCCapabilityInfo(device, pc_capabilities) != PTP_RC_OK) {
|
||||
qWarning("Failed to send capability information to Vita.");
|
||||
free_pc_capability_info(pc_capabilities);
|
||||
return false;
|
||||
}
|
||||
|
||||
free_pc_capability_info(pc_capabilities);
|
||||
}
|
||||
|
||||
// Finally, we tell the Vita we are connected
|
||||
if(VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_Connected) != PTP_RC_OK) {
|
||||
qWarning("Cannot send host status.");
|
||||
return false;
|
||||
}
|
||||
|
||||
VitaMTP_Data_Free_Initiator(pc_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceCapability::free_pc_capability_info(capability_info_t *info)
|
||||
{
|
||||
delete[] &info->functions.formats.next_item[-1];
|
||||
delete[] &info->functions.next_item[-1];
|
||||
delete info;
|
||||
}
|
||||
|
||||
capability_info_t *DeviceCapability::generate_pc_capability_info()
|
||||
{
|
||||
typedef capability_info::capability_info_function tfunction;
|
||||
typedef tfunction::capability_info_format tformat;
|
||||
|
||||
// TODO: Actually do this based on QCMA capabilities
|
||||
capability_info_t *pc_capabilities = new capability_info_t;
|
||||
pc_capabilities->version = "1.0";
|
||||
tfunction *functions = new tfunction[3]();
|
||||
tformat *game_formats = new tformat[5]();
|
||||
game_formats[0].contentType = "vitaApp";
|
||||
game_formats[0].next_item = &game_formats[1];
|
||||
game_formats[1].contentType = "PSPGame";
|
||||
game_formats[1].next_item = &game_formats[2];
|
||||
game_formats[2].contentType = "PSPSaveData";
|
||||
game_formats[2].next_item = &game_formats[3];
|
||||
game_formats[3].contentType = "PSGame";
|
||||
game_formats[3].next_item = &game_formats[4];
|
||||
game_formats[4].contentType = "PSMApp";
|
||||
functions[0].type = "game";
|
||||
functions[0].formats = game_formats[0];
|
||||
functions[0].next_item = &functions[1];
|
||||
functions[1].type = "backup";
|
||||
functions[1].next_item = &functions[2];
|
||||
functions[2].type = "systemUpdate";
|
||||
pc_capabilities->functions = functions[0];
|
||||
return pc_capabilities;
|
||||
}
|
||||
|
||||
DeviceCapability::~DeviceCapability()
|
||||
{
|
||||
VitaMTP_Data_Free_VitaInfo(&vita_info);
|
||||
}
|
52
common/capability.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CAPABILITY_H
|
||||
#define CAPABILITY_H
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
class DeviceCapability
|
||||
{
|
||||
public:
|
||||
explicit DeviceCapability();
|
||||
~DeviceCapability();
|
||||
bool exchangeInfo(vita_device_t *device);
|
||||
|
||||
const char *getVersion() {
|
||||
return vita_info.responderVersion;
|
||||
}
|
||||
int getProtocolVersion() {
|
||||
return vita_info.protocolVersion;
|
||||
}
|
||||
const char *getOnlineId() {
|
||||
return vita_info.onlineId;
|
||||
}
|
||||
const char *getModelInfo() {
|
||||
return vita_info.modelInfo;
|
||||
}
|
||||
|
||||
private:
|
||||
capability_info_t *generate_pc_capability_info();
|
||||
void free_pc_capability_info(capability_info_t *info);
|
||||
|
||||
vita_info_t vita_info;
|
||||
};
|
||||
|
||||
#endif // CAPABILITY_H
|
122
common/cmabroadcast.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmabroadcast.h"
|
||||
#include "cmautils.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QHostAddress>
|
||||
#include <QHostInfo>
|
||||
#include <QMutexLocker>
|
||||
#include <QSettings>
|
||||
#include <QUuid>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
const QString CmaBroadcast::broadcast_reply =
|
||||
"%1\r\n"
|
||||
"host-id:%2\r\n"
|
||||
"host-type:%3\r\n"
|
||||
"host-name:%4\r\n"
|
||||
"host-mtp-protocol-version:%5\r\n"
|
||||
"host-request-port:%6\r\n"
|
||||
"host-wireless-protocol-version:%7\r\n"
|
||||
"host-supported-device:PS Vita, PS Vita TV\r\n";
|
||||
|
||||
const char *CmaBroadcast::broadcast_query_start = "SRCH";
|
||||
const char *CmaBroadcast::broadcast_query_end = " * HTTP/1.1\r\n";
|
||||
|
||||
const char *CmaBroadcast::broadcast_ok = "HTTP/1.1 200 OK";
|
||||
const char *CmaBroadcast::broadcast_unavailable = "HTTP/1.1 503 NG";
|
||||
|
||||
CmaBroadcast::CmaBroadcast(QObject *obj_parent) :
|
||||
QObject(obj_parent)
|
||||
{
|
||||
QSettings settings;
|
||||
// generate a GUID if doesn't exist yet in settings
|
||||
uuid = settings.value("guid").toString();
|
||||
if(uuid.isEmpty()) {
|
||||
uuid = QUuid::createUuid().toString().mid(1,36);
|
||||
settings.setValue("guid", uuid);
|
||||
}
|
||||
|
||||
hostname = QHostInfo::localHostName();
|
||||
setAvailable();
|
||||
|
||||
socket = new QUdpSocket(this);
|
||||
connect(socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
QHostAddress host_address(QHostAddress::Any);
|
||||
#else
|
||||
QHostAddress host_address(QHostAddress::AnyIPv4);
|
||||
#endif
|
||||
|
||||
if(!socket->bind(host_address, QCMA_REQUEST_PORT, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) {
|
||||
qCritical() << "Failed to bind address for UDP broadcast";
|
||||
}
|
||||
}
|
||||
|
||||
void CmaBroadcast::readPendingDatagrams()
|
||||
{
|
||||
if(socket->hasPendingDatagrams()) {
|
||||
QByteArray datagram;
|
||||
datagram.resize(socket->pendingDatagramSize());
|
||||
|
||||
QHostAddress cma_sender;
|
||||
quint16 senderPort;
|
||||
|
||||
socket->readDatagram(datagram.data(), datagram.size(), &cma_sender, &senderPort);
|
||||
|
||||
if(datagram.startsWith(broadcast_query_start) && datagram.contains(broadcast_query_end)) {
|
||||
QMutexLocker locker(&mutex);
|
||||
socket->writeDatagram(reply, cma_sender, senderPort);
|
||||
} else {
|
||||
qWarning("Unknown request: %.*s\n", datagram.length(), datagram.constData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CmaBroadcast::setAvailable()
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
int protocol_version = ::getVitaProtocolVersion();
|
||||
|
||||
reply.clear();
|
||||
reply.insert(0, broadcast_reply
|
||||
.arg(broadcast_ok, uuid, "win", hostname)
|
||||
.arg(protocol_version, 8, 10, QChar('0'))
|
||||
.arg(QCMA_REQUEST_PORT)
|
||||
.arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0')));
|
||||
reply.append('\0');
|
||||
}
|
||||
|
||||
void CmaBroadcast::setUnavailable()
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
int protocol_version = ::getVitaProtocolVersion();
|
||||
|
||||
reply.clear();
|
||||
reply.insert(0, broadcast_reply
|
||||
.arg(broadcast_unavailable, uuid, "win", hostname)
|
||||
.arg(protocol_version, 8, 10, QChar('0'))
|
||||
.arg(QCMA_REQUEST_PORT)
|
||||
.arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0')));
|
||||
reply.append('\0');
|
||||
}
|
58
common/cmabroadcast.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CMABROADCAST_H
|
||||
#define CMABROADCAST_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QUdpSocket>
|
||||
|
||||
#define QCMA_REQUEST_PORT 9309
|
||||
|
||||
class CmaBroadcast : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CmaBroadcast(QObject *parent = 0);
|
||||
|
||||
private:
|
||||
void replyBroadcast(const QByteArray &datagram);
|
||||
|
||||
QMutex mutex;
|
||||
QString uuid;
|
||||
QByteArray reply;
|
||||
QString hostname;
|
||||
QUdpSocket *socket;
|
||||
|
||||
static const QString broadcast_reply;
|
||||
static const char *broadcast_query_start;
|
||||
static const char *broadcast_query_end;
|
||||
static const char *broadcast_ok;
|
||||
static const char *broadcast_unavailable;
|
||||
|
||||
public slots:
|
||||
void setAvailable();
|
||||
void setUnavailable();
|
||||
|
||||
private slots:
|
||||
void readPendingDatagrams();
|
||||
};
|
||||
|
||||
#endif // CMABROADCAST_H
|
284
common/cmaclient.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmaclient.h"
|
||||
#include "capability.h"
|
||||
#include "avdecoder.h"
|
||||
#include "cmaevent.h"
|
||||
#include "cmautils.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QImage>
|
||||
#include <QTextStream>
|
||||
#include <QTime>
|
||||
#include <QSettings>
|
||||
#include <QUrl>
|
||||
|
||||
QMutex CmaClient::mutex;
|
||||
QMutex CmaClient::runner;
|
||||
QWaitCondition CmaClient::usbcondition;
|
||||
QMutex CmaClient::usbwait;
|
||||
QSemaphore CmaClient::sema;
|
||||
|
||||
QString CmaClient::tempOnlineId = QString();
|
||||
|
||||
bool CmaClient::is_active = false;
|
||||
bool CmaClient::in_progress = false;
|
||||
|
||||
CmaClient *CmaClient::this_object = NULL;
|
||||
|
||||
CmaClient::CmaClient(Database *db, QObject *obj_parent) :
|
||||
QObject(obj_parent), m_db(db), m_broadcast(NULL)
|
||||
{
|
||||
this_object = this;
|
||||
}
|
||||
|
||||
|
||||
CmaClient::CmaClient(Database *db, CmaBroadcast *broadcast, QObject *obj_parent) :
|
||||
QObject(obj_parent), m_db(db), m_broadcast(broadcast)
|
||||
{
|
||||
this_object = this;
|
||||
}
|
||||
|
||||
void CmaClient::connectUsb()
|
||||
{
|
||||
vita_device_t *vita;
|
||||
|
||||
qDebug("Starting usb_thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
|
||||
|
||||
setActive(true);
|
||||
usbwait.lock();
|
||||
|
||||
do {
|
||||
if((vita = VitaMTP_Get_First_USB_Vita()) != NULL) {
|
||||
qDebug("Starting new USB connection");
|
||||
processNewConnection(vita);
|
||||
} else {
|
||||
//TODO: replace this with an event-driven setup
|
||||
usbcondition.wait(&usbwait, 2000);
|
||||
mutex.lock();
|
||||
if(in_progress) {
|
||||
sema.acquire();
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
} while(isActive());
|
||||
|
||||
usbwait.unlock();
|
||||
qDebug("Finishing usb_thread");
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void CmaClient::connectWireless()
|
||||
{
|
||||
vita_device_t *vita;
|
||||
wireless_host_info_t host = {NULL, NULL, NULL, QCMA_REQUEST_PORT};
|
||||
typedef CmaClient CC;
|
||||
|
||||
QTime now = QTime::currentTime();
|
||||
qsrand(now.msec());
|
||||
|
||||
qDebug("Starting wireless_thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
|
||||
|
||||
setActive(true);
|
||||
|
||||
do {
|
||||
qDebug("Waiting for wireless connection");
|
||||
if((vita = VitaMTP_Get_First_Wireless_Vita(&host, 0, CC::deviceRegistered, CC::generatePin, CC::registrationComplete)) != NULL) {
|
||||
qDebug("Starting new wireless connection");
|
||||
m_broadcast->setUnavailable();
|
||||
processNewConnection(vita);
|
||||
m_broadcast->setAvailable();
|
||||
} else {
|
||||
mutex.lock();
|
||||
if(in_progress) {
|
||||
sema.acquire();
|
||||
}
|
||||
mutex.unlock();
|
||||
|
||||
// if is active then something happened while setting the socket, wait a little and try again
|
||||
if(isActive()) {
|
||||
qDebug("Error getting wireless connection");
|
||||
Sleeper::sleep(2000);
|
||||
} else {
|
||||
qDebug("Wireless connection cancelled by the user");
|
||||
}
|
||||
}
|
||||
} while(isActive());
|
||||
|
||||
qDebug("Finishing wireless_thread");
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void CmaClient::processNewConnection(vita_device_t *device)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
in_progress = true;
|
||||
|
||||
QTextStream(stdout) << "Vita connected, id: " << VitaMTP_Get_Identification(device) << endl;
|
||||
DeviceCapability vita_info;
|
||||
|
||||
if(!vita_info.exchangeInfo(device)) {
|
||||
qCritical("Error while exchanging info with the vita");
|
||||
if(VitaMTP_Get_Device_Type(device) == VitaDeviceUSB) {
|
||||
// reset the device
|
||||
VitaMTP_USB_Reset(device);
|
||||
}
|
||||
} else {
|
||||
QSettings settings;
|
||||
|
||||
// Conection successful, inform the user
|
||||
if(vita_info.getOnlineId() != NULL) {
|
||||
settings.setValue("lastOnlineId", vita_info.getOnlineId());
|
||||
emit deviceConnected(QString(tr("Connected to %1 (PS Vita)")).arg(vita_info.getOnlineId()));
|
||||
} else {
|
||||
QString onlineId = settings.value("lastOnlineId", "default").toString();
|
||||
emit deviceConnected(QString(tr("Connected to %1 (PS Vita)")).arg(onlineId));
|
||||
}
|
||||
|
||||
enterEventLoop(device);
|
||||
}
|
||||
|
||||
VitaMTP_SendHostStatus(device, VITA_HOST_STATUS_EndConnection);
|
||||
qDebug("Releasing device...");
|
||||
VitaMTP_Release_Device(device);
|
||||
|
||||
emit deviceDisconnected();
|
||||
|
||||
in_progress = false;
|
||||
sema.release();
|
||||
}
|
||||
|
||||
void CmaClient::registrationComplete()
|
||||
{
|
||||
QSettings settings;
|
||||
qDebug("Registration completed");
|
||||
settings.setValue("lastOnlineId", tempOnlineId);
|
||||
emit this_object->pinComplete();
|
||||
}
|
||||
|
||||
int CmaClient::deviceRegistered(const char *deviceid)
|
||||
{
|
||||
qDebug("Got connection request from %s", deviceid);
|
||||
// TODO: check the device to see if is already registered
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CmaClient::generatePin(wireless_vita_info_t *info, int *p_err)
|
||||
{
|
||||
// save the device name in a temporal variable, just in case the pin is rejected
|
||||
tempOnlineId = QString(info->name);
|
||||
qDebug("Registration request from %s (MAC: %s)", info->name, info->mac_addr);
|
||||
int pin = rand() % 10000 * 10000 | rand() % 10000;
|
||||
QTextStream out(stdout);
|
||||
out << "Your registration PIN for " << info->name << " is: ";
|
||||
out.setFieldWidth(8);
|
||||
out.setPadChar('0');
|
||||
out << pin << endl;
|
||||
|
||||
*p_err = 0;
|
||||
emit this_object->receivedPin(info->name, pin);
|
||||
return pin;
|
||||
}
|
||||
|
||||
void CmaClient::enterEventLoop(vita_device_t *device)
|
||||
{
|
||||
vita_event_t obj_event;
|
||||
|
||||
qDebug("Starting event loop");
|
||||
|
||||
CmaEvent eventLoop(m_db, device);
|
||||
QThread obj_thread;
|
||||
obj_thread.setObjectName("event_thread");
|
||||
|
||||
eventLoop.moveToThread(&obj_thread);
|
||||
connect(&obj_thread, SIGNAL(started()), &eventLoop, SLOT(process()));
|
||||
connect(&eventLoop, SIGNAL(refreshDatabase()), this, SIGNAL(refreshDatabase()), Qt::DirectConnection);
|
||||
connect(&eventLoop, SIGNAL(finishedEventLoop()), &obj_thread, SLOT(quit()), Qt::DirectConnection);
|
||||
connect(&eventLoop, SIGNAL(messageSent(QString)), this, SIGNAL(messageSent(QString)), Qt::DirectConnection);
|
||||
obj_thread.start();
|
||||
|
||||
while(isActive()) {
|
||||
if(VitaMTP_Read_Event(device, &obj_event) < 0) {
|
||||
qWarning("Error reading event from Vita.");
|
||||
break;
|
||||
}
|
||||
|
||||
// do not create a event for this since there aren't more events to read
|
||||
if(obj_event.Code == PTP_EC_VITA_RequestTerminate) {
|
||||
qDebug("Terminating event thread");
|
||||
break;
|
||||
|
||||
// this one shuold be processed inmediately
|
||||
} else if(obj_event.Code == PTP_EC_VITA_RequestCancelTask) {
|
||||
eventLoop.vitaEventCancelTask(&obj_event, obj_event.Param1);
|
||||
qDebug("Ended event, code: 0x%x, id: %d", obj_event.Code, obj_event.Param1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// the events are processed synchronously except for cancel/terminate
|
||||
qDebug("Sending new event");
|
||||
eventLoop.setEvent(obj_event);
|
||||
}
|
||||
|
||||
eventLoop.stop();
|
||||
obj_thread.wait();
|
||||
qDebug("Finishing event loop");
|
||||
}
|
||||
|
||||
int CmaClient::stop()
|
||||
{
|
||||
QTextStream(stdout) << "Stopping Qcma" << endl;
|
||||
|
||||
if(!isActive()) {
|
||||
return -1;
|
||||
}
|
||||
CmaClient::setActive(false);
|
||||
qDebug("Cancelling wireless server thread");
|
||||
VitaMTP_Cancel_Get_Wireless_Vita();
|
||||
usbcondition.wakeAll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CmaClient::isActive()
|
||||
{
|
||||
QMutexLocker locker(&runner);
|
||||
return is_active;
|
||||
}
|
||||
|
||||
void CmaClient::setActive(bool state)
|
||||
{
|
||||
QMutexLocker locker(&runner);
|
||||
is_active = state;
|
||||
}
|
||||
|
||||
bool CmaClient::isRunning()
|
||||
{
|
||||
bool ret;
|
||||
if(mutex.tryLock()) {
|
||||
ret = in_progress;
|
||||
mutex.unlock();
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
91
common/cmaclient.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CMACLIENT_H
|
||||
#define CMACLIENT_H
|
||||
|
||||
#include "qlistdb.h"
|
||||
#include "cmaevent.h"
|
||||
#include "cmabroadcast.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSemaphore>
|
||||
#include <QString>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
class CmaClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CmaClient(Database *db, QObject *obj_parent = 0);
|
||||
explicit CmaClient(Database *db, CmaBroadcast *broadcast, QObject *obj_parent = 0);
|
||||
|
||||
static bool isRunning();
|
||||
void launch();
|
||||
|
||||
private:
|
||||
static bool isActive();
|
||||
static void setActive(bool state);
|
||||
static bool isEventLoopEnabled();
|
||||
static void setEventLoop(bool state);
|
||||
void enterEventLoop(vita_device_t *device);
|
||||
|
||||
void processNewConnection(vita_device_t *device);
|
||||
|
||||
static int deviceRegistered(const char *deviceid);
|
||||
static int generatePin(wireless_vita_info_t *info, int *p_err);
|
||||
static int cancelCallback();
|
||||
static void registrationComplete();
|
||||
|
||||
Database *m_db;
|
||||
CmaBroadcast *m_broadcast;
|
||||
static QString tempOnlineId;
|
||||
|
||||
//TODO: move all the control variables to the client manager class
|
||||
static bool is_active;
|
||||
static bool in_progress;
|
||||
static CmaClient *this_object;
|
||||
static QMutex mutex;
|
||||
static QMutex runner;
|
||||
static QMutex usbwait;
|
||||
static QWaitCondition usbcondition;
|
||||
static QSemaphore sema;
|
||||
|
||||
signals:
|
||||
void newEvent(vita_event_t event);
|
||||
void receivedPin(QString, int);
|
||||
void pinComplete();
|
||||
void deviceDetected();
|
||||
void deviceConnected(QString);
|
||||
void messageSent(QString);
|
||||
void deviceDisconnected();
|
||||
void refreshDatabase();
|
||||
void finished();
|
||||
|
||||
public slots:
|
||||
static int stop();
|
||||
|
||||
private slots:
|
||||
void connectUsb();
|
||||
void connectWireless();
|
||||
};
|
||||
|
||||
#endif // CMACLIENT_H
|
1009
common/cmaevent.cpp
Normal file
93
common/cmaevent.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CMAEVENT_H
|
||||
#define CMAEVENT_H
|
||||
|
||||
#include "database.h"
|
||||
#include "httpdownloader.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QSemaphore>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
class CmaEvent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CmaEvent(Database *db, vita_device_t *s_device);
|
||||
void vitaEventCancelTask(vita_event_t *event, int eventId);
|
||||
|
||||
private:
|
||||
uint16_t processAllObjects(metadata_t &metadata, uint32_t handle);
|
||||
void vitaEventSendObject(vita_event_t *event, int eventId);
|
||||
void vitaEventSendObjectMetadata(vita_event_t *event, int eventId);
|
||||
void vitaEventSendNumOfObject(vita_event_t *event, int eventId);
|
||||
void vitaEventSendHttpObjectFromURL(vita_event_t *event, int eventId);
|
||||
void vitaEventUnimplementated(vita_event_t *event, int eventId);
|
||||
void vitaEventSendObjectStatus(vita_event_t *event, int eventId);
|
||||
void vitaEventSendObjectThumb(vita_event_t *event, int eventId);
|
||||
void vitaEventDeleteObject(vita_event_t *event, int eventId);
|
||||
void vitaEventGetSettingInfo(vita_event_t *event, int eventId);
|
||||
void vitaEventSendHttpObjectPropFromURL(vita_event_t *event, int eventId);
|
||||
void vitaEventSendPartOfObject(vita_event_t *event, int eventId);
|
||||
void vitaEventOperateObject(vita_event_t *event, int eventId);
|
||||
void vitaEventGetPartOfObject(vita_event_t *event, int eventId);
|
||||
void vitaEventSendStorageSize(vita_event_t *event, int eventId);
|
||||
void vitaEventCheckExistance(vita_event_t *event, int eventId);
|
||||
void vitaEventGetTreatObject(vita_event_t *event, int eventId);
|
||||
void vitaEventSendCopyConfirmationInfo(vita_event_t *event, int eventId);
|
||||
void vitaEventSendObjectMetadataItems(vita_event_t *event, int eventId);
|
||||
void vitaEventSendNPAccountInfo(vita_event_t *event, int eventId);
|
||||
|
||||
static int readCallback(unsigned char *data, unsigned long wantlen, unsigned long *gotlen);
|
||||
static int writeCallback(const unsigned char *data, unsigned long size, unsigned long *written);
|
||||
|
||||
void processEvent();
|
||||
bool isActive();
|
||||
void setDevice(vita_device_t *m_device);
|
||||
|
||||
vita_device_t *m_device;
|
||||
vita_event_t m_event;
|
||||
|
||||
Database *m_db;
|
||||
|
||||
// control variables
|
||||
bool is_active;
|
||||
QMutex mutex;
|
||||
QMutex active;
|
||||
QSemaphore sema;
|
||||
|
||||
static QFile *m_file;
|
||||
|
||||
signals:
|
||||
void finishedEventLoop();
|
||||
void refreshDatabase();
|
||||
void messageSent(QString);
|
||||
|
||||
public slots:
|
||||
void process();
|
||||
void setEvent(vita_event_t event);
|
||||
void stop();
|
||||
};
|
||||
|
||||
#endif // CMAEVENT_H
|
242
common/cmaobject.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmaobject.h"
|
||||
#include "sforeader.h"
|
||||
#include "avdecoder.h"
|
||||
#include "database.h"
|
||||
#include "cmautils.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
|
||||
int CMAObject::ohfi_count = OHFI_OFFSET;
|
||||
|
||||
CMAObject::CMAObject(CMAObject *obj_parent) :
|
||||
parent(obj_parent), metadata()
|
||||
{
|
||||
}
|
||||
|
||||
CMAObject::~CMAObject()
|
||||
{
|
||||
free(metadata.name);
|
||||
free(metadata.path);
|
||||
|
||||
if(MASK_SET(metadata.dataType, SaveData | Folder)) {
|
||||
free(metadata.data.saveData.title);
|
||||
free(metadata.data.saveData.detail);
|
||||
free(metadata.data.saveData.dirName);
|
||||
free(metadata.data.saveData.savedataTitle);
|
||||
} else if(MASK_SET(metadata.dataType, Photo | File)) {
|
||||
free(metadata.data.photo.title);
|
||||
free(metadata.data.photo.fileName);
|
||||
delete metadata.data.photo.tracks;
|
||||
} else if(MASK_SET(metadata.dataType, Music | File)) {
|
||||
free(metadata.data.music.title);
|
||||
free(metadata.data.music.fileName);
|
||||
free(metadata.data.music.album);
|
||||
free(metadata.data.music.artist);
|
||||
delete metadata.data.music.tracks;
|
||||
} else if(MASK_SET(metadata.dataType, Video | File)) {
|
||||
free(metadata.data.video.title);
|
||||
free(metadata.data.video.explanation);
|
||||
free(metadata.data.video.fileName);
|
||||
free(metadata.data.video.copyright);
|
||||
delete metadata.data.video.tracks;
|
||||
}
|
||||
}
|
||||
|
||||
void CMAObject::loadSfoMetadata(const QString &path)
|
||||
{
|
||||
QString sfo = QDir(path).absoluteFilePath("PARAM.SFO");
|
||||
bool skipMetadata = QSettings().value("skipMetadata", false).toBool();
|
||||
SfoReader reader;
|
||||
|
||||
if(!skipMetadata && reader.load(sfo)) {
|
||||
metadata.data.saveData.title = strdup(reader.value("TITLE", ""));
|
||||
//FIXME: disable savedata detail for now
|
||||
//QString detail(reader.value("SAVEDATA_DETAIL", ""));
|
||||
|
||||
// libxml follow the spec and normalizes the newlines (and others) but
|
||||
// the PS Vita chokes on contiguous codes and crashes the CMA app on
|
||||
// the device. Of course, the "fix" would be that libxml doesn't
|
||||
// normalize newlines but that is aganist the XML spec that the PS Vita
|
||||
// doesn't respect >_>
|
||||
|
||||
// convert DOS to UNIX newlines
|
||||
//detail.replace("\r\n", "\n");
|
||||
// separate newlines from quotes
|
||||
//detail.replace("\n\"", "\n \"");
|
||||
//detail.replace("\"\n", "\" \n");
|
||||
// merge consecutive newlines
|
||||
//detail.replace("\n\n", "\n");
|
||||
//while(detail.endsWith('\n')) {
|
||||
// detail.chop(1);
|
||||
//}
|
||||
//metadata.data.saveData.detail = strdup(detail.toStdString().c_str());
|
||||
metadata.data.saveData.detail = strdup("");
|
||||
|
||||
// remove newlines from savedata title
|
||||
QString title(reader.value("SAVEDATA_TITLE", ""));
|
||||
while(title.endsWith('\n')) {
|
||||
title.chop(1);
|
||||
}
|
||||
metadata.data.saveData.savedataTitle = strdup(title.toStdString().c_str());
|
||||
metadata.data.saveData.dateTimeUpdated = QFileInfo(sfo).created().toUTC().toTime_t();
|
||||
} else {
|
||||
metadata.data.saveData.title = strdup(metadata.name);
|
||||
metadata.data.saveData.detail = strdup("");
|
||||
metadata.data.saveData.savedataTitle = strdup("");
|
||||
metadata.data.saveData.dateTimeUpdated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CMAObject::initObject(const QFileInfo &file, int obj_file_type)
|
||||
{
|
||||
metadata.name = strdup(file.fileName().toUtf8().data());
|
||||
metadata.ohfiParent = parent->metadata.ohfi;
|
||||
metadata.ohfi = ohfi_count++;
|
||||
|
||||
metadata.type = VITA_DIR_TYPE_MASK_REGULAR; // ignored for files
|
||||
metadata.dateTimeCreated = file.created().toUTC().toTime_t();
|
||||
metadata.size = 0;
|
||||
DataType type = file.isFile() ? File : Folder;
|
||||
metadata.dataType = (DataType)(type | (parent->metadata.dataType & ~Folder));
|
||||
|
||||
// create additional metadata
|
||||
if(MASK_SET(metadata.dataType, SaveData | Folder)) {
|
||||
metadata.data.saveData.dirName = strdup(metadata.name);
|
||||
metadata.data.saveData.statusType = 1;
|
||||
loadSfoMetadata(file.absoluteFilePath());
|
||||
} else if(MASK_SET(metadata.dataType, Music | File)) {
|
||||
|
||||
if(obj_file_type < 0) {
|
||||
qWarning("Invalid file type for music: %i, setting it to zero", obj_file_type);
|
||||
obj_file_type = 0;
|
||||
}
|
||||
|
||||
metadata.data.music.fileName = strdup(metadata.name);
|
||||
metadata.data.music.fileFormatType = audio_list[obj_file_type].file_format;
|
||||
metadata.data.music.statusType = 1;
|
||||
metadata.data.music.numTracks = 1;
|
||||
metadata.data.music.tracks = new media_track();
|
||||
metadata.data.music.tracks->type = VITA_TRACK_TYPE_AUDIO;
|
||||
metadata.data.music.tracks->data.track_photo.codecType = audio_list[obj_file_type].file_codec;
|
||||
Database::loadMusicMetadata(file.absoluteFilePath(), metadata);
|
||||
} else if(MASK_SET(metadata.dataType, Video | File)) {
|
||||
metadata.data.video.fileName = strdup(metadata.name);
|
||||
metadata.data.video.dateTimeUpdated = file.created().toUTC().toTime_t();
|
||||
metadata.data.video.statusType = 1;
|
||||
metadata.data.video.fileFormatType = FILE_FORMAT_MP4;
|
||||
metadata.data.video.parentalLevel = 0;
|
||||
metadata.data.video.numTracks = 1;
|
||||
metadata.data.video.tracks = new media_track();
|
||||
metadata.data.video.tracks->type = VITA_TRACK_TYPE_VIDEO;
|
||||
Database::loadVideoMetadata(file.absoluteFilePath(), metadata);
|
||||
} else if(MASK_SET(metadata.dataType, Photo | File)) {
|
||||
|
||||
if(obj_file_type < 0) {
|
||||
qWarning("Invalid file type for photos: %i, setting it to zero", obj_file_type);
|
||||
obj_file_type = 0;
|
||||
}
|
||||
|
||||
metadata.data.photo.fileName = strdup(metadata.name);
|
||||
metadata.data.photo.fileFormatType = photo_list[obj_file_type].file_format;
|
||||
metadata.data.photo.statusType = 1;
|
||||
metadata.data.photo.dateTimeOriginal = file.created().toUTC().toTime_t();
|
||||
metadata.data.photo.numTracks = 1;
|
||||
metadata.data.photo.tracks = new media_track();
|
||||
metadata.data.photo.tracks->type = VITA_TRACK_TYPE_PHOTO;
|
||||
metadata.data.photo.tracks->data.track_photo.codecType = photo_list[obj_file_type].file_codec;
|
||||
Database::loadPhotoMetadata(file.absoluteFilePath(), metadata);
|
||||
}
|
||||
|
||||
m_path = file.absoluteFilePath();
|
||||
|
||||
if(parent->metadata.path == NULL) {
|
||||
metadata.path = strdup(metadata.name);
|
||||
} else {
|
||||
QString newpath = QString(parent->metadata.path) + "/" + metadata.name;
|
||||
metadata.path = strdup(newpath.toUtf8().data());
|
||||
}
|
||||
|
||||
updateObjectSize(file.size());
|
||||
}
|
||||
|
||||
void CMAObject::updateObjectSize(qint64 size)
|
||||
{
|
||||
if(parent) {
|
||||
parent->updateObjectSize(size);
|
||||
}
|
||||
metadata.size += size;
|
||||
}
|
||||
|
||||
void CMAObject::rename(const QString &newname)
|
||||
{
|
||||
free(metadata.name);
|
||||
metadata.name = strdup(newname.toUtf8().data());
|
||||
|
||||
if(metadata.path) {
|
||||
QStringList metadata_path(QString(metadata.path).split("/"));
|
||||
metadata_path.replace(metadata_path.count() - 1, newname);
|
||||
free(metadata.path);
|
||||
metadata.path = strdup(metadata_path.join("/").toUtf8().data());
|
||||
}
|
||||
|
||||
m_path = QFileInfo(m_path).absoluteDir().path() + "/" + newname;
|
||||
}
|
||||
|
||||
void CMAObject::refreshPath()
|
||||
{
|
||||
if(parent) {
|
||||
free(metadata.path);
|
||||
QString newpath(QString(parent->metadata.path) + "/" + metadata.name);
|
||||
metadata.path = strdup(newpath.toUtf8().data());
|
||||
m_path = parent->m_path + "/" + metadata.name;
|
||||
}
|
||||
}
|
||||
|
||||
bool CMAObject::hasParent(const CMAObject *obj)
|
||||
{
|
||||
if(parent) {
|
||||
if(metadata.ohfiParent == obj->metadata.ohfi) {
|
||||
return true;
|
||||
} else {
|
||||
return parent->hasParent(obj);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMAObject::operator==(const CMAObject &obj)
|
||||
{
|
||||
return metadata.ohfi == obj.metadata.ohfi;
|
||||
}
|
||||
|
||||
bool CMAObject::operator!=(const CMAObject &obj)
|
||||
{
|
||||
return metadata.ohfi != obj.metadata.ohfi;
|
||||
}
|
||||
|
||||
bool CMAObject::operator<(const CMAObject &obj)
|
||||
{
|
||||
return metadata.ohfi < obj.metadata.ohfi;
|
||||
}
|
65
common/cmaobject.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CMAOBJECT_H
|
||||
#define CMAOBJECT_H
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
#define OHFI_OFFSET 256
|
||||
|
||||
class CMAObject
|
||||
{
|
||||
public:
|
||||
explicit CMAObject(CMAObject *parent = 0);
|
||||
~CMAObject();
|
||||
|
||||
void refreshPath();
|
||||
void rename(const QString &name);
|
||||
void updateObjectSize(qint64 size);
|
||||
bool hasParent(const CMAObject *obj);
|
||||
void initObject(const QFileInfo &file, int file_type = -1);
|
||||
|
||||
bool operator==(const CMAObject &obj);
|
||||
bool operator!=(const CMAObject &obj);
|
||||
bool operator<(const CMAObject &obj);
|
||||
|
||||
inline void setOhfi(int ohfi) {
|
||||
metadata.ohfi = ohfi;
|
||||
}
|
||||
|
||||
inline static void resetOhfiCounter() {
|
||||
ohfi_count = OHFI_OFFSET;
|
||||
}
|
||||
|
||||
QString m_path;
|
||||
CMAObject *parent;
|
||||
metadata_t metadata;
|
||||
|
||||
protected:
|
||||
static int ohfi_count;
|
||||
|
||||
private:
|
||||
void loadSfoMetadata(const QString &path);
|
||||
};
|
||||
|
||||
#endif // CMAOBJECT_H
|
154
common/cmarootobject.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmarootobject.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
QString CMARootObject::uuid = "ffffffffffffffff";
|
||||
|
||||
CMARootObject::CMARootObject(int ohfi) :
|
||||
num_filters(0), filters(NULL), root_ohfi(ohfi)
|
||||
{
|
||||
}
|
||||
|
||||
void CMARootObject::initObject(const QString &path)
|
||||
{
|
||||
metadata.ohfi = root_ohfi;
|
||||
metadata.type = VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR;
|
||||
|
||||
switch(root_ohfi) {
|
||||
case VITA_OHFI_MUSIC:
|
||||
metadata.dataType = Music;
|
||||
m_path = path;
|
||||
num_filters = 5;
|
||||
filters = new metadata_t[5];
|
||||
createFilter(&filters[0], "Artists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ARTISTS);
|
||||
createFilter(&filters[1], "Albums", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALBUMS);
|
||||
createFilter(&filters[2], "Songs", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_SONGS);
|
||||
createFilter(&filters[3], "Genres", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_GENRES);
|
||||
createFilter(&filters[4], "Playlists", VITA_DIR_TYPE_MASK_MUSIC | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_PLAYLISTS);
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PHOTO:
|
||||
metadata.dataType = Photo;
|
||||
m_path = path;
|
||||
num_filters = 3;
|
||||
filters = new metadata_t[3];
|
||||
createFilter(&filters[0], "All", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
|
||||
createFilter(&filters[1], "Month", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_MONTH);
|
||||
createFilter(&filters[2], "Folders", VITA_DIR_TYPE_MASK_PHOTO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
|
||||
break;
|
||||
|
||||
case VITA_OHFI_VIDEO:
|
||||
metadata.dataType = Video;
|
||||
m_path = path;
|
||||
num_filters = 2;
|
||||
filters = new metadata_t[2];
|
||||
createFilter(&filters[0], "All", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_ALL);
|
||||
createFilter(&filters[1], "Folders", VITA_DIR_TYPE_MASK_VIDEO | VITA_DIR_TYPE_MASK_ROOT | VITA_DIR_TYPE_MASK_REGULAR);
|
||||
break;
|
||||
|
||||
case VITA_OHFI_VITAAPP:
|
||||
metadata.dataType = App;
|
||||
m_path = QDir(QDir(path).absoluteFilePath("APP")).absoluteFilePath(uuid);
|
||||
num_filters = 0;
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PSPAPP:
|
||||
metadata.dataType = App;
|
||||
m_path = QDir(QDir(path).absoluteFilePath("PGAME")).absoluteFilePath(uuid);
|
||||
num_filters = 0;
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PSPSAVE:
|
||||
metadata.dataType = SaveData;
|
||||
m_path = QDir(QDir(path).absoluteFilePath("PSAVEDATA")).absoluteFilePath(uuid);
|
||||
num_filters = 0;
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PSXAPP:
|
||||
metadata.dataType = App;
|
||||
m_path = QDir(QDir(path).absoluteFilePath("PSGAME")).absoluteFilePath(uuid);
|
||||
num_filters = 0;
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PSMAPP:
|
||||
metadata.dataType = App;
|
||||
m_path = QDir(QDir(path).absoluteFilePath("PSM")).absoluteFilePath(uuid);
|
||||
num_filters = 0;
|
||||
break;
|
||||
|
||||
case VITA_OHFI_BACKUP:
|
||||
metadata.dataType = App;
|
||||
m_path = QDir(QDir(path).absoluteFilePath("SYSTEM")).absoluteFilePath(uuid);
|
||||
num_filters = 0;
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PACKAGE:
|
||||
metadata.dataType = Package;
|
||||
m_path = path;
|
||||
num_filters = 0;
|
||||
}
|
||||
|
||||
// create the backup directories
|
||||
QDir dir(m_path);
|
||||
dir.mkpath(dir.absolutePath());
|
||||
}
|
||||
|
||||
CMARootObject::~CMARootObject()
|
||||
{
|
||||
for(int i = 0; i < num_filters; i++) {
|
||||
free(filters[i].name);
|
||||
free(filters[i].path);
|
||||
}
|
||||
|
||||
delete[] filters;
|
||||
}
|
||||
|
||||
void CMARootObject::createFilter(metadata_t *filter, const char *name, int type)
|
||||
{
|
||||
filter->ohfiParent = metadata.ohfi;
|
||||
filter->ohfi = ohfi_count++;
|
||||
filter->name = strdup(name);
|
||||
filter->path = strdup(metadata.path ? metadata.path : "");
|
||||
filter->type = type;
|
||||
filter->dateTimeCreated = 0;
|
||||
filter->size = 0;
|
||||
filter->dataType = static_cast<DataType>(Folder | Special);
|
||||
filter->next_metadata = NULL;
|
||||
//qDebug("Added filter %s to database with OHFI %d (%s)", name, filter->ohfi, metadata.name);
|
||||
}
|
||||
|
||||
int CMARootObject::getFilters(metadata_t **p_head)
|
||||
{
|
||||
int numObjects = num_filters;
|
||||
|
||||
for(int i = 0; i < numObjects; i++) {
|
||||
filters[i].next_metadata = &filters[i + 1];
|
||||
}
|
||||
|
||||
filters[numObjects - 1].next_metadata = NULL;
|
||||
|
||||
if(p_head != NULL) {
|
||||
*p_head = filters;
|
||||
}
|
||||
|
||||
return numObjects;
|
||||
}
|
49
common/cmarootobject.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CMAROOTOBJECT_H
|
||||
#define CMAROOTOBJECT_H
|
||||
|
||||
#include "cmaobject.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
class CMARootObject : public CMAObject
|
||||
{
|
||||
public:
|
||||
explicit CMARootObject(int ohfi);
|
||||
~CMARootObject();
|
||||
|
||||
void initObject(const QString &path);
|
||||
void remove(const CMAObject *obj);
|
||||
int getFilters(metadata_t **p_head);
|
||||
|
||||
int num_filters;
|
||||
metadata_t *filters;
|
||||
static QString uuid;
|
||||
|
||||
private:
|
||||
void createFilter(metadata_t *filter, const char *name, int type);
|
||||
|
||||
int root_ohfi;
|
||||
};
|
||||
|
||||
#endif // CMAROOTOBJECT_H
|
305
common/cmautils.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmautils.h"
|
||||
#include "avdecoder.h"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QImage>
|
||||
#include <QSettings>
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#elif defined Q_OS_ANDROID
|
||||
#include <sys/vfs.h>
|
||||
#define statvfs statfs
|
||||
#else
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
#include <sys/types.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total)
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
|
||||
if(GetDiskFreeSpaceEx(dir.toStdWString().c_str(), (ULARGE_INTEGER *)free, (ULARGE_INTEGER *)total, NULL) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
struct statvfs stat;
|
||||
|
||||
if(statvfs(dir.toUtf8().data(), &stat) == 0) {
|
||||
*total = stat.f_frsize * stat.f_blocks;
|
||||
*free = stat.f_frsize * stat.f_bfree;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool removeRecursively(const QString &path)
|
||||
{
|
||||
QFileInfo file_info(path);
|
||||
|
||||
if(file_info.isDir()) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
return QDir(path).removeRecursively();
|
||||
#else
|
||||
bool result = false;
|
||||
QDir dir(path);
|
||||
|
||||
QDir::Filters filter = QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files;
|
||||
|
||||
if(dir.exists(path)) {
|
||||
foreach(QFileInfo info, dir.entryInfoList(filter, QDir::DirsFirst)) {
|
||||
if(info.isDir()) {
|
||||
result = removeRecursively(info.absoluteFilePath());
|
||||
} else {
|
||||
result = QFile::remove(info.absoluteFilePath());
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result = dir.rmdir(path);
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif
|
||||
} else {
|
||||
return QFile::remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
static QByteArray findFolderAlbumArt(const QString path, metadata_t *metadata)
|
||||
{
|
||||
QByteArray data;
|
||||
QDir folder(path);
|
||||
|
||||
QStringList files = folder.entryList(QDir::Files | QDir::Readable);
|
||||
const QStringList cover_list = QStringList() << "album" << "cover" << "front";
|
||||
const QStringList ext_list = QStringList() << "jpg" << "jpeg" << "png" << "gif";
|
||||
|
||||
foreach(const QString &file, files) {
|
||||
foreach(const QString &cover, cover_list) {
|
||||
foreach(const QString &ext, ext_list) {
|
||||
if(file.compare(QString("%1.%2").arg(cover, ext), Qt::CaseInsensitive) == 0) {
|
||||
qDebug() << "Trying to load album art from" << folder.absoluteFilePath(file);
|
||||
QImage img;
|
||||
if(img.load(folder.absoluteFilePath(file))) {
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
QImage result = img.scaled(256, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
result.save(&buffer, "JPEG");
|
||||
metadata->data.thumbnail.width = result.width();
|
||||
metadata->data.thumbnail.height = result.height();
|
||||
}
|
||||
// only try with the first match
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata)
|
||||
{
|
||||
QByteArray data;
|
||||
|
||||
if(MASK_SET(type, SaveData)) {
|
||||
QFile file(QDir(path).absoluteFilePath("ICON0.PNG"));
|
||||
|
||||
if(file.open(QIODevice::ReadOnly)) {
|
||||
data = file.readAll();
|
||||
}
|
||||
} else if(MASK_SET(type, Photo)) {
|
||||
QImage img;
|
||||
|
||||
if(img.load(path)) {
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
QImage result = img.scaled(240, 136, Qt::KeepAspectRatio, Qt::FastTransformation);
|
||||
result.save(&buffer, "JPEG");
|
||||
metadata->data.thumbnail.width = result.width();
|
||||
metadata->data.thumbnail.height = result.height();
|
||||
}
|
||||
} else if(MASK_SET(type, Music)) {
|
||||
if(MASK_SET(type, Folder)) {
|
||||
// TODO: try to load an album cover from one of the audio files.
|
||||
data = findFolderAlbumArt(path, metadata);
|
||||
} else {
|
||||
AVDecoder decoder;
|
||||
|
||||
if(decoder.open(path)) {
|
||||
data = decoder.getAudioThumbnail(256, 256);
|
||||
metadata->data.thumbnail.width = 256;
|
||||
metadata->data.thumbnail.height = 256;
|
||||
}
|
||||
}
|
||||
} else if(MASK_SET(type, Video)) {
|
||||
AVDecoder decoder;
|
||||
if(decoder.open(path)) {
|
||||
data = decoder.getVideoThumbnail(256, 256);
|
||||
metadata->data.thumbnail.width = 256;
|
||||
metadata->data.thumbnail.height = 256;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
QString readable_size(qint64 size, bool use_gib)
|
||||
{
|
||||
QStringList list;
|
||||
list << "KiB" << "MiB";
|
||||
if(use_gib) {
|
||||
list << "GiB";
|
||||
}
|
||||
|
||||
QStringListIterator i(list);
|
||||
QString unit("bytes");
|
||||
|
||||
float size_f = size;
|
||||
|
||||
while(size_f >= 1024.0 && i.hasNext()) {
|
||||
unit = i.next();
|
||||
size_f /= 1024.0;
|
||||
}
|
||||
return QString().setNum(size_f,'f',2) + " " + unit;
|
||||
}
|
||||
|
||||
int getVitaProtocolVersion()
|
||||
{
|
||||
QString protocol_mode = QSettings().value("protocolMode", "automatic").toString();
|
||||
qDebug() << "Using protocol mode: " << protocol_mode;
|
||||
|
||||
int protocol;
|
||||
|
||||
if(protocol_mode == "manual")
|
||||
{
|
||||
int index = QSettings().value("protocolIndex").toInt();
|
||||
|
||||
switch(index)
|
||||
{
|
||||
case 0:
|
||||
protocol = VITAMTP_PROTOCOL_FW_3_30;
|
||||
break;
|
||||
case 1:
|
||||
protocol = VITAMTP_PROTOCOL_FW_3_10;
|
||||
break;
|
||||
case 2:
|
||||
protocol = VITAMTP_PROTOCOL_FW_3_00;
|
||||
break;
|
||||
case 3:
|
||||
protocol = VITAMTP_PROTOCOL_FW_2_60;
|
||||
break;
|
||||
case 4:
|
||||
protocol = VITAMTP_PROTOCOL_FW_2_10;
|
||||
break;
|
||||
case 5:
|
||||
protocol = VITAMTP_PROTOCOL_FW_2_00;
|
||||
break;
|
||||
case 6:
|
||||
protocol = VITAMTP_PROTOCOL_FW_1_80;
|
||||
break;
|
||||
case 7:
|
||||
protocol = VITAMTP_PROTOCOL_FW_1_60;
|
||||
break;
|
||||
case 8:
|
||||
protocol = VITAMTP_PROTOCOL_FW_1_50;
|
||||
break;
|
||||
case 9:
|
||||
protocol = VITAMTP_PROTOCOL_FW_1_00;
|
||||
break;
|
||||
default:
|
||||
protocol = VITAMTP_PROTOCOL_MAX_VERSION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(protocol_mode == "custom")
|
||||
{
|
||||
bool ok;
|
||||
protocol = QSettings().value("protocolVersion").toInt(&ok);
|
||||
|
||||
if(!ok || protocol <= 0)
|
||||
protocol = VITAMTP_PROTOCOL_MAX_VERSION;
|
||||
}
|
||||
else
|
||||
protocol = VITAMTP_PROTOCOL_MAX_VERSION;
|
||||
|
||||
return protocol;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
bool belongsToGroup(const char *groupname)
|
||||
{
|
||||
int size_max = sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||
|
||||
if(size_max == -1)
|
||||
size_max = 1024;
|
||||
|
||||
QByteArray buf(size_max, Qt::Uninitialized);
|
||||
|
||||
group *result = NULL;
|
||||
group entry;
|
||||
|
||||
getgrnam_r(groupname, &entry, buf.data(), buf.size(), &result);
|
||||
|
||||
if(result != NULL && *result->gr_mem != NULL) {
|
||||
char **user_list = result->gr_mem;
|
||||
|
||||
int user_size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
||||
if(user_size_max == -1)
|
||||
user_size_max = 1024;
|
||||
|
||||
std::vector<char> user_buf(user_size_max);
|
||||
|
||||
uid_t user_id = getuid();
|
||||
|
||||
while(*user_list != NULL) {
|
||||
char *user_name = *user_list;
|
||||
|
||||
passwd *pw = NULL;
|
||||
passwd entry;
|
||||
|
||||
getpwnam_r(user_name, &entry, user_buf.data(), user_buf.size(), &pw);
|
||||
|
||||
if(pw != NULL && pw->pw_uid == user_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
user_list++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
59
common/cmautils.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
// Qt4 doesn't have public methods for Thread::*sleep
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
typedef QThread Sleeper;
|
||||
#else
|
||||
class Sleeper : QThread
|
||||
{
|
||||
public:
|
||||
static void sleep(unsigned long secs) {
|
||||
QThread::sleep(secs);
|
||||
}
|
||||
static void msleep(unsigned long msecs) {
|
||||
QThread::msleep(msecs);
|
||||
}
|
||||
static void usleep(unsigned long usecs) {
|
||||
QThread::usleep(usecs);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
bool removeRecursively(const QString &path);
|
||||
QString readable_size(qint64 size, bool use_gib = false);
|
||||
bool getDiskSpace(const QString &dir, quint64 *free, quint64 *total);
|
||||
QByteArray getThumbnail(const QString &path, DataType type, metadata_t *metadata);
|
||||
int getVitaProtocolVersion();
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
bool belongsToGroup(const char *groupname);
|
||||
#endif
|
||||
|
||||
|
||||
#endif // UTILS_H
|
50
common/common.pro
Normal file
@@ -0,0 +1,50 @@
|
||||
include(../config.pri)
|
||||
|
||||
TARGET = qcma_common
|
||||
QT += core network sql
|
||||
TEMPLATE = lib
|
||||
CONFIG += staticlib
|
||||
|
||||
SOURCES += \
|
||||
capability.cpp \
|
||||
cmaobject.cpp \
|
||||
cmarootobject.cpp \
|
||||
cmautils.cpp \
|
||||
sforeader.cpp \
|
||||
cmaclient.cpp \
|
||||
cmabroadcast.cpp \
|
||||
avdecoder.cpp \
|
||||
cmaevent.cpp \
|
||||
dds.cpp \
|
||||
sqlitedb.cpp \
|
||||
httpdownloader.cpp \
|
||||
qlistdb.cpp \
|
||||
database.cpp
|
||||
|
||||
HEADERS += \
|
||||
capability.h \
|
||||
cmaobject.h \
|
||||
cmarootobject.h \
|
||||
cmautils.h \
|
||||
sforeader.h \
|
||||
cmaclient.h \
|
||||
cmabroadcast.h \
|
||||
avdecoder.h \
|
||||
cmaevent.h \
|
||||
dds.h \
|
||||
sqlitedb.h \
|
||||
httpdownloader.h \
|
||||
qlistdb.h \
|
||||
database.h
|
||||
|
||||
OTHER_FILES += \
|
||||
resources/xml/psp2-updatelist.xml
|
||||
|
||||
TRANSLATIONS += \
|
||||
resources/translations/qcma_es.ts \
|
||||
resources/translations/qcma_fr.ts \
|
||||
resources/translations/qcma_ja.ts
|
||||
|
||||
RESOURCES += common.qrc translations.qrc
|
||||
|
||||
PKGCONFIG = libvitamtp libavformat libavcodec libavutil libswscale
|
5
common/common.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/main">
|
||||
<file>resources/xml/psp2-updatelist.xml</file>
|
||||
</qresource>
|
||||
</RCC>
|
152
common/database.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "database.h"
|
||||
#include "avdecoder.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
#include <QSettings>
|
||||
#include <QTextStream>
|
||||
#include <QThread>
|
||||
|
||||
const file_type audio_list[] = {
|
||||
{"mp3", FILE_FORMAT_MP3, CODEC_TYPE_MP3},
|
||||
{"mp4", FILE_FORMAT_MP4, CODEC_TYPE_AAC},
|
||||
{"wav", FILE_FORMAT_WAV, CODEC_TYPE_PCM}
|
||||
};
|
||||
|
||||
const file_type photo_list[] = {
|
||||
{"jpg", FILE_FORMAT_JPG, CODEC_TYPE_JPG},
|
||||
{"jpeg", FILE_FORMAT_JPG, CODEC_TYPE_JPG},
|
||||
{"png", FILE_FORMAT_PNG, CODEC_TYPE_PNG},
|
||||
{"tif", FILE_FORMAT_TIF, CODEC_TYPE_TIF},
|
||||
{"tiff", FILE_FORMAT_TIF, CODEC_TYPE_TIF},
|
||||
{"bmp", FILE_FORMAT_BMP, CODEC_TYPE_BMP},
|
||||
{"gif", FILE_FORMAT_GIF, CODEC_TYPE_GIF},
|
||||
};
|
||||
|
||||
const file_type video_list[] = {
|
||||
{"mp4", FILE_FORMAT_MP4, 0}
|
||||
};
|
||||
|
||||
Database::Database(QObject *obj_parent) :
|
||||
QObject(obj_parent),
|
||||
mutex(QMutex::Recursive)
|
||||
{
|
||||
}
|
||||
|
||||
void Database::process()
|
||||
{
|
||||
qDebug("Starting database_thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
|
||||
clear();
|
||||
cancel_operation = false;
|
||||
int count = create();
|
||||
cancel_operation = false;
|
||||
QTextStream(stdout) << "Total entries added to the database: " << count << endl;
|
||||
if(count < 0) {
|
||||
clear();
|
||||
}
|
||||
emit updated(count);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void Database::cancelOperation()
|
||||
{
|
||||
QMutexLocker locker(&cancel);
|
||||
cancel_operation = true;
|
||||
}
|
||||
|
||||
bool Database::continueOperation()
|
||||
{
|
||||
QMutexLocker locker(&cancel);
|
||||
return !cancel_operation;
|
||||
}
|
||||
|
||||
int Database::checkFileType(const QString path, int ohfi_root)
|
||||
{
|
||||
switch(ohfi_root) {
|
||||
case VITA_OHFI_MUSIC:
|
||||
for(int i = 0, max = sizeof(audio_list) / sizeof(file_type); i < max; i++) {
|
||||
if(path.endsWith(audio_list[i].file_ext, Qt::CaseInsensitive)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VITA_OHFI_PHOTO:
|
||||
for(int i = 0, max = sizeof(photo_list) / sizeof(file_type); i< max; i++) {
|
||||
if(path.endsWith(photo_list[i].file_ext, Qt::CaseInsensitive)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VITA_OHFI_VIDEO:
|
||||
for(int i = 0, max = sizeof(video_list) / sizeof(file_type); i< max; i++) {
|
||||
if(path.endsWith(video_list[i].file_ext, Qt::CaseInsensitive)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Database::loadMusicMetadata(const QString &path, metadata_t &metadata)
|
||||
{
|
||||
AVDecoder decoder;
|
||||
bool skipMetadata = QSettings().value("skipMetadata", false).toBool();
|
||||
|
||||
if(!skipMetadata && decoder.open(path)) {
|
||||
decoder.getAudioMetadata(metadata);
|
||||
} else {
|
||||
metadata.data.music.album = strdup("");
|
||||
metadata.data.music.artist = strdup("");
|
||||
metadata.data.music.title = strdup(metadata.name);
|
||||
}
|
||||
}
|
||||
|
||||
void Database::loadVideoMetadata(const QString &path, metadata_t &metadata)
|
||||
{
|
||||
AVDecoder decoder;
|
||||
bool skipMetadata = QSettings().value("skipMetadata", false).toBool();
|
||||
|
||||
if(!skipMetadata && decoder.open(path)) {
|
||||
decoder.getVideoMetadata(metadata);
|
||||
} else {
|
||||
metadata.data.video.title = strdup(metadata.name);
|
||||
metadata.data.video.explanation = strdup("");
|
||||
metadata.data.video.copyright = strdup("");
|
||||
// default to H264 video codec
|
||||
metadata.data.video.tracks->data.track_video.codecType = CODEC_TYPE_AVC;
|
||||
}
|
||||
}
|
||||
|
||||
void Database::loadPhotoMetadata(const QString &path, metadata_t &metadata)
|
||||
{
|
||||
QImage img;
|
||||
bool skipMetadata = QSettings().value("skipMetadata", false).toBool();
|
||||
|
||||
if(!skipMetadata && img.load(path)) {
|
||||
metadata.data.photo.tracks->data.track_photo.width = img.width();
|
||||
metadata.data.photo.tracks->data.track_photo.height = img.height();
|
||||
}
|
||||
metadata.data.photo.title = strdup(metadata.name);
|
||||
}
|
117
common/database.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DATABASE_H
|
||||
#define DATABASE_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
typedef struct {
|
||||
const char *file_ext;
|
||||
int file_format;
|
||||
int file_codec;
|
||||
} file_type;
|
||||
|
||||
#define OHFI_BASE_VALUE 256
|
||||
|
||||
#define FILE_FORMAT_MP4 1
|
||||
#define FILE_FORMAT_WAV 2
|
||||
#define FILE_FORMAT_MP3 3
|
||||
#define FILE_FORMAT_JPG 4
|
||||
#define FILE_FORMAT_PNG 5
|
||||
#define FILE_FORMAT_GIF 6
|
||||
#define FILE_FORMAT_BMP 7
|
||||
#define FILE_FORMAT_TIF 8
|
||||
|
||||
#define CODEC_TYPE_MPEG4 2
|
||||
#define CODEC_TYPE_AVC 3
|
||||
#define CODEC_TYPE_MP3 12
|
||||
#define CODEC_TYPE_AAC 13
|
||||
#define CODEC_TYPE_PCM 15
|
||||
#define CODEC_TYPE_JPG 17
|
||||
#define CODEC_TYPE_PNG 18
|
||||
#define CODEC_TYPE_TIF 19
|
||||
#define CODEC_TYPE_BMP 20
|
||||
#define CODEC_TYPE_GIF 21
|
||||
|
||||
extern const file_type audio_list[3];
|
||||
extern const file_type photo_list[7];
|
||||
extern const file_type video_list[1];
|
||||
|
||||
class Database : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Database(QObject *parent = 0);
|
||||
|
||||
virtual bool load() = 0;
|
||||
virtual bool rescan() = 0;
|
||||
virtual void setUUID(const QString &uuid) = 0;
|
||||
|
||||
virtual int childObjectCount(int parent_ohfi) = 0;
|
||||
virtual bool deleteEntry(int ohfi, int root_ohfi = 0) = 0;
|
||||
virtual QString getAbsolutePath(int ohfi) = 0;
|
||||
virtual QString getRelativePath(int ohfi) = 0;
|
||||
virtual bool getObjectList(int ohfi, metadata_t **metadata) = 0;
|
||||
virtual bool getObjectMetadata(int ohfi, metadata_t &metadata) = 0;
|
||||
virtual int getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index = 0, int max_number = 0) = 0;
|
||||
virtual qint64 getObjectSize(int ohfi) = 0;
|
||||
virtual int getPathId(const char *name, int ohfi) = 0;
|
||||
virtual int insertObjectEntry(const QString &path, const QString &name, int parent_ohfi) = 0;
|
||||
virtual bool renameObject(int ohfi, const QString &name) = 0;
|
||||
virtual void setObjectSize(int ohfi, qint64 size) = 0;
|
||||
virtual int getParentId(int ohfi) = 0;
|
||||
virtual int getRootId(int ohfi) = 0;
|
||||
virtual void freeMetadata(metadata_t *metadata) = 0;
|
||||
|
||||
static int checkFileType(const QString path, int ohfi_root);
|
||||
static void loadMusicMetadata(const QString &path, metadata_t &metadata);
|
||||
static void loadPhotoMetadata(const QString &path, metadata_t &metadata);
|
||||
static void loadVideoMetadata(const QString &path, metadata_t &metadata);
|
||||
|
||||
QMutex mutex;
|
||||
|
||||
protected:
|
||||
bool continueOperation();
|
||||
|
||||
private:
|
||||
|
||||
virtual void clear() = 0;
|
||||
virtual int create() = 0;
|
||||
|
||||
// control variables
|
||||
QMutex cancel;
|
||||
bool cancel_operation;
|
||||
|
||||
signals:
|
||||
void fileAdded(QString);
|
||||
void directoryAdded(QString);
|
||||
void updated(int);
|
||||
|
||||
protected slots:
|
||||
void process();
|
||||
|
||||
public slots:
|
||||
void cancelOperation();
|
||||
};
|
||||
|
||||
#endif // DATABASE_H
|
1032
common/dds.cpp
Normal file
30
common/dds.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KIMG_DDS_H
|
||||
#define KIMG_DDS_H
|
||||
|
||||
#include <QImage>
|
||||
#include <QString>
|
||||
|
||||
bool loadDDS(const QString &filename, QImage *image);
|
||||
|
||||
#endif
|
||||
|
||||
|
2
common/defines.pri
Normal file
@@ -0,0 +1,2 @@
|
||||
INCLUDEPATH += $$IN_PWD
|
||||
DEPENDPATH += $$IN_PWD
|
136
common/httpdownloader.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "httpdownloader.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
QNetworkReply *HTTPDownloader::reply = NULL;
|
||||
volatile qint64 HTTPDownloader::m_contentLength = -1;
|
||||
|
||||
QMutex HTTPDownloader::dataAvailable;
|
||||
QMutex HTTPDownloader::dataRead;
|
||||
|
||||
QByteArray HTTPDownloader::buffer;
|
||||
bool HTTPDownloader::bufferReady = false;
|
||||
qint64 HTTPDownloader::downloadLeft = 0;
|
||||
|
||||
HTTPDownloader::HTTPDownloader(const QString &url, QObject *obj_parent) :
|
||||
QObject(obj_parent), remote_url(url), firstRead(true)
|
||||
{
|
||||
lengthMutex.lock();
|
||||
}
|
||||
|
||||
HTTPDownloader::~HTTPDownloader()
|
||||
{
|
||||
lengthMutex.unlock();
|
||||
dataAvailable.unlock();
|
||||
}
|
||||
|
||||
void HTTPDownloader::downloadFile()
|
||||
{
|
||||
dataAvailable.lock();
|
||||
qDebug("Starting http_thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
|
||||
request = new QNetworkAccessManager(this);
|
||||
reply = request->get(QNetworkRequest(QUrl(remote_url)));
|
||||
connect(reply, SIGNAL(metaDataChanged()), this, SLOT(metadataChanged()));
|
||||
connect(reply, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||
this, SLOT(error(QNetworkReply::NetworkError)));
|
||||
connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
|
||||
connect(reply, SIGNAL(finished()), request, SLOT(deleteLater()));
|
||||
}
|
||||
|
||||
void HTTPDownloader::metadataChanged()
|
||||
{
|
||||
QVariant len = reply->header(QNetworkRequest::ContentLengthHeader);
|
||||
if(len.isValid()) {
|
||||
m_contentLength = len.toInt();
|
||||
buffer.resize(8);
|
||||
*(uint64_t *)buffer.data() = m_contentLength;
|
||||
downloadLeft = m_contentLength;
|
||||
} else {
|
||||
m_contentLength = -1;
|
||||
}
|
||||
lengthMutex.unlock();
|
||||
}
|
||||
|
||||
qint64 HTTPDownloader::getFileSize()
|
||||
{
|
||||
lengthMutex.lock();
|
||||
return m_contentLength;
|
||||
}
|
||||
|
||||
void HTTPDownloader::readyRead()
|
||||
{
|
||||
QMutexLocker locker(&dataRead);
|
||||
|
||||
downloadLeft -= reply->bytesAvailable();
|
||||
|
||||
buffer.append(reply->readAll());
|
||||
|
||||
if(buffer.size() >= 16 * 1024 || downloadLeft == 0) {
|
||||
dataAvailable.unlock();
|
||||
}
|
||||
|
||||
if(downloadLeft == 0)
|
||||
qDebug() << "remote download complete";
|
||||
}
|
||||
|
||||
int HTTPDownloader::readCallback(unsigned char *data, unsigned long wantlen, unsigned long *gotlen)
|
||||
{
|
||||
if(downloadLeft && !dataAvailable.tryLock(30000)) {
|
||||
qWarning("Connection timeout while receiving data from network, aborting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&dataRead);
|
||||
|
||||
if(buffer.size() == 0)
|
||||
return -1;
|
||||
|
||||
int read_size = wantlen > (unsigned long)buffer.size() ? buffer.size() : wantlen;
|
||||
|
||||
memcpy(data, buffer.data(), read_size);
|
||||
buffer.remove(0, read_size);
|
||||
|
||||
qDebug() << "sending data: " << read_size << ", left in buffer: " << buffer.size();
|
||||
|
||||
*gotlen = read_size;
|
||||
|
||||
return PTP_RC_OK;
|
||||
}
|
||||
|
||||
void HTTPDownloader::error(QNetworkReply::NetworkError errorCode)
|
||||
{
|
||||
Q_UNUSED(errorCode);
|
||||
QString str_error = reply->errorString();
|
||||
|
||||
qWarning() << "Network error:" << str_error;
|
||||
emit messageSent(tr("Network error: %1").arg(str_error));
|
||||
|
||||
lengthMutex.unlock();
|
||||
|
||||
// clear the buffer so a read callback can be aborted
|
||||
QMutexLocker locker(&dataRead);
|
||||
buffer.clear();
|
||||
}
|
66
common/httpdownloader.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HTTPDOWNLOADER_H
|
||||
#define HTTPDOWNLOADER_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMutex>
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
class HTTPDownloader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HTTPDownloader(const QString &url, QObject *parent = 0);
|
||||
~HTTPDownloader();
|
||||
qint64 getFileSize();
|
||||
|
||||
signals:
|
||||
void messageSent(QString);
|
||||
|
||||
public slots:
|
||||
void downloadFile();
|
||||
static int readCallback(unsigned char *data, unsigned long wantlen, unsigned long *gotlen);
|
||||
void metadataChanged();
|
||||
void readyRead();
|
||||
void error(QNetworkReply::NetworkError);
|
||||
|
||||
private:
|
||||
QString remote_url;
|
||||
QNetworkAccessManager *request;
|
||||
QMutex lengthMutex;
|
||||
bool firstRead;
|
||||
|
||||
static QMutex dataAvailable;
|
||||
static QMutex dataRead;
|
||||
|
||||
static QNetworkReply *reply;
|
||||
volatile static qint64 m_contentLength;
|
||||
|
||||
static QByteArray buffer;
|
||||
static bool bufferReady;
|
||||
static qint64 downloadLeft;
|
||||
};
|
||||
|
||||
#endif // HTTPDOWNLOADER_H
|
610
common/qlistdb.cpp
Normal file
@@ -0,0 +1,610 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cmautils.h"
|
||||
#include "qlistdb.h"
|
||||
#include "cmaobject.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QSettings>
|
||||
#include <QTextStream>
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
|
||||
QListDB::QListDB(QObject *obj_parent) :
|
||||
Database(obj_parent)
|
||||
{
|
||||
QString uuid = QSettings().value("lastAccountId", "ffffffffffffffff").toString();
|
||||
CMARootObject::uuid = uuid;
|
||||
thread = new QThread();
|
||||
moveToThread(thread);
|
||||
timer = new QTimer();
|
||||
thread->start();
|
||||
|
||||
timer->setInterval(0);
|
||||
timer->setSingleShot(true);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(process()));
|
||||
}
|
||||
|
||||
QListDB::~QListDB()
|
||||
{
|
||||
clear();
|
||||
timer->stop();
|
||||
delete timer;
|
||||
thread->quit();
|
||||
thread->wait();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
void QListDB::setUUID(const QString &uuid)
|
||||
{
|
||||
CMARootObject::uuid = uuid;
|
||||
QSettings().setValue("lastAccountId", uuid);
|
||||
}
|
||||
|
||||
bool QListDB::load()
|
||||
{
|
||||
// not implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QListDB::rescan()
|
||||
{
|
||||
if(mutex.tryLock(1000)) {
|
||||
if(CMARootObject::uuid != "ffffffffffffffff") {
|
||||
timer->start();
|
||||
return true;
|
||||
} else {
|
||||
mutex.unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QListDB::clear()
|
||||
{
|
||||
for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
|
||||
CMARootObject *first = static_cast<CMARootObject *>((*root).takeFirst());
|
||||
delete first;
|
||||
qDeleteAll(*root);
|
||||
}
|
||||
|
||||
object_list.clear();
|
||||
}
|
||||
|
||||
int QListDB::create()
|
||||
{
|
||||
int total_objects = 0;
|
||||
//QMutexLocker locker(&mutex);
|
||||
const int ohfi_array[] = { VITA_OHFI_MUSIC, VITA_OHFI_PHOTO, VITA_OHFI_VIDEO,
|
||||
VITA_OHFI_PACKAGE, VITA_OHFI_BACKUP, VITA_OHFI_VITAAPP,
|
||||
VITA_OHFI_PSPAPP, VITA_OHFI_PSPSAVE, VITA_OHFI_PSXAPP,
|
||||
VITA_OHFI_PSMAPP
|
||||
};
|
||||
CMAObject::resetOhfiCounter();
|
||||
QSettings settings;
|
||||
|
||||
for(int i = 0, max = sizeof(ohfi_array) / sizeof(int); i < max; i++) {
|
||||
CMARootObject *obj = new CMARootObject(ohfi_array[i]);
|
||||
bool skipCurrent = false;
|
||||
int dir_count;
|
||||
|
||||
switch(ohfi_array[i]) {
|
||||
case VITA_OHFI_MUSIC:
|
||||
obj->initObject(settings.value("musicPath").toString());
|
||||
skipCurrent = settings.value("musicSkip", false).toBool();
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PHOTO:
|
||||
obj->initObject(settings.value("photoPath").toString());
|
||||
skipCurrent = settings.value("photoSkip", false).toBool();
|
||||
break;
|
||||
|
||||
case VITA_OHFI_VIDEO:
|
||||
obj->initObject(settings.value("videoPath").toString());
|
||||
skipCurrent = settings.value("videoSkip", false).toBool();
|
||||
break;
|
||||
|
||||
case VITA_OHFI_BACKUP:
|
||||
case VITA_OHFI_VITAAPP:
|
||||
case VITA_OHFI_PSPAPP:
|
||||
case VITA_OHFI_PSPSAVE:
|
||||
case VITA_OHFI_PSXAPP:
|
||||
case VITA_OHFI_PSMAPP:
|
||||
obj->initObject(settings.value("appsPath").toString());
|
||||
break;
|
||||
|
||||
case VITA_OHFI_PACKAGE:
|
||||
obj->initObject(settings.value("pkgPath").toString());
|
||||
}
|
||||
|
||||
root_list list;
|
||||
list << obj;
|
||||
emit directoryAdded(obj->m_path);
|
||||
|
||||
if(!skipCurrent) {
|
||||
dir_count = recursiveScanRootDirectory(list, obj, ohfi_array[i]);
|
||||
} else {
|
||||
dir_count = 0;
|
||||
}
|
||||
|
||||
if(dir_count < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
qDebug("Added objects for OHFI 0x%02X: %i", ohfi_array[i], dir_count);
|
||||
|
||||
total_objects += dir_count;
|
||||
object_list[ohfi_array[i]] = list;
|
||||
}
|
||||
return total_objects;
|
||||
}
|
||||
|
||||
CMAObject *QListDB::getParent(CMAObject *last_dir, const QString ¤t_path)
|
||||
{
|
||||
while(last_dir && current_path != last_dir->m_path) {
|
||||
last_dir = last_dir->parent;
|
||||
}
|
||||
|
||||
return last_dir;
|
||||
}
|
||||
|
||||
int QListDB::scanRootDirectory(root_list &list, int ohfi_type)
|
||||
{
|
||||
int obj_file_type = -1;
|
||||
int total_objects = 0;
|
||||
CMAObject *last_dir = list.first();
|
||||
QDir dir(last_dir->m_path);
|
||||
dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
|
||||
QDirIterator it(dir, QDirIterator::Subdirectories);
|
||||
|
||||
while(it.hasNext()) {
|
||||
|
||||
if(!continueOperation()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
it.next();
|
||||
QFileInfo info = it.fileInfo();
|
||||
|
||||
if(info.isFile()) {
|
||||
if((obj_file_type = checkFileType(info.absoluteFilePath(), ohfi_type)) < 0) {
|
||||
//qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
CMAObject *obj = new CMAObject(getParent(last_dir, info.path()));
|
||||
obj->initObject(info, obj_file_type);
|
||||
//qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi);
|
||||
list << obj;
|
||||
|
||||
if(obj->metadata.dataType & Folder) {
|
||||
last_dir = obj;
|
||||
} else {
|
||||
total_objects++;
|
||||
}
|
||||
}
|
||||
return total_objects;
|
||||
}
|
||||
|
||||
int QListDB::recursiveScanRootDirectory(root_list &list, CMAObject *obj_parent, int ohfi_type)
|
||||
{
|
||||
int obj_file_type = -1;
|
||||
int total_objects = 0;
|
||||
|
||||
QDir dir(obj_parent->m_path);
|
||||
dir.setSorting(QDir::Name | QDir::DirsFirst);
|
||||
QFileInfoList qsl = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Time);
|
||||
|
||||
foreach(const QFileInfo &info, qsl) {
|
||||
|
||||
if(!continueOperation()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(info.isFile() && (obj_file_type = checkFileType(info.absoluteFilePath(), ohfi_type)) < 0) {
|
||||
//qDebug("Excluding %s from database", info.absoluteFilePath().toStdString().c_str());>
|
||||
} else {
|
||||
CMAObject *obj = new CMAObject(obj_parent);
|
||||
obj->initObject(info, obj_file_type);
|
||||
emit fileAdded(obj->metadata.name);
|
||||
//qDebug("Added %s to database with OHFI %d", obj->metadata.name, obj->metadata.ohfi);
|
||||
list << obj;
|
||||
if(info.isDir()) {
|
||||
emit directoryAdded(obj->m_path);
|
||||
total_objects += recursiveScanRootDirectory(list, obj, ohfi_type);
|
||||
} else {
|
||||
total_objects++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_objects;
|
||||
}
|
||||
|
||||
bool QListDB::removeInternal(root_list &list, int ohfi)
|
||||
{
|
||||
bool found = false;
|
||||
QList<CMAObject *>::iterator it = list.begin();
|
||||
|
||||
while(it != list.end()) {
|
||||
if(!found && (*it)->metadata.ohfi == ohfi) {
|
||||
// update the size of the parent objects
|
||||
(*it)->updateObjectSize(-(*it)->metadata.size);
|
||||
it = list.erase(it);
|
||||
found = true;
|
||||
} else if(found && (*it)->metadata.ohfiParent == ohfi) {
|
||||
it = list.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool QListDB::lessThanComparator(const CMAObject *a, const CMAObject *b)
|
||||
{
|
||||
return a->metadata.ohfi < b->metadata.ohfi;
|
||||
}
|
||||
|
||||
bool QListDB::hasFilter(const CMARootObject *object,int ohfi)
|
||||
{
|
||||
for(int i = 0; i < object->num_filters; i++) {
|
||||
if(object->filters[i].ohfi == ohfi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QListDB::findInternal(const root_list &list, int ohfi, find_data &data)
|
||||
{
|
||||
if(hasFilter(static_cast<CMARootObject *>(list.first()), ohfi)) {
|
||||
data.it = list.begin();
|
||||
} else {
|
||||
CMAObject obj;
|
||||
obj.setOhfi(ohfi);
|
||||
data.it = qBinaryFind(list.begin(), list.end(), &obj, QListDB::lessThanComparator);
|
||||
}
|
||||
data.end = list.end();
|
||||
return data.it != data.end;
|
||||
}
|
||||
|
||||
bool QListDB::find(int ohfi, QListDB::find_data &data)
|
||||
{
|
||||
for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
|
||||
if(findInternal(*root, ohfi, data)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CMAObject *QListDB::ohfiToObject(int ohfi)
|
||||
{
|
||||
find_data data;
|
||||
return find(ohfi, data) ? *data.it : NULL;
|
||||
}
|
||||
|
||||
CMAObject *QListDB::pathToObjectInternal(const root_list &list, const char *path)
|
||||
{
|
||||
// skip the first element since is the root element
|
||||
root_list::const_iterator skipped_first = ++list.begin();
|
||||
|
||||
for(root_list::const_iterator obj = skipped_first; obj != list.end(); ++obj) {
|
||||
if(strcasecmp(path, (*obj)->metadata.path) == 0) {
|
||||
return (*obj);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int QListDB::acceptFilteredObject(const CMAObject *obj_parent, const CMAObject *current, int type)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
int result = 0;
|
||||
|
||||
if(MASK_SET(type, VITA_DIR_TYPE_MASK_PHOTO)) {
|
||||
result = (current->metadata.dataType & Photo);
|
||||
} else if(MASK_SET(type, VITA_DIR_TYPE_MASK_VIDEO)) {
|
||||
result = (current->metadata.dataType & Video);
|
||||
} else if(MASK_SET(type, VITA_DIR_TYPE_MASK_MUSIC)) {
|
||||
result = (current->metadata.dataType & Music);
|
||||
}
|
||||
|
||||
if(MASK_SET(type, VITA_DIR_TYPE_MASK_ARTISTS)) {
|
||||
// unimplemented
|
||||
return 0;
|
||||
} else if(MASK_SET(type, VITA_DIR_TYPE_MASK_GENRES)) {
|
||||
// unimplemented
|
||||
return 0;
|
||||
} else if(MASK_SET(type, VITA_DIR_TYPE_MASK_PLAYLISTS)) {
|
||||
// unimplemented
|
||||
return 0;
|
||||
} else if(MASK_SET(type, VITA_DIR_TYPE_MASK_MONTH)) {
|
||||
// unimplemented
|
||||
return 0;
|
||||
} else if(type & (VITA_DIR_TYPE_MASK_ALL | VITA_DIR_TYPE_MASK_SONGS)) {
|
||||
result = result && (current->metadata.dataType & File);
|
||||
} else if(type & (VITA_DIR_TYPE_MASK_REGULAR)) {
|
||||
result = (obj_parent->metadata.ohfi == current->metadata.ohfiParent);
|
||||
}
|
||||
|
||||
// TODO: Support other filter types
|
||||
return result;
|
||||
}
|
||||
|
||||
void QListDB::dumpMetadataList(const metadata_t *p_head)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
while(p_head) {
|
||||
qDebug("Metadata: %s with OHFI %d", p_head->name, p_head->ohfi);
|
||||
p_head = p_head->next_metadata;
|
||||
}
|
||||
}
|
||||
|
||||
bool QListDB::getObjectMetadata(int ohfi, metadata_t &metadata)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
CMAObject *obj = ohfiToObject(ohfi);
|
||||
if(obj) {
|
||||
//TODO: return the pointer instead of copying the struct
|
||||
metadata = obj->metadata;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int QListDB::childObjectCount(int parent_ohfi)
|
||||
{
|
||||
return getObjectMetadatas(parent_ohfi, NULL);
|
||||
}
|
||||
|
||||
bool QListDB::deleteEntry(int ohfi, int root_ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
if(root_ohfi) {
|
||||
return removeInternal(object_list[root_ohfi], ohfi);
|
||||
} else {
|
||||
for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
|
||||
if(removeInternal(*root, ohfi)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QListDB::getObjectList(int ohfi, metadata_t **metadata)
|
||||
{
|
||||
find_data iters;
|
||||
if(find(ohfi, iters)) {
|
||||
CMAObject *object;
|
||||
do {
|
||||
object = *iters.it;
|
||||
*metadata = &object->metadata;
|
||||
metadata = &(*metadata)->next_metadata;
|
||||
*metadata = NULL;
|
||||
object = *++iters.it;
|
||||
} while(iters.it != iters.end && object->metadata.ohfiParent >= OHFI_OFFSET);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int QListDB::getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index, int max_number)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
CMARootObject *obj_parent = static_cast<CMARootObject *>(ohfiToObject(parent_ohfi));
|
||||
|
||||
if(obj_parent == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(obj_parent->metadata.dataType & File) {
|
||||
*metadata = &obj_parent->metadata;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int type = obj_parent->metadata.type;
|
||||
|
||||
if(obj_parent->metadata.ohfi < OHFI_OFFSET && obj_parent->filters) { // if we have filters
|
||||
if(parent_ohfi == obj_parent->metadata.ohfi) { // if we are looking at root
|
||||
return obj_parent->getFilters(metadata);
|
||||
} else { // we are looking at a filter
|
||||
for(int j = 0; j < obj_parent->num_filters; j++) {
|
||||
if(obj_parent->filters[j].ohfi == parent_ohfi) {
|
||||
type = obj_parent->filters[j].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
int numObjects = 0;
|
||||
metadata_t temp = metadata_t();
|
||||
metadata_t *tail = &temp;
|
||||
|
||||
for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
|
||||
for(root_list::iterator object = (*root).begin(); object != (*root).end(); ++object) {
|
||||
if(acceptFilteredObject(obj_parent, *object, type)) {
|
||||
if(offset++ >= index) {
|
||||
tail->next_metadata = &(*object)->metadata;
|
||||
tail = tail->next_metadata;
|
||||
numObjects++;
|
||||
}
|
||||
|
||||
if(max_number > 0 && numObjects >= max_number) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(numObjects > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tail->next_metadata = NULL;
|
||||
|
||||
if(metadata != NULL) {
|
||||
*metadata = temp.next_metadata;
|
||||
}
|
||||
|
||||
return numObjects;
|
||||
}
|
||||
|
||||
qint64 QListDB::getObjectSize(int ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
CMAObject *obj = ohfiToObject(ohfi);
|
||||
return obj ? obj->metadata.size : -1;
|
||||
}
|
||||
|
||||
int QListDB::getPathId(const char *name, int ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
|
||||
|
||||
if(ohfi && (*root).first()->metadata.ohfi != ohfi) {
|
||||
continue;
|
||||
}
|
||||
CMAObject *obj = pathToObjectInternal(*root, name);
|
||||
|
||||
if(obj) {
|
||||
return obj->metadata.ohfi;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QListDB::insertObjectEntry(const QString &path, const QString &name, int parent_ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
CMAObject *parent_obj = ohfiToObject(parent_ohfi);
|
||||
|
||||
for(map_list::iterator root = object_list.begin(); root != object_list.end(); ++root) {
|
||||
root_list *cat_list = &(*root);
|
||||
root_list::const_iterator it = qBinaryFind(cat_list->begin(), cat_list->end(), parent_obj, QListDB::lessThanComparator);
|
||||
|
||||
if(it != cat_list->end()) {
|
||||
CMAObject *newobj = new CMAObject(parent_obj);
|
||||
|
||||
// get the root object
|
||||
while(parent_obj->parent) {
|
||||
parent_obj = parent_obj->parent;
|
||||
}
|
||||
|
||||
QFileInfo info(path, name);
|
||||
newobj->initObject(info, parent_obj->metadata.dataType);
|
||||
cat_list->append(newobj);
|
||||
return newobj->metadata.ohfi;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString QListDB::getAbsolutePath(int ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
CMAObject *obj = ohfiToObject(ohfi);
|
||||
return obj ? obj->m_path : NULL;
|
||||
}
|
||||
|
||||
QString QListDB::getRelativePath(int ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
CMAObject *obj = ohfiToObject(ohfi);
|
||||
return obj ? obj->metadata.path : NULL;
|
||||
}
|
||||
|
||||
bool QListDB::renameObject(int ohfi, const QString &name)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
CMAObject *root = ohfiToObject(ohfi);
|
||||
|
||||
if(!root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//rename the current object
|
||||
root->rename(name);
|
||||
QListDB::find_data iters;
|
||||
find(root->metadata.ohfi, iters);
|
||||
|
||||
// rename the rest of the list only if has the renamed parent in some part of the chain
|
||||
while(iters.it != iters.end) {
|
||||
CMAObject *obj = *iters.it++;
|
||||
|
||||
if(obj->hasParent(root)) {
|
||||
obj->refreshPath();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QListDB::setObjectSize(int ohfi, qint64 size)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
CMAObject *obj = ohfiToObject(ohfi);
|
||||
|
||||
if(obj) {
|
||||
obj->updateObjectSize(size);
|
||||
}
|
||||
}
|
||||
|
||||
int QListDB::getRootId(int ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
CMAObject *obj = ohfiToObject(ohfi);
|
||||
|
||||
if(!obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(obj->parent) {
|
||||
obj = obj->parent;
|
||||
}
|
||||
|
||||
return obj->metadata.ohfi;
|
||||
}
|
||||
|
||||
int QListDB::getParentId(int ohfi)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
CMAObject *obj = ohfiToObject(ohfi);
|
||||
|
||||
return obj ? obj->metadata.ohfiParent : 0;
|
||||
}
|
95
common/qlistdb.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QLISTDB_H
|
||||
#define QLISTDB_H
|
||||
|
||||
#include "database.h"
|
||||
#include "cmarootobject.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
class QListDB : public Database
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QListDB(QObject *parent = 0);
|
||||
~QListDB();
|
||||
|
||||
bool load();
|
||||
bool rescan();
|
||||
void close();
|
||||
void clear();
|
||||
|
||||
bool reload(bool &prepared);
|
||||
void setUUID(const QString &uuid);
|
||||
|
||||
int childObjectCount(int parent_ohfi);
|
||||
bool deleteEntry(int ohfi, int root_ohfi = 0);
|
||||
QString getAbsolutePath(int ohfi);
|
||||
bool getObjectList(int ohfi, metadata_t **metadata);
|
||||
bool getObjectMetadata(int ohfi, metadata_t &metadata);
|
||||
int getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index = 0, int max_number = 0);
|
||||
qint64 getObjectSize(int ohfi);
|
||||
int getParentId(int ohfi);
|
||||
int getPathId(const char *name, int ohfi);
|
||||
QString getRelativePath(int ohfi);
|
||||
int getRootId(int ohfi);
|
||||
int insertObjectEntry(const QString &path, const QString &name, int parent_ohfi);
|
||||
bool renameObject(int ohfi, const QString &name);
|
||||
void setObjectSize(int ohfi, qint64 size);
|
||||
void freeMetadata(metadata_t *metadata) {
|
||||
Q_UNUSED(metadata);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
QList<CMAObject *>::const_iterator it;
|
||||
QList<CMAObject *>::const_iterator end;
|
||||
} find_data;
|
||||
|
||||
typedef QList<CMAObject *> root_list;
|
||||
typedef QMap<int, root_list> map_list;
|
||||
|
||||
int create();
|
||||
int scanRootDirectory(root_list &list,int ohfi_type);
|
||||
int recursiveScanRootDirectory(root_list &list, CMAObject *parent, int ohfi_type);
|
||||
bool hasFilter(const CMARootObject *object,int ohfi);
|
||||
bool removeInternal(root_list &list, int ohfi);
|
||||
bool findInternal(const root_list &list, int ohfi, find_data &data);
|
||||
CMAObject *getParent(CMAObject *last_dir, const QString ¤t_path);
|
||||
CMAObject *pathToObjectInternal(const root_list &list, const char *path);
|
||||
static bool lessThanComparator(const CMAObject *a, const CMAObject *b);
|
||||
void dumpMetadataList(const metadata_t *p_head);
|
||||
bool find(int ohfi, find_data &data);
|
||||
int acceptFilteredObject(const CMAObject *parent, const CMAObject *current, int type);
|
||||
CMAObject *ohfiToObject(int ohfi);
|
||||
|
||||
QTimer *timer;
|
||||
QThread *thread;
|
||||
map_list object_list;
|
||||
};
|
||||
|
||||
#endif // QLISTDB_H
|
530
common/resources/translations/qcma_es.ts
Normal file
@@ -0,0 +1,530 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="es_ES">
|
||||
<context>
|
||||
<name>BackupItem</name>
|
||||
<message>
|
||||
<source>Delete entry</source>
|
||||
<translation type="vanished">Borrar entrada</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open folder</source>
|
||||
<translation type="vanished">Abrir directorio</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BackupManagerForm</name>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestor de Respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Online ID / Username</source>
|
||||
<translation type="vanished">ID Online / Nombre de usuario</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Type</source>
|
||||
<translation type="vanished">Tipo de respaldo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PS Vita Games</source>
|
||||
<translation type="vanished">Juegos PS Vita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSP Games</source>
|
||||
<translation type="vanished">Juegos PSP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSM Games</source>
|
||||
<translation type="vanished">Juegos PSM</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSOne Games</source>
|
||||
<translation type="vanished">Juegos PSOne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSP Savedatas</source>
|
||||
<translation type="vanished">Salvados PSP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backups</source>
|
||||
<translation type="vanished">Respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup disk usage</source>
|
||||
<translation type="vanished">Uso de disco en respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Filter</source>
|
||||
<translation type="vanished">Filtro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default account</source>
|
||||
<translation type="vanished">Cuenta por defecto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to remove the backup of the following entry?</source>
|
||||
<translation type="vanished">¿Estas seguro de borrar la siguiente entrada?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup disk usage: %1</source>
|
||||
<translation type="vanished">Uso de disco en respaldos: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [GAME]</source>
|
||||
<translation type="vanished"> [JUEGO]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [SAVE]</source>
|
||||
<translation type="vanished"> [SALVADO]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [UPDATE]</source>
|
||||
<translation type="vanished"> [ACTUALIZACIÓN]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [DLC]</source>
|
||||
<translation type="vanished"> [DLC]</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ClientManager</name>
|
||||
<message>
|
||||
<source>Added %1 items to the database</source>
|
||||
<translation type="vanished">Agregadas %1 entradas a la base de datos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database indexing aborted by user</source>
|
||||
<translation type="vanished">Actualización de la base de datos cancelada por el usuario</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cannot initialize VitaMTP library</source>
|
||||
<translation type="vanished">No se pudo inicializar VitaMTP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This user doesn't belong to the vitamtp group, there could be a problem while reading the USB bus.</source>
|
||||
<translation type="vanished">Este usuario no pertenece al grupo vitamtp, puede haber problemas al leer el bus USB.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must enable at least USB or Wireless monitoring</source>
|
||||
<translation type="vanished">Debe habilitar por lo menos el monitoreo USB o inalámbrico</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No PS Vita system has been registered</source>
|
||||
<translation type="vanished">Nigún sistema PS Vita ha sido registrado</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CmaClient</name>
|
||||
<message>
|
||||
<location filename="../../cmaclient.cpp" line="151"/>
|
||||
<location filename="../../cmaclient.cpp" line="154"/>
|
||||
<source>Connected to %1 (PS Vita)</source>
|
||||
<translation>Conectado a %1 (PS Vita)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfigWidget</name>
|
||||
<message>
|
||||
<source>QCMA Settings</source>
|
||||
<translation type="vanished">Ajustes QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Folders</source>
|
||||
<translation type="vanished">Directorios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specify the folders that the PS Vita will access for each content type.</source>
|
||||
<translation type="vanished">Especificar los directorios que el sistema PS Vita accederá para cada tipo de contenido.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Screenshots and Pictures are Saved to/Imported from.</source>
|
||||
<translation type="vanished">Esta es la ubicación donde tus capturas de pantalla e imágenes serán almacenadas o importadas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Photo Folder</source>
|
||||
<translation type="vanished">Directorio de Fotos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Browse...</source>
|
||||
<translation type="vanished">Buscar...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Videos are Saved to/Imported from.</source>
|
||||
<translation type="vanished">Esta es la ubicación donde tus videos serán almacenados o importados.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video Folder</source>
|
||||
<translation type="vanished">Directorio de Videos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Music is Saved to/Imported from.</source>
|
||||
<translation type="vanished">Esta es la ubicación donde tu música será almacenada o importada.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Music Folder</source>
|
||||
<translation type="vanished">Directorio de Música</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Games, Apps, Savegames, and System Backups are Saved to/Imported from.</source>
|
||||
<translation type="vanished">Esta es la ubicación donde tus juegos, aplicaciones, partidas salvadas y respaldos del sistema serán almacenados o importados.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Applications / Backups</source>
|
||||
<translation type="vanished">Aplicaciones / Juegos / Respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Software Updates and Browser Data is Saved to/Imported from.</source>
|
||||
<translation type="vanished">Esta es la ubicación donde el sistema PS Vita leerá los contenidos que intente descargar.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Updates / Web content</source>
|
||||
<translation type="vanished">Actualizaciones / Contenido Web</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your PS Vita system will read all the content that it tries to download.</source>
|
||||
<translation type="vanished">Esta es la ubicación donde el sistema PS Vita leerá los contenidos que intente descargar.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Packages</source>
|
||||
<translation type="vanished">Archivos PKG</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Other</source>
|
||||
<translation type="vanished">Otros</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600;">Advanced settings</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600;">Ajustes Avanzados</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offline Mode</source>
|
||||
<translation type="vanished">Modo desconectado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip metadata extraction</source>
|
||||
<translation type="vanished">Saltar la extracción de metadatos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database automatically when files on the PC are changed</source>
|
||||
<translation type="vanished">Actualizar la base de datos automaticamente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SQLite</source>
|
||||
<translation type="vanished">SQLite</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip photo scanning</source>
|
||||
<translation type="vanished">Omitir el escaneo de fotos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip video scanning</source>
|
||||
<translation type="vanished">Omitir el escaneo de vídeos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip music scanning</source>
|
||||
<translation type="vanished">Omitir el escaneo de música</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CMA protocol version</source>
|
||||
<translation type="vanished">Versión de protocolo CMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CMA protocol selection</source>
|
||||
<translation type="vanished">Uso de protocolo CMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Latest</source>
|
||||
<translation type="vanished">Último</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Manual</source>
|
||||
<translation type="vanished">Manual</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom</source>
|
||||
<translation type="vanished">Personalizado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CMA custom version</source>
|
||||
<translation type="vanished">Versión personalizada CMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable USB monitoring</source>
|
||||
<translation type="vanished">Deshabilitar monitoreo USB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Wi-Fi monitoring</source>
|
||||
<translation type="vanished">Deshabilitar monitoreo WiFi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database backend</source>
|
||||
<translation type="vanished">Almacenaje de base de datos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>In Memory</source>
|
||||
<translation type="vanished">En memoria</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a photo source</source>
|
||||
<translation type="vanished">Seleccione el directorio a ser utilizado como origen de fotos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a music source</source>
|
||||
<translation type="vanished">Seleccione el directorio a ser utilizado como origen de música</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a video source</source>
|
||||
<translation type="vanished">Seleccione el directorio a ser utilizado como origen de videos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to save PS Vita games and backups</source>
|
||||
<translation type="vanished">Seleccione el directorio a ser utilizado para guardar juegos y respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to fetch software updates</source>
|
||||
<translation type="vanished">Seleccione el directorio a ser utilizado para extraer actualizaciones de software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to software packages</source>
|
||||
<translation type="vanished">Seleccione el directorio a ser utilizado para almacenar archivos pkg</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfirmDialog</name>
|
||||
<message>
|
||||
<source>Confirmation Message</source>
|
||||
<translation type="vanished">Mensaje de confirmación</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FilterLineEdit</name>
|
||||
<message>
|
||||
<source>Filter</source>
|
||||
<translation type="vanished">Filtro</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HTTPDownloader</name>
|
||||
<message>
|
||||
<location filename="../../httpdownloader.cpp" line="129"/>
|
||||
<source>Network error: %1</source>
|
||||
<translation>Error de red: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HeadlessManager</name>
|
||||
<message>
|
||||
<source>This user doesn't belong to the vitamtp group, there could be a problem while reading the USB bus.</source>
|
||||
<translatorcomment>Este usuario no pertenece al grupo vitamtp, puede haber problemas al leer el bus USB.</translatorcomment>
|
||||
<translation type="vanished">Este usuario no pertenece al grupo vitamtp, puede haber problemas al leer el bus USB.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>KDENotifierTray</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">Refrescar base de datos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestor de Respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">Acerca de QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">Acerca de Qt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">Salir</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qcma status</source>
|
||||
<translation type="vanished">Estado de Qcma</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
<translation type="vanished">Desconectado</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWidget</name>
|
||||
<message>
|
||||
<source>Shutting down...</source>
|
||||
<translation type="vanished">Cerrando...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stopping QCMA (disconnect your PS Vita)</source>
|
||||
<translation type="vanished">Deteniendo QCMA (desconecte su PS Vita)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
<translation type="vanished">Desconectado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The device has been disconnected</source>
|
||||
<translation type="vanished">El dispositivo se ha desconectado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qcma</source>
|
||||
<translation type="vanished">Acerca de Qcma</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyright (C) 2015 Codestation</source>
|
||||
<translation type="vanished">Copyright (C) 2015 Codestation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyright (C) 2015 Codestation
|
||||
|
||||
build hash: %1
|
||||
build branch: %2</source>
|
||||
<translation type="vanished">Copyright (C) 2015 Codestation
|
||||
|
||||
Hash de compilación: %1
|
||||
Rama de compilación: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation type="vanished">Información</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PinForm</name>
|
||||
<message>
|
||||
<source>Device pairing</source>
|
||||
<translation type="vanished">Emparejamiento de dispositivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An unregistered PS Vita system is connecting with QCMA via Wi-Fi</source>
|
||||
<translation type="vanished">Un sistema PS Vita no registrado se intenta conectar con QCMA mediante Wi-Fi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device: PS Vita</source>
|
||||
<translation type="vanished">Dispositivo: PS Vita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Input the following number in the PS Vita system to register it with QCMA</source>
|
||||
<translation type="vanished">Introduce el siguiente número en el sistema PS Vita para registrarlo con QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Time remaining: 300 seconds</source>
|
||||
<translation type="vanished">Tiempo restante: 300 segundos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="vanished">Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device: %1 (PS Vita)</source>
|
||||
<translation type="vanished">Dispositivo: %1 (PS Vita)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Time remaining: %1 seconds</source>
|
||||
<translation type="vanished">Tiempo restante: %1 segundos</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ProgressForm</name>
|
||||
<message>
|
||||
<source>Refreshing database...</source>
|
||||
<translation type="vanished">Actualizando base de datos...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Reading directory:</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Leyendo directorio:</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>directory name</source>
|
||||
<translation type="vanished">Cargando nombre de directorio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Processing file:</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Procesando archivo:</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>file name</source>
|
||||
<translation type="vanished">Cargando nombre de archivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="vanished">Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database indexing in progress</source>
|
||||
<translation type="vanished">Actualización de base de datos en progreso</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to cancel the database indexing?</source>
|
||||
<translation type="vanished">¿Estas seguro de cancelar la actualización a la base de datos?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<source>An instance of Qcma is already running</source>
|
||||
<translation type="vanished">Otra instancia de Qcma ya se encuentra en ejecución</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QTrayIcon</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">Refrescar base de datos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestor de Respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">Acerca de QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">Acerca de Qt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">Salir</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UnityIndicator</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">Refrescar base de datos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestor de Respaldos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">Acerca de QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">Acerca de Qt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">Salir</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
508
common/resources/translations/qcma_fr.ts
Normal file
@@ -0,0 +1,508 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="fr_FR">
|
||||
<context>
|
||||
<name>BackupItem</name>
|
||||
<message>
|
||||
<source>Delete entry</source>
|
||||
<translation type="vanished">Supprimer l'entrée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open folder</source>
|
||||
<translation type="vanished">Ouvrir le répertoire</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BackupManagerForm</name>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestonaire de Sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Online ID / Username</source>
|
||||
<translation type="vanished">ID Online / Nom d'utilisateur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Type</source>
|
||||
<translation type="vanished">Type de sauvegarde</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PS Vita Games</source>
|
||||
<translation type="vanished">Jeux PS Vita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSP Games</source>
|
||||
<translation type="vanished">Jeux PSP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSM Games</source>
|
||||
<translation type="vanished">Jeux PSM</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSOne Games</source>
|
||||
<translation type="vanished">Jeux PSOne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSP Savedatas</source>
|
||||
<translation type="vanished">Sauvegardes PSP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backups</source>
|
||||
<translation type="vanished">Sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup disk usage</source>
|
||||
<translation type="vanished">Utilisation du disque par les sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Filter</source>
|
||||
<translation type="vanished">Filtrer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default account</source>
|
||||
<translation type="vanished">Compte par défaut</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to remove the backup of the following entry?</source>
|
||||
<translation type="vanished">Êtes-vous sur de voulloir supprimer cette sauvegarde?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup disk usage: %1</source>
|
||||
<translation type="vanished">Utilisation du disque de sauvegarde: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [GAME]</source>
|
||||
<translation type="vanished"> [JEU]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [SAVE]</source>
|
||||
<translation type="vanished"> [SAUVEGARDE]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [UPDATE]</source>
|
||||
<translation type="vanished"> [MISE_A_JOUR]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [DLC]</source>
|
||||
<translation type="vanished"> [DLC]</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ClientManager</name>
|
||||
<message>
|
||||
<source>Added %1 items to the database</source>
|
||||
<translation type="vanished">%1 éléments ont été rajoutés à la base de données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database indexing aborted by user</source>
|
||||
<translation type="vanished">Mise à jour de la base de données annulée par l'utilisateur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cannot initialize VitaMTP library</source>
|
||||
<translation type="vanished">Impossible d'initaliser la librairie VitaMTP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must enable at least USB or Wireless monitoring</source>
|
||||
<translation type="vanished">Vous devez soit activer la connexion par Wifi, soit activer celle par USB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No PS Vita system has been registered</source>
|
||||
<translation type="vanished">Aucunne PS Vita reconnue</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CmaClient</name>
|
||||
<message>
|
||||
<location filename="../../cmaclient.cpp" line="151"/>
|
||||
<location filename="../../cmaclient.cpp" line="154"/>
|
||||
<source>Connected to %1 (PS Vita)</source>
|
||||
<translation>Connecté à %1 (PS Vita)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfigWidget</name>
|
||||
<message>
|
||||
<source>QCMA Settings</source>
|
||||
<translation type="vanished">Configuration de QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Folders</source>
|
||||
<translation type="vanished">Répertoires</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specify the folders that the PS Vita will access for each content type.</source>
|
||||
<translation type="vanished">Choisissez les répertoires que la PS Vita va acceder pour chaque type de contenu.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Screenshots and Pictures are Saved to/Imported from.</source>
|
||||
<translation type="vanished">Emplacement pour Copier/Importer les Copies d'écrans et les Photos.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Photo Folder</source>
|
||||
<translation type="vanished">Répertoire des Photos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Browse...</source>
|
||||
<translation type="vanished">Selectionner...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Videos are Saved to/Imported from.</source>
|
||||
<translation type="vanished">Emplacement pour Copier/Importer les Vidéos.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video Folder</source>
|
||||
<translation type="vanished">Répertoire des Vidéos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Music is Saved to/Imported from.</source>
|
||||
<translation type="vanished">Emplacement pour Copier/Importer les Musiques.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Music Folder</source>
|
||||
<translation type="vanished">Répertoire des Musiques</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Games, Apps, Savegames, and System Backups are Saved to/Imported from.</source>
|
||||
<translation type="vanished">Emplacement pour Copier/Importer les Jeux, Applications & Sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Applications / Backups</source>
|
||||
<translation type="vanished">Applications / Jeux / Sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Software Updates and Browser Data is Saved to/Imported from.</source>
|
||||
<translation type="vanished">Emplacement pour Copier/Importer les mises à jours du logiciel de la Vita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Updates / Web content</source>
|
||||
<translation type="vanished">Mise à jours / Contenu Web</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your PS Vita system will read all the content that it tries to download.</source>
|
||||
<translation type="vanished">Emplacement pour Copier/Importer les contenus téléchargés.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Packages</source>
|
||||
<translation type="vanished">Archive des Packages</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Other</source>
|
||||
<translation type="vanished">Autres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600;">Advanced settings</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600;">Options Avancées</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offline Mode</source>
|
||||
<translation type="vanished">Mode déconnecté</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip metadata extraction</source>
|
||||
<translation type="vanished">Passer l'extracion de métadonnées</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database automatically when files on the PC are changed</source>
|
||||
<translation type="vanished">Mise à jour automatique de la base de données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SQLite</source>
|
||||
<translation type="vanished">SQLite</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip photo scanning</source>
|
||||
<translation type="vanished">Passer le scan des photos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip video scanning</source>
|
||||
<translation type="vanished">Passer le scan des videos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip music scanning</source>
|
||||
<translation type="vanished">Passer le scan des musiques</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CMA protocol version</source>
|
||||
<translation type="vanished">Version du protocol CMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CMA protocol selection</source>
|
||||
<translation type="vanished">Utilisation du protocolo CMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Latest</source>
|
||||
<translation type="vanished">Dernier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Manual</source>
|
||||
<translation type="vanished">Manuel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom</source>
|
||||
<translation type="vanished">Personalisé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CMA custom version</source>
|
||||
<translation type="vanished">Version CMA personalisée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable USB monitoring</source>
|
||||
<translation type="vanished">Désactiver la surveillance USB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Wi-Fi monitoring</source>
|
||||
<translation type="vanished">Désactiver la surveillance WiFi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database backend</source>
|
||||
<translation type="vanished">Moteur de base de données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>In Memory</source>
|
||||
<translation type="vanished">En memoire</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a photo source</source>
|
||||
<translation type="vanished">Choisissez le répertoire à utiliser comme source de photos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a music source</source>
|
||||
<translation type="vanished">Choisissez le répertoire à utiliser comme source de musiques</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a video source</source>
|
||||
<translation type="vanished">Choisissez le répertoire à utiliser comme source de videos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to save PS Vita games and backups</source>
|
||||
<translation type="vanished">Choisissez le répertoire à utiliser pour sauvegarder les jeux PS Vita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to fetch software updates</source>
|
||||
<translation type="vanished">Choisissez le répertoire à utiliser pour recevoir les mise à jour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to software packages</source>
|
||||
<translation type="vanished">Choisissez le répertoire à utiliser pour ranger les packages de software</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfirmDialog</name>
|
||||
<message>
|
||||
<source>Confirmation Message</source>
|
||||
<translation type="vanished">Message de confirmation</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FilterLineEdit</name>
|
||||
<message>
|
||||
<source>Filter</source>
|
||||
<translation type="vanished">Filtre</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HTTPDownloader</name>
|
||||
<message>
|
||||
<location filename="../../httpdownloader.cpp" line="129"/>
|
||||
<source>Network error: %1</source>
|
||||
<translation>Erreur réseau: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>KDENotifierTray</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">Paramètres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">Mise à jour de la DB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestonaire de Sauvegards</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">À propos de QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">À propos de Qt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">Quitter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qcma status</source>
|
||||
<translation type="vanished">État de Qcma</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
<translation type="vanished">Déconnecté</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWidget</name>
|
||||
<message>
|
||||
<source>Shutting down...</source>
|
||||
<translation type="vanished">Fin du programme...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stopping QCMA (disconnect your PS Vita)</source>
|
||||
<translation type="vanished">Arrêter QCMA (déconnecte votre PS Vita)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
<translation type="vanished">Déconnecté</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The device has been disconnected</source>
|
||||
<translation type="vanished">L'appareil a été déconnecté</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyright (C) 2015 Codestation</source>
|
||||
<translation type="obsolete">Copyright (C) 2014 Codestation {2015 ?}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyright (C) 2015 Codestation
|
||||
|
||||
build hash: %1
|
||||
build branch: %2</source>
|
||||
<translation type="obsolete">Copyright (C) 2014 Codestation
|
||||
|
||||
Hash de compilación: %1
|
||||
Rama de compilación: %2 {2015 ?} {1
|
||||
?}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation type="vanished">Information</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PinForm</name>
|
||||
<message>
|
||||
<source>Device pairing</source>
|
||||
<translation type="vanished">Pairage d'appareil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An unregistered PS Vita system is connecting with QCMA via Wi-Fi</source>
|
||||
<translation type="vanished">Un systême PS Vita inconnu essaye de se connecter à QCMA par Wi-Fi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device: PS Vita</source>
|
||||
<translation type="vanished">Appareil: PS Vita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Input the following number in the PS Vita system to register it with QCMA</source>
|
||||
<translation type="vanished">Introduisez ce numero d'identification dans le systême PS Vita pour l'enregistrer avec QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Time remaining: 300 seconds</source>
|
||||
<translation type="vanished">Temps restant: 300 secondes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="vanished">Annuler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device: %1 (PS Vita)</source>
|
||||
<translation type="vanished">Appareil: %1 (PS Vita)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Time remaining: %1 seconds</source>
|
||||
<translation type="vanished">Temps restant: %1 secondes</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ProgressForm</name>
|
||||
<message>
|
||||
<source>Refreshing database...</source>
|
||||
<translation type="vanished">Mise à jour de la base de données...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Reading directory:</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Lecture du répertoire:</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>directory name</source>
|
||||
<translation type="vanished">Nom du répertoire</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Processing file:</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Traitement du fichier:</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>file name</source>
|
||||
<translation type="vanished">Nom du fichier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="vanished">Annuler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database indexing in progress</source>
|
||||
<translation type="vanished">Mise à jour de la base de donnée en cours</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to cancel the database indexing?</source>
|
||||
<translation type="vanished">Êtes-vous sur de vouloir annuler la mise à jour de la base de données?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QTrayIcon</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">Paramètres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">Rafraichir la base de données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestonaire de Sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">À propos de QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">À propos de Qt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">Quitter</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UnityIndicator</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">Paramètres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">Mise à jour de la base de données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">Gestionaire de Sauvegardes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">À propos de QCMA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">À propos de Qt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">Quitter</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
490
common/resources/translations/qcma_ja.ts
Normal file
@@ -0,0 +1,490 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="ja_JP">
|
||||
<context>
|
||||
<name>BackupItem</name>
|
||||
<message>
|
||||
<source>Delete entry</source>
|
||||
<translation type="vanished">項目を削除する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open folder</source>
|
||||
<translation type="vanished">フォルダを開く</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>BackupManagerForm</name>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">バックアップマネージャー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Online ID / Username</source>
|
||||
<translation type="vanished">オンラインID / ユーザー名</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Type</source>
|
||||
<translation type="vanished">バックアップの種類</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PS Vita Games</source>
|
||||
<translation type="vanished">PS Vitaゲーム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSP Games</source>
|
||||
<translation type="vanished">PSPゲーム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSM Games</source>
|
||||
<translation type="vanished">PSMゲーム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSOne Games</source>
|
||||
<translation type="vanished">PS1ゲーム</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PSP Savedatas</source>
|
||||
<translation type="vanished">PSPセーブデータ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backups</source>
|
||||
<translation type="vanished">バックアップ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup disk usage</source>
|
||||
<translation type="vanished">バックアップディスク使用容量</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Filter</source>
|
||||
<translation type="vanished">フィルタ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default account</source>
|
||||
<translation type="vanished">標準アカウント</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to remove the backup of the following entry?</source>
|
||||
<translation type="vanished">次の項目のバックアップを削除してもよろしいですか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup disk usage: %1</source>
|
||||
<translation type="vanished">バックアップディスク使用容量: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [GAME]</source>
|
||||
<translation type="vanished"> [ゲーム]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [SAVE]</source>
|
||||
<translation type="vanished"> [セーブ]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [UPDATE]</source>
|
||||
<translation type="vanished"> [アップデート]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> [DLC]</source>
|
||||
<translation type="vanished"> [DLC]</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ClientManager</name>
|
||||
<message>
|
||||
<source>Added %1 items to the database</source>
|
||||
<translation type="vanished">%1個の項目をデータベースに追加しました</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database indexing aborted by user</source>
|
||||
<translation type="vanished">データベース構築がユーザーにより中止されました</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cannot initialize VitaMTP library</source>
|
||||
<translation type="vanished">VitaMTPライブラリを初期化できません</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must enable at least USB or Wireless monitoring</source>
|
||||
<translation type="vanished">少なくともUSBと無線のどちらかの監視を有効にする必要があります</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No PS Vita system has been registered</source>
|
||||
<translation type="vanished">PS Vitaが登録されていません</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CmaClient</name>
|
||||
<message>
|
||||
<location filename="../../cmaclient.cpp" line="151"/>
|
||||
<location filename="../../cmaclient.cpp" line="154"/>
|
||||
<source>Connected to %1 (PS Vita)</source>
|
||||
<translation>%1 (PS Vita) に接続されました</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfigWidget</name>
|
||||
<message>
|
||||
<source>QCMA Settings</source>
|
||||
<translation type="vanished">QCMA設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Folders</source>
|
||||
<translation type="vanished">フォルダ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Specify the folders that the PS Vita will access for each content type.</source>
|
||||
<translation type="vanished">PS Vitaがアクセスするフォルダーをコンテンツの種類ごとに指定してください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Screenshots and Pictures are Saved to/Imported from.</source>
|
||||
<translation type="vanished">スクリーンショットや画像を保存/インポートする場所です。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Photo Folder</source>
|
||||
<translation type="vanished">フォト</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Browse...</source>
|
||||
<translation type="vanished">参照...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Videos are Saved to/Imported from.</source>
|
||||
<translation type="vanished">ビデオを保存/インポートする場所です。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video Folder</source>
|
||||
<translation type="vanished">ビデオ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Music is Saved to/Imported from.</source>
|
||||
<translation type="vanished">ミュージックを保存/インポートする場所です。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Music Folder</source>
|
||||
<translation type="vanished">ミュージック</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Games, Apps, Savegames, and System Backups are Saved to/Imported from.</source>
|
||||
<translation type="vanished">ゲームやアプリ、セーブデータ、システムバックアップを保存/インポートする場所です。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Applications / Backups</source>
|
||||
<translation type="vanished">アプリケーション/バックアップファイル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your Software Updates and Browser Data is Saved to/Imported from.</source>
|
||||
<translation type="vanished">ソフトウェアアップデートとブラウザデータをを保存/インポートする場所です。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Updates / Web content</source>
|
||||
<translation type="vanished">アップデート/Webコンテンツ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This is the location your PS Vita system will read all the content that it tries to download.</source>
|
||||
<translation type="vanished">この場所の全てのコンテンツをPS Vitaシステムが読み込み、ダウンロードを試みます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Packages</source>
|
||||
<translation type="vanished">パッケージ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Other</source>
|
||||
<translation type="vanished">その他</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600;">Advanced settings</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600;">詳細設定</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offline Mode</source>
|
||||
<translation type="vanished">オフラインモード</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip metadata extraction</source>
|
||||
<translation type="vanished">メタデータの展開をスキップする</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database automatically when files on the PC are changed</source>
|
||||
<translation type="vanished">PCのファイルが変更された際にデータベースを自動的に更新する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SQLite</source>
|
||||
<translation type="vanished">SQLite</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip photo scanning</source>
|
||||
<translation type="vanished">フォトのスキャンをスキップする</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip video scanning</source>
|
||||
<translation type="vanished">ビデオのスキャンをスキップする</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Skip music scanning</source>
|
||||
<translation type="vanished">ミュージックのスキャンをスキップする</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable USB monitoring</source>
|
||||
<translation type="vanished">USBの監視を無効にする</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Wi-Fi monitoring</source>
|
||||
<translation type="vanished">Wi-Fiの監視を無効にする</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database backend</source>
|
||||
<translation type="vanished">データベース保存</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>In Memory</source>
|
||||
<translation type="vanished">メモリ内</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a photo source</source>
|
||||
<translation type="vanished">フォトの参照先として使用されるフォルダを選択してください</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a music source</source>
|
||||
<translation type="vanished">ミュージックの参照先として使用されるフォルダを選択してください</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used as a video source</source>
|
||||
<translation type="vanished">ビデオの参照先として使用されるフォルダを選択してください</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to save PS Vita games and backups</source>
|
||||
<translation type="vanished">PS Vitaのゲームとバックアップの保存に使用されるフォルダを選択してください</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to fetch software updates</source>
|
||||
<translation type="vanished">ソフトウェアアップデートの取得に使用されるフォルダを選択してください</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select the folder to be used to software packages</source>
|
||||
<translation type="vanished">ソフトウェアパッケージに使うフォルダを選択してください</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConfirmDialog</name>
|
||||
<message>
|
||||
<source>Confirmation Message</source>
|
||||
<translation type="vanished">確認メッセージ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p><span style=" font-size:10pt;">Are you sure to delete the backup of the following game?</span></p><p><span style=" font-size:12pt; font-weight:600;">Game Name</span></p></body></html>
|
||||
</source>
|
||||
<translation type="vanished"><html><head/><body><p><span style=" font-size:10pt;">次のゲームのバックアップを削除してもよろしいですか?</span></p><p><span style=" font-size:12pt; font-weight:600;">ゲーム名</span></p></body></html>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FilterLineEdit</name>
|
||||
<message>
|
||||
<source>Filter</source>
|
||||
<translation type="vanished">フィルタ</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>HTTPDownloader</name>
|
||||
<message>
|
||||
<location filename="../../httpdownloader.cpp" line="129"/>
|
||||
<source>Network error: %1</source>
|
||||
<translation>ネットワークエラー: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>KDENotifierTray</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">データベースを更新する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">バックアップマネージャー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">QCMAについて</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">Qtについて</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">終了</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qcma status</source>
|
||||
<translation type="vanished">QCMAステータス</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
<translation type="vanished">切断されました</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWidget</name>
|
||||
<message>
|
||||
<source>Shutting down...</source>
|
||||
<translation type="vanished">終了しています...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stopping QCMA (disconnect your PS Vita)</source>
|
||||
<translation type="vanished">QCMAを停止しています (PS Vitaとの接続を切断してください)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
<translation type="vanished">切断されました</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The device has been disconnected</source>
|
||||
<translation type="vanished">デバイスが切断されました</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyright (C) 2015 Codestation</source>
|
||||
<translation type="obsolete">Copyright (C) 2014 Codestation {2015 ?}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copyright (C) 2015 Codestation
|
||||
|
||||
build hash: %1
|
||||
build branch: %2</source>
|
||||
<translation type="obsolete">Copyright (C) 2014 Codestation
|
||||
|
||||
ビルドハッシュ: %1
|
||||
ビルドブランチ: %2 {2015 ?} {1
|
||||
?}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Information</source>
|
||||
<translation type="vanished">情報</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PinForm</name>
|
||||
<message>
|
||||
<source>Device pairing</source>
|
||||
<translation type="vanished">端末のペアリング</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An unregistered PS Vita system is connecting with QCMA via Wi-Fi</source>
|
||||
<translation type="vanished">登録されていないPS VitaがWi-Fi経由でQCMAで接続しています</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device: PS Vita</source>
|
||||
<translation type="vanished">端末: PS Vita</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Input the following number in the PS Vita system to register it with QCMA</source>
|
||||
<translation type="vanished">QCMAでPS Vitaを登録するために次の番号をPS Vitaで入力してください</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Time remaining: 300 seconds</source>
|
||||
<translation type="vanished">残り時間: 300秒</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="vanished">キャンセル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device: %1 (PS Vita)</source>
|
||||
<translation type="vanished">端末: %1 (PS Vita)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Time remaining: %1 seconds</source>
|
||||
<translation type="vanished">残り時間: %1秒</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ProgressForm</name>
|
||||
<message>
|
||||
<source>Refreshing database...</source>
|
||||
<translation type="vanished">データベースを更新しています...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Reading directory:</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Leyendo directorio:</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>directory name</source>
|
||||
<translation type="vanished">ディレクトリ名</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Processing file:</span></p></body></html></source>
|
||||
<translation type="vanished"><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Procesando archivo:</span></p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>file name</source>
|
||||
<translation type="vanished">ファイル名</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="vanished">キャンセル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Database indexing in progress</source>
|
||||
<translation type="vanished">データベース構築が進行中です</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to cancel the database indexing?</source>
|
||||
<translation type="vanished">データベース構築をキャンセルしてもよろしいですか?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QTrayIcon</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">データベースを更新する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">バックアップマネージャー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">QCMAについて</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">Qtについて</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">終了</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>UnityIndicator</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation type="vanished">設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh database</source>
|
||||
<translation type="vanished">データベースを更新する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Backup Manager</source>
|
||||
<translation type="vanished">バックアップマネージャー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About QCMA</source>
|
||||
<translation type="vanished">QCMAについて</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About Qt</source>
|
||||
<translation type="vanished">Qtについて</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit</source>
|
||||
<translation type="vanished">終了</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
84
common/resources/xml/psp2-updatelist.xml
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<update_data_list>
|
||||
<region id="au">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="eu">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="jp">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="kr">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="mx">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="ru">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="tw">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="uk">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
<region id="us">
|
||||
<np level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<np_d level0_system_version="00.000.000" level1_system_version="00.000.000" level2_system_version="00.000.000" map="00.000.000" />
|
||||
<version system_version="00.000.000" label="0.00">
|
||||
<update_data update_type="full">
|
||||
<image size="0">http://www.example.com/PSP2UPDAT.PUP</image>
|
||||
</update_data>
|
||||
</version>
|
||||
</region>
|
||||
</update_data_list>
|
51
common/sforeader.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sforeader.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
SfoReader::SfoReader()
|
||||
{
|
||||
}
|
||||
|
||||
bool SfoReader::load(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
if(file.open(QIODevice::ReadOnly)) {
|
||||
data = file.readAll();
|
||||
key_offset = data.constData();
|
||||
header = (sfo_header *)key_offset;
|
||||
index = (sfo_index *)(key_offset + sizeof(sfo_header));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *SfoReader::value(const char *key, const char *defaultValue)
|
||||
{
|
||||
const char *base_key = key_offset + header->key_offset;
|
||||
for(uint i = 0; i < header->pair_count; i++) {
|
||||
const char *curr_key = base_key + index[i].key_offset;
|
||||
if(strcmp(key, curr_key) == 0) {
|
||||
return key_offset + header->value_offset + index[i].data_offset;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
56
common/sforeader.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SFOREADER_H
|
||||
#define SFOREADER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
class SfoReader
|
||||
{
|
||||
public:
|
||||
SfoReader();
|
||||
bool load(const QString &path);
|
||||
const char *value(const char *key, const char *defaultValue);
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
quint16 key_offset;
|
||||
uchar alignment;
|
||||
uchar data_type;
|
||||
quint32 value_size;
|
||||
quint32 value_size_with_padding;
|
||||
quint32 data_offset;
|
||||
} __attribute__((packed)) sfo_index;
|
||||
|
||||
typedef struct {
|
||||
char id[4];
|
||||
quint32 version;
|
||||
quint32 key_offset;
|
||||
quint32 value_offset;
|
||||
quint32 pair_count;
|
||||
} __attribute__((packed)) sfo_header;
|
||||
|
||||
QByteArray data;
|
||||
const char *key_offset;
|
||||
const sfo_header *header;
|
||||
const sfo_index *index;
|
||||
};
|
||||
|
||||
#endif // SFOREADER_H
|
1318
common/sqlitedb.cpp
Normal file
102
common/sqlitedb.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SQLITEDB_H
|
||||
#define SQLITEDB_H
|
||||
|
||||
#include "database.h"
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QObject>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QTimer>
|
||||
|
||||
class SQLiteDB : public Database
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SQLiteDB(QObject *parent = 0);
|
||||
~SQLiteDB();
|
||||
|
||||
bool load();
|
||||
bool rescan();
|
||||
void close();
|
||||
|
||||
bool reload(bool &prepared);
|
||||
void setUUID(const QString &m_uuid);
|
||||
|
||||
bool open();
|
||||
int create();
|
||||
void clear();
|
||||
bool initialize();
|
||||
QSqlError getLastError();
|
||||
|
||||
int childObjectCount(int parent_ohfi);
|
||||
bool deleteEntry(int ohfi, int root_ohfi = 0);
|
||||
QString getAbsolutePath(int ohfi);
|
||||
bool getObjectList(int ohfi, metadata_t **metadata);
|
||||
bool getObjectMetadata(int ohfi, metadata_t &metadata);
|
||||
int getObjectMetadatas(int parent_ohfi, metadata_t **metadata, int index = 0, int max_number = 0);
|
||||
qint64 getObjectSize(int ohfi);
|
||||
int getParentId(int ohfi);
|
||||
int getPathId(const char *name, int ohfi);
|
||||
QString getRelativePath(int ohfi);
|
||||
int getRootId(int ohfi);
|
||||
int insertObjectEntry(const QString &path, const QString &name, int parent_ohfi);
|
||||
bool renameObject(int ohfi, const QString &name);
|
||||
void setObjectSize(int ohfi, qint64 size);
|
||||
void freeMetadata(metadata_t *metadata);
|
||||
|
||||
int getPathId(const QString &path);
|
||||
QString getPathFromId(int ohfi);
|
||||
bool updateSize(int ohfi, quint64 size);
|
||||
bool deleteEntry(int ohfi);
|
||||
bool insertSourceEntry(uint object_id, const QString &path, const QString &name);
|
||||
uint insertMusicEntry(const QString &path, const QString &name, int parent, int type);
|
||||
uint insertVideoEntry(const QString &path, const QString &name, int parent, int type);
|
||||
uint insertPhotoEntry(const QString &path, const QString &name, int parent, int type);
|
||||
uint insertSavedataEntry(const QString &path, const QString &name, int parent, int type);
|
||||
bool insertApplicationEntry(const QString &name, int ohfi, int app_type);
|
||||
|
||||
private:
|
||||
int recursiveScanRootDirectory(const QString &base_path, const QString &rel_path, int parent_ohfi, int root_ohfi);
|
||||
int insertObjectEntryInternal(const QString &path, const QString &name, int parent_ohfi, int type);
|
||||
int insertDefaultEntry(const QString &path, const QString &name, const QString &title, int parent, int type);
|
||||
int insertNodeEntry(const QString &title, int type, int data_type);
|
||||
bool updateAdjacencyList(int ohfi, int parent);
|
||||
QString getBasePath(int root_ohfi);
|
||||
int getObjectType(int ohfi);
|
||||
void fillMetadata(const QSqlQuery &query, metadata_t &metadata);
|
||||
qint64 getChildenTotalSize(int ohfi);
|
||||
bool updateObjectPath(int ohfi, const QString &name);
|
||||
int getRootItems(int root_ohfi, metadata_t **metadata);
|
||||
bool insertVirtualEntries();
|
||||
bool insertVirtualEntry(int ohfi);
|
||||
|
||||
QTimer *timer;
|
||||
QThread *thread;
|
||||
|
||||
QString m_uuid;
|
||||
QSqlDatabase db;
|
||||
};
|
||||
|
||||
#endif // SQLITEDB_H
|
7
common/translations.qrc
Normal file
@@ -0,0 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>resources/translations/qcma_es.qm</file>
|
||||
<file>resources/translations/qcma_fr.qm</file>
|
||||
<file>resources/translations/qcma_ja.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
63
config.pri
Normal file
@@ -0,0 +1,63 @@
|
||||
CXXFLAGS_WARNINGS = -Wall -Wextra -Wdisabled-optimization -Wformat=2 -Winit-self \
|
||||
-Wmissing-include-dirs -Woverloaded-virtual -Wundef -Wno-unused \
|
||||
-Wno-missing-field-initializers -Wno-format-nonliteral
|
||||
|
||||
# custom CXXFLAGS
|
||||
QMAKE_CXXFLAGS += -Wno-write-strings -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS $$CXXFLAGS_WARNINGS
|
||||
|
||||
QT_CONFIG -= no-pkg-config
|
||||
CONFIG += link_pkgconfig
|
||||
CONFIG -= debug_and_release
|
||||
|
||||
VERSION = 0.3.10
|
||||
|
||||
#Linux-only config
|
||||
unix:!macx {
|
||||
# largefile support
|
||||
DEFINES += _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE
|
||||
|
||||
# installation prefix
|
||||
isEmpty(PREFIX) {
|
||||
PREFIX = /usr/local
|
||||
}
|
||||
|
||||
BINDIR = $$PREFIX/bin
|
||||
DATADIR = $$PREFIX/share
|
||||
MANDIR = $$DATADIR/man/man1
|
||||
}
|
||||
|
||||
# Windows config
|
||||
win32 {
|
||||
# avoid alignment issues with newer mingw compiler
|
||||
QMAKE_CXXFLAGS += -mno-ms-bitfields
|
||||
}
|
||||
|
||||
# OS X config
|
||||
macx {
|
||||
# OS X icon
|
||||
ICON = resources/images/qcma.icns
|
||||
# re-enable pkg-config on OS X (brew installs pkg-config files)
|
||||
QT_CONFIG -= no-pkg-config
|
||||
}
|
||||
|
||||
# try to get the current git version + hash
|
||||
QCMA_GIT_VERSION=$$system(git describe --tags)
|
||||
|
||||
#use the generic version if the above command fails (no git executable or metadata)
|
||||
isEmpty(QCMA_GIT_VERSION) {
|
||||
DEFINES += QCMA_VER=\\\"$$VERSION\\\"
|
||||
} else {
|
||||
DEFINES += QCMA_VER=\\\"$$QCMA_GIT_VERSION\\\"
|
||||
}
|
||||
|
||||
GET_HASHES {
|
||||
# try to get the current git commit and branch
|
||||
QCMA_GIT_HASH=$$system(git rev-parse --short HEAD)
|
||||
QCMA_GIT_BRANCH=$$system(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# pass the current git commit hash
|
||||
!isEmpty(QCMA_GIT_HASH):!isEmpty(QCMA_GIT_BRANCH) {
|
||||
DEFINES += QCMA_BUILD_HASH=\\\"$$QCMA_GIT_HASH\\\"
|
||||
DEFINES += QCMA_BUILD_BRANCH=\\\"$$QCMA_GIT_BRANCH\\\"
|
||||
}
|
||||
}
|
214
gui/clientmanager.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "clientmanager.h"
|
||||
#include "cmaclient.h"
|
||||
#include "cmautils.h"
|
||||
#include "forms/progressform.h"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int ClientManager::sighup_fd[2];
|
||||
int ClientManager::sigterm_fd[2];
|
||||
#endif
|
||||
|
||||
ClientManager::ClientManager(Database *db, QObject *obj_parent) :
|
||||
QObject(obj_parent), m_db(db)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighup_fd))
|
||||
qFatal("Couldn't create HUP socketpair");
|
||||
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigterm_fd))
|
||||
qFatal("Couldn't create TERM socketpair");
|
||||
|
||||
sn_hup = new QSocketNotifier(sighup_fd[1], QSocketNotifier::Read, this);
|
||||
connect(sn_hup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
|
||||
sn_term = new QSocketNotifier(sigterm_fd[1], QSocketNotifier::Read, this);
|
||||
connect(sn_term, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
|
||||
#endif
|
||||
}
|
||||
|
||||
ClientManager::~ClientManager()
|
||||
{
|
||||
VitaMTP_Cleanup();
|
||||
}
|
||||
|
||||
void ClientManager::databaseUpdated(int count)
|
||||
{
|
||||
progress.interruptShow();
|
||||
progress.hide();
|
||||
if(count >= 0) {
|
||||
emit messageSent(tr("Added %1 items to the database").arg(count));
|
||||
} else {
|
||||
emit messageSent(tr("Database indexing aborted by user"));
|
||||
}
|
||||
emit updated(count);
|
||||
}
|
||||
|
||||
void ClientManager::showPinDialog(QString name, int pin)
|
||||
{
|
||||
pinForm.setPin(name, pin);
|
||||
pinForm.startCountdown();
|
||||
}
|
||||
|
||||
void ClientManager::start()
|
||||
{
|
||||
if(VitaMTP_Init() < 0) {
|
||||
emit messageSent(tr("Cannot initialize VitaMTP library"));
|
||||
return;
|
||||
}
|
||||
|
||||
// initializing database for the first use
|
||||
refreshDatabase();
|
||||
|
||||
connect(m_db, SIGNAL(fileAdded(QString)), &progress, SLOT(setFileName(QString)));
|
||||
connect(m_db, SIGNAL(directoryAdded(QString)), &progress, SLOT(setDirectoryName(QString)));
|
||||
connect(m_db, SIGNAL(updated(int)), this, SLOT(databaseUpdated(int)));
|
||||
connect(&progress, SIGNAL(canceled()), m_db, SLOT(cancelOperation()), Qt::DirectConnection);
|
||||
|
||||
thread_count = 0;
|
||||
qDebug("Starting cma threads");
|
||||
CmaClient *client;
|
||||
QSettings settings;
|
||||
|
||||
if(!settings.value("disableUSB", false).toBool()) {
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
if(!belongsToGroup("vitamtp"))
|
||||
emit messageSent(tr("This user doesn't belong to the vitamtp group, there could be a problem while reading the USB bus."));
|
||||
#endif
|
||||
|
||||
usb_thread = new QThread();
|
||||
client = new CmaClient(m_db);
|
||||
usb_thread->setObjectName("usb_thread");
|
||||
connect(usb_thread, SIGNAL(started()), client, SLOT(connectUsb()));
|
||||
connect(client, SIGNAL(messageSent(QString)), this, SIGNAL(messageSent(QString)));
|
||||
connect(client, SIGNAL(finished()), usb_thread, SLOT(quit()), Qt::DirectConnection);
|
||||
connect(usb_thread, SIGNAL(finished()), usb_thread, SLOT(deleteLater()));
|
||||
connect(usb_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
|
||||
connect(usb_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
|
||||
|
||||
connect(client, SIGNAL(deviceConnected(QString)), this, SIGNAL(deviceConnected(QString)));
|
||||
connect(client, SIGNAL(deviceDisconnected()), this, SIGNAL(deviceDisconnected()));
|
||||
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||
|
||||
client->moveToThread(usb_thread);
|
||||
usb_thread->start();
|
||||
thread_count++;
|
||||
}
|
||||
|
||||
if(!settings.value("disableWireless", false).toBool()) {
|
||||
CmaBroadcast *broadcast = new CmaBroadcast(this);
|
||||
wireless_thread = new QThread();
|
||||
client = new CmaClient(m_db, broadcast);
|
||||
wireless_thread->setObjectName("wireless_thread");
|
||||
connect(wireless_thread, SIGNAL(started()), client, SLOT(connectWireless()));
|
||||
connect(client, SIGNAL(messageSent(QString)), this, SIGNAL(messageSent(QString)));
|
||||
connect(client, SIGNAL(receivedPin(QString,int)), this, SLOT(showPinDialog(QString,int)));
|
||||
connect(client, SIGNAL(finished()), wireless_thread, SLOT(quit()), Qt::DirectConnection);
|
||||
connect(wireless_thread, SIGNAL(finished()), wireless_thread, SLOT(deleteLater()));
|
||||
connect(wireless_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
|
||||
connect(wireless_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
|
||||
|
||||
connect(client, SIGNAL(pinComplete()), &pinForm, SLOT(hide()));
|
||||
connect(client, SIGNAL(deviceConnected(QString)), this, SIGNAL(deviceConnected(QString)));
|
||||
connect(client, SIGNAL(deviceDisconnected()), this, SIGNAL(deviceDisconnected()));
|
||||
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||
|
||||
client->moveToThread(wireless_thread);
|
||||
wireless_thread->start();
|
||||
thread_count++;
|
||||
}
|
||||
|
||||
if(thread_count == 0) {
|
||||
emit messageSent(tr("You must enable at least USB or Wireless monitoring"));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientManager::refreshDatabase()
|
||||
{
|
||||
if(m_db->load()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!m_db->rescan()) {
|
||||
emit messageSent(tr("No PS Vita system has been registered"));
|
||||
} else {
|
||||
progress.showDelayed(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientManager::stop()
|
||||
{
|
||||
if(CmaClient::stop() < 0) {
|
||||
emit stopped();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientManager::threadStopped()
|
||||
{
|
||||
mutex.lock();
|
||||
if(--thread_count == 0) {
|
||||
emit stopped();
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
void ClientManager::hupSignalHandler(int)
|
||||
{
|
||||
char a = 1;
|
||||
::write(sighup_fd[0], &a, sizeof(a));
|
||||
}
|
||||
|
||||
void ClientManager::termSignalHandler(int)
|
||||
{
|
||||
char a = 1;
|
||||
::write(sigterm_fd[0], &a, sizeof(a));
|
||||
}
|
||||
|
||||
void ClientManager::handleSigTerm()
|
||||
{
|
||||
sn_term->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sigterm_fd[1], &tmp, sizeof(tmp));
|
||||
|
||||
stop();
|
||||
|
||||
sn_term->setEnabled(true);
|
||||
}
|
||||
|
||||
void ClientManager::handleSigHup()
|
||||
{
|
||||
sn_hup->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sighup_fd[1], &tmp, sizeof(tmp));
|
||||
|
||||
refreshDatabase();
|
||||
|
||||
sn_hup->setEnabled(true);
|
||||
}
|
||||
#endif
|
94
gui/clientmanager.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CLIENTMANAGER_H
|
||||
#define CLIENTMANAGER_H
|
||||
|
||||
#include "database.h"
|
||||
#include "forms/pinform.h"
|
||||
#include "forms/progressform.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <QSocketNotifier>
|
||||
#endif
|
||||
|
||||
class ClientManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClientManager(Database *db, QObject *parent = 0);
|
||||
~ClientManager();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// unix signal handlers
|
||||
static void hupSignalHandler(int);
|
||||
static void termSignalHandler(int);
|
||||
#endif
|
||||
|
||||
private:
|
||||
int thread_count;
|
||||
QMutex mutex;
|
||||
|
||||
Database *m_db;
|
||||
|
||||
PinForm pinForm;
|
||||
ProgressForm progress;
|
||||
|
||||
QThread *usb_thread;
|
||||
QThread *wireless_thread;
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// signal handling
|
||||
static int sighup_fd[2];
|
||||
static int sigterm_fd[2];
|
||||
|
||||
QSocketNotifier *sn_hup;
|
||||
QSocketNotifier *sn_term;
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void updated(int);
|
||||
void stopped();
|
||||
void receivedPin(int);
|
||||
void deviceDisconnected();
|
||||
void messageSent(QString);
|
||||
void deviceConnected(QString);
|
||||
|
||||
public slots:
|
||||
void refreshDatabase();
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// Qt signal handlers
|
||||
void handleSigHup();
|
||||
void handleSigTerm();
|
||||
#endif
|
||||
|
||||
private slots:
|
||||
void threadStopped();
|
||||
void databaseUpdated(int count);
|
||||
void showPinDialog(QString name, int pin);
|
||||
};
|
||||
|
||||
#endif // CLIENTMANAGER_H
|
2
gui/defines.pri
Normal file
@@ -0,0 +1,2 @@
|
||||
INCLUDEPATH += $$IN_PWD
|
||||
DEPENDPATH += $$IN_PWD
|
89
gui/filterlineedit.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Xian Nox
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "filterlineedit.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QStyle>
|
||||
|
||||
FilterLineEdit::FilterLineEdit(QWidget *obj_parent) :
|
||||
QLineEdit(obj_parent)
|
||||
{
|
||||
int frame_width = frameWidth();
|
||||
clearButton = new QToolButton(this);
|
||||
QIcon clearIcon(":/main/resources/images/edit-clear-locationbar-rtl.png");
|
||||
clearButton->setIcon(clearIcon);
|
||||
clearButton->setIconSize(QSize(sizeHint().height() - 4 * frame_width,
|
||||
sizeHint().height() - 4 * frame_width));
|
||||
clearButton->setCursor(Qt::ArrowCursor);
|
||||
clearButton->setStyleSheet("QToolButton { border:none; padding:0px; }");
|
||||
clearButton->hide();
|
||||
connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
||||
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateCloseButton(const QString&)));
|
||||
|
||||
setStyleSheet(QString("LineEdit { color:black; font-style:normal; padding-right:%1px; }").arg(
|
||||
clearButton->sizeHint().width() + frame_width + 1));
|
||||
|
||||
QSize min_size_hint = minimumSizeHint();
|
||||
setMinimumSize(qMax(min_size_hint.width(), clearButton->sizeHint().height() + frame_width),
|
||||
qMax(min_size_hint.height(), clearButton->sizeHint().height() + frame_width));
|
||||
}
|
||||
|
||||
void FilterLineEdit::updateCloseButton(const QString& filter_text)
|
||||
{
|
||||
if(filter_text.isEmpty() || filter_text == tr("Filter")) {
|
||||
clearButton->setVisible(false);
|
||||
} else {
|
||||
clearButton->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void FilterLineEdit::focusInEvent(QFocusEvent *e)
|
||||
{
|
||||
if(this->styleSheet() == "FilterLineEdit { color:gray; font-style:italic; }") {
|
||||
this->clear();
|
||||
}
|
||||
|
||||
setStyleSheet(QString("FilterLineEdit { color:black; font-style:normal; padding-right:%1px; }").arg(clearButton->sizeHint().width() + frameWidth() + 1));
|
||||
|
||||
QLineEdit::focusInEvent(e);
|
||||
}
|
||||
|
||||
void FilterLineEdit::focusOutEvent(QFocusEvent *e)
|
||||
{
|
||||
if(this->text().isEmpty()) {
|
||||
this->setText(tr("Filter"));
|
||||
this->setStyleSheet("FilterLineEdit { color:gray; font-style:italic; }");
|
||||
}
|
||||
|
||||
QLineEdit::focusOutEvent(e);
|
||||
}
|
||||
|
||||
int FilterLineEdit::frameWidth() const
|
||||
{
|
||||
return style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this);
|
||||
}
|
||||
|
||||
void FilterLineEdit::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QSize sz = clearButton->sizeHint();
|
||||
clearButton->move(rect().right() - sz.width(), rect().bottom() - sz.height() + frameWidth());
|
||||
|
||||
QLineEdit::resizeEvent(e);
|
||||
}
|
47
gui/filterlineedit.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Xian Nox
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FILTERLINEEDIT_H
|
||||
#define FILTERLINEEDIT_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QToolButton>
|
||||
|
||||
class FilterLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FilterLineEdit(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void focusInEvent(QFocusEvent *e);
|
||||
void focusOutEvent(QFocusEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
int frameWidth() const;
|
||||
|
||||
private:
|
||||
QToolButton *clearButton;
|
||||
|
||||
private slots:
|
||||
void updateCloseButton(const QString &text);
|
||||
|
||||
};
|
||||
|
||||
#endif // FILTERLINEEDIT_H
|
104
gui/forms/backupitem.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "backupitem.h"
|
||||
#include "ui_backupitem.h"
|
||||
#include "cmautils.h"
|
||||
#include "dds.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
|
||||
const QString BackupItem::gameTemplate = "<html><head/><body>"
|
||||
"<p><span style=\" font-size:13pt; font-weight:600;\">%1</span></p>"
|
||||
"</body></html>";
|
||||
|
||||
const QString BackupItem::sizeTemplate = "<html><head/><body>"
|
||||
"<p><span style=\" font-size:10pt;\">%1</span></p>"
|
||||
"</body></html>";
|
||||
|
||||
const QString BackupItem::infoTemplate = "<html><head/><body>"
|
||||
"<p><span style=\" font-size:10pt;\"> %1</span></p>"
|
||||
"</body></html>";
|
||||
|
||||
BackupItem::BackupItem(QWidget *obj_parent) :
|
||||
QWidget(obj_parent),
|
||||
ui(new Ui::BackupItem)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
// connect the buttons
|
||||
connect(ui->openButton, SIGNAL(clicked()), this, SLOT(openDirectory()));
|
||||
connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(removeEntry()));
|
||||
}
|
||||
|
||||
BackupItem::~BackupItem()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BackupItem::openDirectory()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("file:///" + m_path));
|
||||
}
|
||||
|
||||
void BackupItem::removeEntry()
|
||||
{
|
||||
emit deleteEntry(this);
|
||||
}
|
||||
|
||||
const QPixmap *BackupItem::getIconPixmap()
|
||||
{
|
||||
return ui->itemPicture->pixmap();
|
||||
}
|
||||
|
||||
void BackupItem::setDirectory(const QString &path)
|
||||
{
|
||||
m_path = path;
|
||||
}
|
||||
|
||||
void BackupItem::setItemInfo(const QString &name, const QString &item_size, const QString &extra)
|
||||
{
|
||||
ui->gameLabel->setText(gameTemplate.arg(name));
|
||||
ui->sizeLabel->setText(sizeTemplate.arg(item_size));
|
||||
ui->infoLabel->setText(infoTemplate.arg(extra));
|
||||
}
|
||||
|
||||
int BackupItem::getIconWidth()
|
||||
{
|
||||
return ui->itemPicture->width();
|
||||
}
|
||||
|
||||
void BackupItem::setItemIcon(const QString &path, int item_width, bool try_dds)
|
||||
{
|
||||
ui->itemPicture->setMinimumWidth(item_width);
|
||||
QPixmap pixmap(path);
|
||||
if((pixmap.width() <= 0 || pixmap.height() <= 0) && try_dds) {
|
||||
QImage image;
|
||||
if(loadDDS(path, &image)) {
|
||||
pixmap = QPixmap::fromImage(image);
|
||||
}
|
||||
}
|
||||
ui->itemPicture->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
bool BackupItem::lessThan(const BackupItem *s1, const BackupItem *s2)
|
||||
{
|
||||
return s1->title.compare(s2->title) < 0;
|
||||
}
|
||||
|
63
gui/forms/backupitem.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BACKUPITEM_H
|
||||
#define BACKUPITEM_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class BackupItem;
|
||||
}
|
||||
|
||||
class BackupItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BackupItem(QWidget *parent = 0);
|
||||
~BackupItem();
|
||||
|
||||
void setItemInfo(const QString &name, const QString &size, const QString &extra);
|
||||
void setItemIcon(const QString &m_path, int width = 48, bool try_dds = false);
|
||||
void setDirectory(const QString &m_path);
|
||||
const QPixmap *getIconPixmap();
|
||||
int getIconWidth();
|
||||
|
||||
static bool lessThan(const BackupItem *s1, const BackupItem *s2);
|
||||
|
||||
int ohfi;
|
||||
QString title;
|
||||
|
||||
private:
|
||||
QString m_path;
|
||||
Ui::BackupItem *ui;
|
||||
static const QString gameTemplate;
|
||||
static const QString sizeTemplate;
|
||||
static const QString infoTemplate;
|
||||
|
||||
signals:
|
||||
void deleteEntry(BackupItem *entry);
|
||||
|
||||
private slots:
|
||||
void openDirectory();
|
||||
void removeEntry();
|
||||
};
|
||||
|
||||
#endif // BACKUPITEM_H
|
154
gui/forms/backupitem.ui
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BackupItem</class>
|
||||
<widget class="QWidget" name="BackupItem">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>638</width>
|
||||
<height>75</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="itemPicture">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="gameLabel">
|
||||
<property name="text">
|
||||
<string notr="true"><p><span style=" font-size:12pt; font-weight:600;">Game Name</span></p></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="sizeLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"><p><span style=" font-size:10pt;">0.00 GiB</span></p></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="infoLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"><html><head/><body><p><span style=" font-size:9pt;">[APP] [SAVE] [UPDATE] [DLC]</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete entry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="openButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
257
gui/forms/backupmanagerform.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "backupmanagerform.h"
|
||||
#include "ui_backupmanagerform.h"
|
||||
#include "cmaobject.h"
|
||||
#include "sforeader.h"
|
||||
#include "confirmdialog.h"
|
||||
#include "cmautils.h"
|
||||
#include "filterlineedit.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
BackupManagerForm::BackupManagerForm(Database *db, QWidget *obj_parent) :
|
||||
QDialog(obj_parent), m_db(db),
|
||||
ui(new Ui::BackupManagerForm)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setupForm();
|
||||
}
|
||||
|
||||
BackupManagerForm::~BackupManagerForm()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BackupManagerForm::setupForm()
|
||||
{
|
||||
this->resize(800, 480);
|
||||
connect(ui->backupComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(loadBackupListing(int)));
|
||||
ui->tableWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
ui->tableWidget->horizontalHeader()->hide();
|
||||
}
|
||||
|
||||
void BackupManagerForm::removeEntry(BackupItem *item)
|
||||
{
|
||||
ConfirmDialog msgBox;
|
||||
|
||||
msgBox.setMessageText(tr("Are you sure to remove the backup of the following entry?"), item->title);
|
||||
msgBox.setMessagePixmap(*item->getIconPixmap(), item->getIconWidth());
|
||||
|
||||
if(msgBox.exec() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&m_db->mutex);
|
||||
|
||||
int parent_ohfi = m_db->getParentId(item->ohfi);
|
||||
removeRecursively(m_db->getAbsolutePath(item->ohfi));
|
||||
m_db->deleteEntry(item->ohfi);
|
||||
|
||||
for(int i = 0; i < ui->tableWidget->rowCount(); ++i) {
|
||||
BackupItem *iter_item = static_cast<BackupItem *>(ui->tableWidget->cellWidget(i, 0));
|
||||
if(iter_item == item) {
|
||||
ui->tableWidget->removeRow(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(parent_ohfi > 0) {
|
||||
setBackupUsage(m_db->getObjectSize(parent_ohfi));
|
||||
}
|
||||
}
|
||||
|
||||
void BackupManagerForm::setBackupUsage(qint64 usage_size)
|
||||
{
|
||||
ui->usageLabel->setText(tr("Backup disk usage: %1").arg(readable_size(usage_size, true)));
|
||||
}
|
||||
|
||||
void BackupManagerForm::loadBackupListing(int index)
|
||||
{
|
||||
int ohfi;
|
||||
bool sys_dir;
|
||||
int img_width;
|
||||
|
||||
//TODO: load all the accounts in the combobox
|
||||
ui->accountBox->clear();
|
||||
ui->accountBox->addItem(QSettings().value("lastOnlineId", tr("Default account")).toString());
|
||||
|
||||
if(index < 0) {
|
||||
index = ui->backupComboBox->currentIndex();
|
||||
}
|
||||
|
||||
ui->tableWidget->clear();
|
||||
|
||||
switch(index) {
|
||||
case 0:
|
||||
ohfi = VITA_OHFI_VITAAPP;
|
||||
img_width = 48;
|
||||
sys_dir = true;
|
||||
break;
|
||||
case 1:
|
||||
ohfi = VITA_OHFI_PSPAPP;
|
||||
img_width = 80;
|
||||
sys_dir = true;
|
||||
break;
|
||||
case 2:
|
||||
ohfi = VITA_OHFI_PSMAPP;
|
||||
img_width = 48;
|
||||
sys_dir = true;
|
||||
break;
|
||||
case 3:
|
||||
ohfi = VITA_OHFI_PSXAPP;
|
||||
img_width = 48;
|
||||
sys_dir = true;
|
||||
break;
|
||||
case 4:
|
||||
ohfi = VITA_OHFI_PSPSAVE;
|
||||
img_width = 80;
|
||||
sys_dir = false;
|
||||
break;
|
||||
case 5:
|
||||
ohfi = VITA_OHFI_BACKUP;
|
||||
img_width = 48;
|
||||
sys_dir = false;
|
||||
break;
|
||||
default:
|
||||
ohfi = VITA_OHFI_VITAAPP;
|
||||
img_width = 48;
|
||||
sys_dir = true;
|
||||
}
|
||||
|
||||
m_db->mutex.lock();
|
||||
|
||||
// get the item list
|
||||
metadata_t *meta = NULL;
|
||||
int row_count = m_db->getObjectMetadatas(ohfi, &meta);
|
||||
ui->tableWidget->setRowCount(row_count);
|
||||
|
||||
// exit if there aren't any items
|
||||
if(row_count == 0) {
|
||||
setBackupUsage(0);
|
||||
m_db->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
// adjust the table item width to fill all the widget
|
||||
QHeaderView *vert_header = ui->tableWidget->verticalHeader();
|
||||
QHeaderView *horiz_header = ui->tableWidget->horizontalHeader();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
horiz_header->setSectionResizeMode(QHeaderView::Stretch);
|
||||
#else
|
||||
horiz_header->setResizeMode(QHeaderView::Stretch);
|
||||
#endif
|
||||
qint64 backup_size = m_db->getObjectSize(ohfi);
|
||||
setBackupUsage(backup_size);
|
||||
QString path = m_db->getAbsolutePath(ohfi);
|
||||
QList<BackupItem *> item_list;
|
||||
|
||||
metadata_t *first = meta;
|
||||
while(meta) {
|
||||
QString base_path = path + QDir::separator() + meta->name;
|
||||
QString parent_path = sys_dir ? base_path + QDir::separator() + "sce_sys" : base_path;
|
||||
SfoReader reader;
|
||||
QString game_name;
|
||||
|
||||
// retrieve the game name from the SFO
|
||||
if(reader.load(QDir(parent_path).absoluteFilePath(sys_dir ? "param.sfo" : "PARAM.SFO"))) {
|
||||
game_name = QString::fromUtf8(reader.value("TITLE", meta->name));
|
||||
} else {
|
||||
game_name = QString(meta->name);
|
||||
}
|
||||
|
||||
BackupItem *item = new BackupItem();
|
||||
// save the game title and ohfi for sorting/deleting
|
||||
item->ohfi = meta->ohfi;
|
||||
item->title = game_name;
|
||||
|
||||
connect(item, SIGNAL(deleteEntry(BackupItem*)), this, SLOT(removeEntry(BackupItem*)));
|
||||
|
||||
// show better size info for multi GiB backups
|
||||
bool use_gb = ohfi == VITA_OHFI_BACKUP && meta->size > 1024*1024*1024;
|
||||
QString read_size = readable_size(meta->size, use_gb);
|
||||
|
||||
QString info;
|
||||
|
||||
// check if is listing PS Vita games
|
||||
if(index == 0) {
|
||||
if(QDir(base_path + QDir::separator() + "app").exists()) {
|
||||
info.append(tr(" [GAME]"));
|
||||
}
|
||||
if(QDir(base_path + QDir::separator() + "savedata").exists()) {
|
||||
info.append(tr(" [SAVE]"));
|
||||
}
|
||||
if(QDir(base_path + QDir::separator() + "patch").exists()) {
|
||||
info.append(tr(" [UPDATE]"));
|
||||
}
|
||||
if(QDir(base_path + QDir::separator() + "addcont").exists()) {
|
||||
info.append(tr(" [DLC]"));
|
||||
}
|
||||
}
|
||||
|
||||
item->setItemInfo(game_name, read_size, info);
|
||||
item->setItemIcon(QDir(parent_path).absoluteFilePath(sys_dir ? "icon0.png" : "ICON0.PNG"), img_width, ohfi == VITA_OHFI_PSMAPP);
|
||||
item->setDirectory(path + QDir::separator() + meta->name);
|
||||
item->resize(646, 68);
|
||||
|
||||
item_list << item;
|
||||
meta = meta->next_metadata;
|
||||
}
|
||||
|
||||
m_db->freeMetadata(first);
|
||||
|
||||
qSort(item_list.begin(), item_list.end(), BackupItem::lessThan);
|
||||
|
||||
int row;
|
||||
QList<BackupItem *>::iterator it;
|
||||
vert_header->setUpdatesEnabled(false);
|
||||
|
||||
// insert the sorted items into the table
|
||||
for(it = item_list.begin(), row = 0; it != item_list.end(); ++it, ++row) {
|
||||
ui->tableWidget->setCellWidget(row, 0, *it);
|
||||
vert_header->resizeSection(row, 68);
|
||||
}
|
||||
|
||||
vert_header->setUpdatesEnabled(true);
|
||||
m_db->mutex.unlock();
|
||||
|
||||
// apply filter
|
||||
this->on_filterLineEdit_textChanged(ui->filterLineEdit->text());
|
||||
}
|
||||
|
||||
void BackupManagerForm::on_filterLineEdit_textChanged(const QString &arg1)
|
||||
{
|
||||
if(arg1 != tr("Filter")) {
|
||||
for(int i = 0; i < ui->tableWidget->rowCount(); ++i) {
|
||||
BackupItem *item = (BackupItem*) ui->tableWidget->cellWidget(i, 0);
|
||||
|
||||
if(item->title.contains(arg1, Qt::CaseInsensitive)) {
|
||||
ui->tableWidget->setRowHidden(i, false);
|
||||
} else {
|
||||
ui->tableWidget->setRowHidden(i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
gui/forms/backupmanagerform.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BACKUPMANAGERFORM_H
|
||||
#define BACKUPMANAGERFORM_H
|
||||
|
||||
#include "database.h"
|
||||
#include "backupitem.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class BackupManagerForm;
|
||||
}
|
||||
|
||||
class BackupManagerForm : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BackupManagerForm(Database *db, QWidget *parent = 0);
|
||||
~BackupManagerForm();
|
||||
|
||||
Database *m_db;
|
||||
|
||||
private:
|
||||
void setupForm();
|
||||
void setBackupUsage(qint64 size);
|
||||
|
||||
Ui::BackupManagerForm *ui;
|
||||
|
||||
public slots:
|
||||
void loadBackupListing(int index);
|
||||
void removeEntry(BackupItem *item);
|
||||
private slots:
|
||||
void on_filterLineEdit_textChanged(const QString &arg1);
|
||||
};
|
||||
|
||||
#endif // BACKUPMANAGERFORM_H
|
139
gui/forms/backupmanagerform.ui
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BackupManagerForm</class>
|
||||
<widget class="QWidget" name="BackupManagerForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>857</width>
|
||||
<height>478</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Backup Manager</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Online ID / Username</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="accountBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Backup Type</string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="backupComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS Vita Games</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PSP Games</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PSM Games</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PSOne Games</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PSP Savedatas</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Backups</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<property name="columnCount">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<column/>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="usageLabel">
|
||||
<property name="text">
|
||||
<string>Backup disk usage</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="FilterLineEdit" name="filterLineEdit">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">FilterLineEdit { color:gray; font-style:italic; }</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FilterLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>filterlineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
249
gui/forms/configwidget.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "configwidget.h"
|
||||
#include "ui_configwidget.h"
|
||||
|
||||
extern "C" {
|
||||
#include <vitamtp.h>
|
||||
}
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QSettings>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QStandardPaths>
|
||||
#else
|
||||
#include <QDesktopServices>
|
||||
#define QStandardPaths QDesktopServices
|
||||
#define writableLocation storageLocation
|
||||
#endif
|
||||
|
||||
ConfigWidget::ConfigWidget(QWidget *obj_parent) :
|
||||
QDialog(obj_parent),
|
||||
ui(new Ui::ConfigWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connectSignals();
|
||||
setDefaultData();
|
||||
}
|
||||
|
||||
void ConfigWidget::connectSignals()
|
||||
{
|
||||
QSignalMapper *mapper = new QSignalMapper(this);
|
||||
mapper->setMapping(ui->photoBtn, BTN_PHOTO);
|
||||
mapper->setMapping(ui->musicBtn, BTN_MUSIC);
|
||||
mapper->setMapping(ui->videoBtn, BTN_VIDEO);
|
||||
mapper->setMapping(ui->appBtn, BTN_APPS);
|
||||
mapper->setMapping(ui->urlBtn, BTN_URL);
|
||||
mapper->setMapping(ui->pkgBtn, BTN_PKG);
|
||||
connect(ui->photoBtn, SIGNAL(clicked()), mapper, SLOT(map()));
|
||||
connect(ui->musicBtn, SIGNAL(clicked()), mapper, SLOT(map()));
|
||||
connect(ui->videoBtn, SIGNAL(clicked()), mapper, SLOT(map()));
|
||||
connect(ui->appBtn, SIGNAL(clicked()), mapper, SLOT(map()));
|
||||
connect(ui->urlBtn, SIGNAL(clicked()), mapper, SLOT(map()));
|
||||
connect(ui->pkgBtn, SIGNAL(clicked()), mapper, SLOT(map()));
|
||||
connect(mapper, SIGNAL(mapped(int)), this, SLOT(browseBtnPressed(int)));
|
||||
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
|
||||
connect(ui->protocolModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolModeChanged(int)));
|
||||
}
|
||||
|
||||
void ConfigWidget::protocolModeChanged(int index)
|
||||
{
|
||||
switch(index)
|
||||
{
|
||||
case 0:
|
||||
ui->protocolBox->setEnabled(false);
|
||||
ui->protocolEdit->setEnabled(false);
|
||||
break;
|
||||
case 1:
|
||||
ui->protocolBox->setEnabled(true);
|
||||
ui->protocolEdit->setEnabled(false);
|
||||
break;
|
||||
case 2:
|
||||
ui->protocolBox->setEnabled(false);
|
||||
ui->protocolEdit->setEnabled(true);
|
||||
break;
|
||||
default:
|
||||
ui->protocolBox->setEnabled(false);
|
||||
ui->protocolEdit->setEnabled(false);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConfigWidget::setDefaultData()
|
||||
{
|
||||
QString defaultdir;
|
||||
QSettings settings;
|
||||
defaultdir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
|
||||
ui->photoPath->setText(QDir::toNativeSeparators(settings.value("photoPath", defaultdir).toString()));
|
||||
|
||||
defaultdir = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
|
||||
ui->musicPath->setText(QDir::toNativeSeparators(settings.value("musicPath", defaultdir).toString()));
|
||||
|
||||
defaultdir = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
|
||||
ui->videoPath->setText(QDir::toNativeSeparators(settings.value("videoPath", defaultdir).toString()));
|
||||
|
||||
defaultdir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
defaultdir.append(QDir::separator()).append("PS Vita");
|
||||
ui->appPath->setText(QDir::toNativeSeparators(settings.value("appsPath", defaultdir).toString()));
|
||||
|
||||
defaultdir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
defaultdir.append(QDir::separator()).append("PSV Updates");
|
||||
ui->urlPath->setText(QDir::toNativeSeparators(settings.value("urlPath", defaultdir).toString()));
|
||||
|
||||
defaultdir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
|
||||
defaultdir.append(QDir::separator()).append("PSV Packages");
|
||||
ui->pkgPath->setText(QDir::toNativeSeparators(settings.value("pkgPath", defaultdir).toString()));
|
||||
|
||||
ui->offlineCheck->setChecked(settings.value("offlineMode", true).toBool());
|
||||
ui->metadataCheck->setChecked(settings.value("skipMetadata", false).toBool());
|
||||
ui->usbCheck->setChecked(settings.value("disableUSB", false).toBool());
|
||||
ui->wifiCheck->setChecked(settings.value("disableWireless", false).toBool());
|
||||
ui->databaseSelect->setCurrentIndex(settings.value("useMemoryStorage", true).toBool() ? 0 : 1);
|
||||
|
||||
ui->photoSkipCheck->setChecked(settings.value("photoSkip", false).toBool());
|
||||
ui->videoSkipCheck->setChecked(settings.value("videoSkip", false).toBool());
|
||||
ui->musicSkipCheck->setChecked(settings.value("musicSkip", false).toBool());
|
||||
|
||||
QString protocol_mode = settings.value("protocolMode", "automatic").toString();
|
||||
|
||||
if(protocol_mode == "manual")
|
||||
ui->protocolModeBox->setCurrentIndex(1);
|
||||
else if(protocol_mode == "custom")
|
||||
ui->protocolModeBox->setCurrentIndex(2);
|
||||
else
|
||||
ui->protocolModeBox->setCurrentIndex(0);
|
||||
|
||||
protocolModeChanged(ui->protocolModeBox->currentIndex());
|
||||
|
||||
ui->protocolBox->setCurrentIndex(settings.value("protocolIndex", 0).toInt());
|
||||
|
||||
bool ok;
|
||||
int protocol_version = settings.value("protocolVersion", VITAMTP_PROTOCOL_MAX_VERSION).toInt(&ok);
|
||||
|
||||
if(ok && protocol_version > 0)
|
||||
ui->protocolEdit->setText(QString::number(protocol_version));
|
||||
else
|
||||
ui->protocolEdit->setText(QString::number(VITAMTP_PROTOCOL_MAX_VERSION));
|
||||
}
|
||||
|
||||
ConfigWidget::~ConfigWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConfigWidget::browseBtnPressed(int btn)
|
||||
{
|
||||
QString msg;
|
||||
QLineEdit *lineedit;
|
||||
|
||||
switch(btn) {
|
||||
case BTN_PHOTO:
|
||||
lineedit = ui->photoPath;
|
||||
msg = tr("Select the folder to be used as a photo source");
|
||||
break;
|
||||
|
||||
case BTN_MUSIC:
|
||||
lineedit = ui->musicPath;
|
||||
msg = tr("Select the folder to be used as a music source");
|
||||
break;
|
||||
|
||||
case BTN_VIDEO:
|
||||
lineedit = ui->videoPath;
|
||||
msg = tr("Select the folder to be used as a video source");
|
||||
break;
|
||||
|
||||
case BTN_APPS:
|
||||
lineedit = ui->appPath;
|
||||
msg = tr("Select the folder to be used to save PS Vita games and backups");
|
||||
break;
|
||||
|
||||
case BTN_URL:
|
||||
lineedit = ui->urlPath;
|
||||
msg = tr("Select the folder to be used to fetch software updates");
|
||||
break;
|
||||
|
||||
case BTN_PKG:
|
||||
lineedit = ui->pkgPath;
|
||||
msg = tr("Select the folder to be used to software packages");
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
QString selected = QFileDialog::getExistingDirectory(this, msg, lineedit->text(), QFileDialog::ShowDirsOnly);
|
||||
|
||||
if(!selected.isEmpty()) {
|
||||
lineedit->setText(QDir::toNativeSeparators((selected)));
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigWidget::savePath(QSettings &settings, const QLineEdit *edit, const QString &key)
|
||||
{
|
||||
QString path = edit->text();
|
||||
if(path.endsWith(QDir::separator())) {
|
||||
path.chop(1);
|
||||
}
|
||||
settings.setValue(key, QDir::fromNativeSeparators(path));
|
||||
QDir(QDir::root()).mkpath(path);
|
||||
}
|
||||
|
||||
void ConfigWidget::accept()
|
||||
{
|
||||
QSettings settings;
|
||||
savePath(settings, ui->photoPath, "photoPath");
|
||||
savePath(settings, ui->musicPath, "musicPath");
|
||||
savePath(settings, ui->videoPath, "videoPath");
|
||||
savePath(settings, ui->appPath, "appsPath");
|
||||
savePath(settings, ui->urlPath, "urlPath");
|
||||
savePath(settings, ui->pkgPath, "pkgPath");
|
||||
settings.setValue("offlineMode", ui->offlineCheck->isChecked());
|
||||
settings.setValue("skipMetadata", ui->metadataCheck->isChecked());
|
||||
settings.setValue("disableUSB", ui->usbCheck->isChecked());
|
||||
settings.setValue("disableWireless", ui->wifiCheck->isChecked());
|
||||
settings.setValue("useMemoryStorage", ui->databaseSelect->currentIndex() == 0);
|
||||
settings.setValue("photoSkip", ui->photoSkipCheck->isChecked());
|
||||
settings.setValue("videoSkip", ui->videoSkipCheck->isChecked());
|
||||
settings.setValue("musicSkip", ui->musicSkipCheck->isChecked());
|
||||
settings.setValue("protocolIndex", ui->protocolBox->currentIndex());
|
||||
|
||||
if(ui->protocolModeBox->currentIndex() == 0)
|
||||
settings.setValue("protocolMode", "automatic");
|
||||
else if(ui->protocolModeBox->currentIndex() == 1)
|
||||
settings.setValue("protocolMode", "manual");
|
||||
else if(ui->protocolModeBox->currentIndex() == 2)
|
||||
settings.setValue("protocolMode", "custom");
|
||||
|
||||
bool ok;
|
||||
int protocol = ui->protocolEdit->text().toInt(&ok);
|
||||
|
||||
if(ok && protocol > 0)
|
||||
settings.setValue("protocolVersion", protocol);
|
||||
else
|
||||
settings.setValue("protocolVersion", VITAMTP_PROTOCOL_MAX_VERSION);
|
||||
|
||||
settings.sync();
|
||||
|
||||
done(Accepted);
|
||||
}
|
55
gui/forms/configwidget.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CONFIGWIDGET_H
|
||||
#define CONFIGWIDGET_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLineEdit>
|
||||
#include <QSettings>
|
||||
#include <QSignalMapper>
|
||||
|
||||
namespace Ui {
|
||||
class ConfigWidget;
|
||||
}
|
||||
|
||||
class ConfigWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigWidget(QWidget *parent = 0);
|
||||
~ConfigWidget();
|
||||
|
||||
private:
|
||||
enum browse_buttons {BTN_PHOTO, BTN_MUSIC, BTN_VIDEO, BTN_APPS, BTN_URL, BTN_PKG};
|
||||
|
||||
void connectSignals();
|
||||
void setDefaultData();
|
||||
void savePath(QSettings &settings, const QLineEdit *edit, const QString &key);
|
||||
|
||||
Ui::ConfigWidget *ui;
|
||||
|
||||
private slots:
|
||||
void protocolModeChanged(int index);
|
||||
void browseBtnPressed(int from);
|
||||
void accept();
|
||||
};
|
||||
|
||||
#endif // CONFIGWIDGET_H
|
525
gui/forms/configwidget.ui
Normal file
@@ -0,0 +1,525 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfigWidget</class>
|
||||
<widget class="QWidget" name="ConfigWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>519</width>
|
||||
<height>525</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>QCMA Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Folders</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Specify the folders that the PS Vita will access for each content type.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="whatsThis">
|
||||
<string>This is the location your Screenshots and Pictures are Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Photo Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="photoPath">
|
||||
<property name="toolTip">
|
||||
<string>This is the location your Screenshots and Pictures are Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="photoBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="whatsThis">
|
||||
<string>This is the location your Videos are Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Video Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="videoPath">
|
||||
<property name="toolTip">
|
||||
<string>This is the location your Videos are Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="videoBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="whatsThis">
|
||||
<string>This is the location your Music is Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Music Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="musicPath">
|
||||
<property name="toolTip">
|
||||
<string>This is the location your Music is Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="musicBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="whatsThis">
|
||||
<string>This is the location your Games, Apps, Savegames, and System Backups are Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Applications / Backups</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="appPath">
|
||||
<property name="toolTip">
|
||||
<string>This is the location your Games, Apps, Savegames, and System Backups are Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="appBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="whatsThis">
|
||||
<string>This is the location your Software Updates and Browser Data is Saved to/Imported from.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Updates / Web content</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="urlPath">
|
||||
<property name="toolTip">
|
||||
<string>This is the location your PS Vita system will read all the content that it tries to download.</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="urlBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Packages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="pkgPath"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pkgBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Other</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600;">Advanced settings</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="offlineCheck">
|
||||
<property name="text">
|
||||
<string>Offline Mode</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="metadataCheck">
|
||||
<property name="text">
|
||||
<string>Skip metadata extraction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="usbCheck">
|
||||
<property name="text">
|
||||
<string>Disable USB monitoring</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="wifiCheck">
|
||||
<property name="text">
|
||||
<string>Disable Wi-Fi monitoring</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_3">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update database automatically when files on the PC are changed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Database backend</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="databaseSelect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>In Memory</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>SQLite</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="photoSkipCheck">
|
||||
<property name="text">
|
||||
<string>Skip photo scanning</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="videoSkipCheck">
|
||||
<property name="text">
|
||||
<string>Skip video scanning</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="musicSkipCheck">
|
||||
<property name="text">
|
||||
<string>Skip music scanning</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>CMA protocol version</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="protocolBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 3.30 - 1900010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 3.10 - 1800010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 3.00 - 1700010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 2.60 - 1600010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 2.10 - 1500010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 2.00 - 1400010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 1.80 - 1300010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 1.60 - 1200010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 1.50 - 1100010</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">FW 1.00 - 1000010</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="protocolEdit">
|
||||
<property name="inputMask">
|
||||
<string notr="true">9999999</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>CMA protocol selection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="protocolModeBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Latest</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Manual</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Custom</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>CMA custom version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
50
gui/forms/confirmdialog.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "confirmdialog.h"
|
||||
#include "ui_confirmdialog.h"
|
||||
|
||||
const QString ConfirmDialog::messageTemplate = "<html><head/><body>"
|
||||
"<p><span style=\"font-size:10pt;\">%1</span></p>"
|
||||
"<p><span style=\"font-size:12pt; font-weight:600;\">%2</span></p>"
|
||||
"</body></html>";
|
||||
|
||||
ConfirmDialog::ConfirmDialog(QWidget *obj_parent) :
|
||||
QDialog(obj_parent),
|
||||
ui(new Ui::ConfirmDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
}
|
||||
|
||||
void ConfirmDialog::setMessageText(const QString message, const QString game_title)
|
||||
{
|
||||
ui->confirmText->setText(messageTemplate.arg(message, game_title));
|
||||
}
|
||||
|
||||
void ConfirmDialog::setMessagePixmap(const QPixmap &pixmap, int dialog_width)
|
||||
{
|
||||
ui->itemPicture->setPixmap(pixmap);
|
||||
ui->itemPicture->setMinimumWidth(dialog_width);
|
||||
}
|
||||
|
||||
ConfirmDialog::~ConfirmDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
46
gui/forms/confirmdialog.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CONFIRMDIALOG_H
|
||||
#define CONFIRMDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class ConfirmDialog;
|
||||
}
|
||||
|
||||
class ConfirmDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfirmDialog(QWidget *parent = 0);
|
||||
~ConfirmDialog();
|
||||
|
||||
void setMessageText(const QString message, const QString game_title);
|
||||
void setMessagePixmap(const QPixmap &pixmap, int width);
|
||||
|
||||
static const QString messageTemplate;
|
||||
|
||||
private:
|
||||
Ui::ConfirmDialog *ui;
|
||||
};
|
||||
|
||||
#endif // CONFIRMDIALOG_H
|
120
gui/forms/confirmdialog.ui
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfirmDialog</class>
|
||||
<widget class="QDialog" name="ConfirmDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>519</width>
|
||||
<height>106</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Confirmation Message</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="itemPicture">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="confirmText">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-size:10pt;">Are you sure to delete the backup of the following game?</span></p><p><span style=" font-size:12pt; font-weight:600;">Game Name</span></p></body></html>
|
||||
</string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ConfirmDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ConfirmDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
71
gui/forms/pinform.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pinform.h"
|
||||
#include "ui_pinform.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
const QString PinForm::pinFormat =
|
||||
"<html><head/><body>"
|
||||
"<p><span style=\"font-size:24pt; font-weight:600;\">%1</span></p>"
|
||||
"</body></html>";
|
||||
|
||||
PinForm::PinForm(QWidget *obj_parent) :
|
||||
QWidget(obj_parent),
|
||||
ui(new Ui::PinForm)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
move(QApplication::desktop()->screen()->rect().center() - rect().center());
|
||||
setFixedSize(size());
|
||||
setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint);
|
||||
connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(hide()));
|
||||
}
|
||||
|
||||
void PinForm::setPin(QString name, int pin)
|
||||
{
|
||||
qDebug() << "Got pin from user " << name;
|
||||
ui->deviceLabel->setText(tr("Device: %1 (PS Vita)").arg(name));
|
||||
ui->pinLabel->setText(pinFormat.arg(QString::number(pin), 8, QChar('0')));
|
||||
show();
|
||||
}
|
||||
|
||||
void PinForm::startCountdown()
|
||||
{
|
||||
timer.setInterval(1000);
|
||||
counter = 300;
|
||||
connect(&timer, SIGNAL(timeout()), this, SLOT(decreaseTimer()));
|
||||
timer.start();
|
||||
}
|
||||
|
||||
void PinForm::decreaseTimer()
|
||||
{
|
||||
counter--;
|
||||
if(counter == 0) {
|
||||
timer.stop();
|
||||
hide();
|
||||
}
|
||||
ui->timeLabel->setText(tr("Time remaining: %1 seconds").arg(counter));
|
||||
}
|
||||
|
||||
PinForm::~PinForm()
|
||||
{
|
||||
delete ui;
|
||||
}
|
55
gui/forms/pinform.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PINFORM_H
|
||||
#define PINFORM_H
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class PinForm;
|
||||
}
|
||||
|
||||
class PinForm : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PinForm(QWidget *parent = 0);
|
||||
~PinForm();
|
||||
|
||||
private:
|
||||
Ui::PinForm *ui;
|
||||
|
||||
// pin timeout
|
||||
int counter;
|
||||
QTimer timer;
|
||||
|
||||
static const QString pinFormat;
|
||||
|
||||
public slots:
|
||||
void startCountdown();
|
||||
void setPin(QString name, int pin);
|
||||
|
||||
private slots:
|
||||
void decreaseTimer();
|
||||
};
|
||||
|
||||
#endif // PINFORM_H
|
115
gui/forms/pinform.ui
Normal file
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PinForm</class>
|
||||
<widget class="QWidget" name="PinForm">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>526</width>
|
||||
<height>216</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Device pairing</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>An unregistered PS Vita system is connecting with QCMA via Wi-Fi</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="deviceLabel">
|
||||
<property name="text">
|
||||
<string>Device: PS Vita</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Input the following number in the PS Vita system to register it with QCMA</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pinLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-size:24pt; font-weight:600;">12345678</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="timeLabel">
|
||||
<property name="text">
|
||||
<string>Time remaining: 300 seconds</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
77
gui/forms/progressform.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "progressform.h"
|
||||
#include "ui_progressform.h"
|
||||
|
||||
#include <QDesktopWidget>
|
||||
#include <QMessageBox>
|
||||
|
||||
ProgressForm::ProgressForm(QWidget *obj_parent) :
|
||||
QWidget(obj_parent),
|
||||
ui(new Ui::ProgressForm)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
move(QApplication::desktop()->screen()->rect().center() - rect().center());
|
||||
setFixedSize(size());
|
||||
setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint);
|
||||
connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(cancelConfirm()));
|
||||
}
|
||||
|
||||
ProgressForm::~ProgressForm()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ProgressForm::cancelConfirm()
|
||||
{
|
||||
QMessageBox box;
|
||||
box.setText(tr("Database indexing in progress"));
|
||||
box.setInformativeText(tr("Are you sure to cancel the database indexing?"));
|
||||
box.setIcon(QMessageBox::Warning);
|
||||
box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||
if(box.exec() == QMessageBox::Ok) {
|
||||
emit canceled();
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressForm::setFileName(QString file)
|
||||
{
|
||||
QString elided = ui->fileLabel->fontMetrics().elidedText(file, Qt::ElideMiddle, ui->fileLabel->width(), 0);
|
||||
ui->fileLabel->setText(elided);
|
||||
}
|
||||
|
||||
void ProgressForm::setDirectoryName(QString dir)
|
||||
{
|
||||
QString elided = ui->directoryLabel->fontMetrics().elidedText(dir, Qt::ElideMiddle, ui->directoryLabel->width(), 0);
|
||||
ui->directoryLabel->setText(elided);
|
||||
}
|
||||
|
||||
void ProgressForm::showDelayed(int msec)
|
||||
{
|
||||
timer.setSingleShot(true);
|
||||
timer.setInterval(msec);
|
||||
connect(&timer, SIGNAL(timeout()), this, SLOT(show()));
|
||||
timer.start();
|
||||
}
|
||||
|
||||
void ProgressForm::interruptShow()
|
||||
{
|
||||
timer.stop();
|
||||
}
|
57
gui/forms/progressform.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PROGRESSFORM_H
|
||||
#define PROGRESSFORM_H
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class ProgressForm;
|
||||
}
|
||||
|
||||
class ProgressForm : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProgressForm(QWidget *parent = 0);
|
||||
~ProgressForm();
|
||||
|
||||
void showDelayed(int msec = 1000);
|
||||
void interruptShow();
|
||||
|
||||
private:
|
||||
Ui::ProgressForm *ui;
|
||||
|
||||
QTimer timer;
|
||||
|
||||
signals:
|
||||
void canceled();
|
||||
|
||||
private slots:
|
||||
void cancelConfirm();
|
||||
|
||||
public slots:
|
||||
void setDirectoryName(QString dir);
|
||||
void setFileName(QString file);
|
||||
};
|
||||
|
||||
#endif // PROGRESSFORM_H
|
80
gui/forms/progressform.ui
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProgressForm</class>
|
||||
<widget class="QWidget" name="ProgressForm">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>602</width>
|
||||
<height>138</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Refreshing database...</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Reading directory:</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="directoryLabel">
|
||||
<property name="text">
|
||||
<string>directory name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Processing file:</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="fileLabel">
|
||||
<property name="text">
|
||||
<string>file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
83
gui/gui.pro
Normal file
@@ -0,0 +1,83 @@
|
||||
include(../config.pri)
|
||||
include(../common/defines.pri)
|
||||
|
||||
TARGET = qcma
|
||||
TEMPLATE += app
|
||||
QT += gui widgets network sql
|
||||
LIBS += -L../common -lqcma_common
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwidget.cpp \
|
||||
singleapplication.cpp \
|
||||
clientmanager.cpp \
|
||||
filterlineedit.cpp \
|
||||
qtrayicon.cpp \
|
||||
# forms
|
||||
forms/backupitem.cpp \
|
||||
forms/backupmanagerform.cpp \
|
||||
forms/configwidget.cpp \
|
||||
forms/confirmdialog.cpp \
|
||||
forms/pinform.cpp \
|
||||
forms/progressform.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwidget.h \
|
||||
singleapplication.h \
|
||||
clientmanager.h \
|
||||
filterlineedit.h \
|
||||
qtrayicon.h \
|
||||
trayindicator.h \
|
||||
trayindicator_global.h \
|
||||
# forms
|
||||
forms/backupitem.h \
|
||||
forms/backupmanagerform.h \
|
||||
forms/configwidget.h \
|
||||
forms/confirmdialog.h \
|
||||
forms/pinform.h \
|
||||
forms/progressform.h
|
||||
|
||||
FORMS += \
|
||||
forms/configwidget.ui \
|
||||
forms/backupmanagerform.ui \
|
||||
forms/backupitem.ui \
|
||||
forms/confirmdialog.ui \
|
||||
forms/progressform.ui \
|
||||
forms/pinform.ui
|
||||
|
||||
OTHER_FILES += \
|
||||
resources/images/psv_icon.png \
|
||||
resources/images/psv_icon_16.png \
|
||||
resources/images/qcma.png \
|
||||
resources/qcma.desktop \
|
||||
qcma.rc
|
||||
|
||||
RESOURCES += gui.qrc
|
||||
|
||||
# find packages using pkg-config
|
||||
PKGCONFIG = libvitamtp libavformat libavcodec libavutil libswscale
|
||||
|
||||
#Linux-only config
|
||||
unix:!macx {
|
||||
PKGCONFIG += libnotify
|
||||
|
||||
# config for desktop file and icon
|
||||
desktop.path = $$DATADIR/applications/$${TARGET}
|
||||
desktop.files += resources/$${TARGET}.desktop
|
||||
|
||||
icon64.path = $$DATADIR/icons/hicolor/64x64/apps
|
||||
icon64.files += resources/images/$${TARGET}.png
|
||||
|
||||
man.files = qcma.1
|
||||
man.path = $$MANDIR
|
||||
|
||||
target.path = $$BINDIR
|
||||
|
||||
INSTALLS += target desktop icon64 man
|
||||
}
|
||||
|
||||
# Windows config
|
||||
win32 {
|
||||
# Windows icon
|
||||
RC_FILE = qcma.rc
|
||||
}
|
12
gui/gui.qrc
Normal file
@@ -0,0 +1,12 @@
|
||||
<RCC>
|
||||
<qresource prefix="/main">
|
||||
<file>resources/images/tray/qcma_on.png</file>
|
||||
<file>resources/images/tray/qcma_on_16.png</file>
|
||||
<file>resources/images/qcma.png</file>
|
||||
<file>resources/images/edit-clear-locationbar-rtl.png</file>
|
||||
<file>resources/images/tray/qcma_off.png</file>
|
||||
<file>resources/images/tray/qcma_off_16.png</file>
|
||||
<file>resources/images/qcma_on.png</file>
|
||||
<file>resources/images/qcma_off.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
152
gui/main.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Q_OS_WIN32
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLibraryInfo>
|
||||
#include <QLocale>
|
||||
#include <QTextCodec>
|
||||
#include <QTextStream>
|
||||
#include <QThread>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "singleapplication.h"
|
||||
#include "mainwidget.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
static void noMessageOutput(QtMsgType type, const QMessageLogContext &, const QString & str)
|
||||
{
|
||||
const char * msg = str.toStdString().c_str();
|
||||
#else
|
||||
static void noMessageOutput(QtMsgType type, const char *msg)
|
||||
{
|
||||
#endif
|
||||
Q_UNUSED(type);
|
||||
Q_UNUSED(msg);
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN32
|
||||
static bool setup_handlers()
|
||||
{
|
||||
struct sigaction hup, term;
|
||||
|
||||
hup.sa_handler = ClientManager::hupSignalHandler;
|
||||
sigemptyset(&hup.sa_mask);
|
||||
hup.sa_flags = 0;
|
||||
hup.sa_flags |= SA_RESTART;
|
||||
|
||||
if (sigaction(SIGHUP, &hup, NULL) != 0) {
|
||||
qCritical("SIGHUP signal handle failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
term.sa_handler = ClientManager::termSignalHandler;
|
||||
sigemptyset(&term.sa_mask);
|
||||
term.sa_flags |= SA_RESTART;
|
||||
|
||||
if (sigaction(SIGTERM, &term, NULL) != 0) {
|
||||
qCritical("SIGTERM signal handle failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(SingleApplication::sendMessage(QObject::tr("An instance of Qcma is already running"))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SingleApplication app(argc, argv);
|
||||
|
||||
#ifndef Q_OS_WIN32
|
||||
// FIXME: libmtp sends SIGPIPE if a socket write fails crashing the whole app
|
||||
// the proper fix is to libmtp to handle the cancel properly or ignoring
|
||||
// SIGPIPE on the socket
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
setup_handlers();
|
||||
#endif
|
||||
|
||||
if(app.arguments().contains("--with-debug")) {
|
||||
VitaMTP_Set_Logging(VitaMTP_DEBUG);
|
||||
} else if(app.arguments().contains("--verbose")) {
|
||||
VitaMTP_Set_Logging(VitaMTP_VERBOSE);
|
||||
} else {
|
||||
VitaMTP_Set_Logging(VitaMTP_NONE);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
qInstallMessageHandler(noMessageOutput);
|
||||
#else
|
||||
qInstallMsgHandler(noMessageOutput);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
|
||||
QTextStream(stdout) << "Starting Qcma " << QCMA_VER << endl;
|
||||
|
||||
QTranslator translator;
|
||||
QString locale = QLocale().system().name();
|
||||
qDebug() << "Current locale:" << locale;
|
||||
|
||||
if(app.arguments().contains("--set-locale")) {
|
||||
int index = app.arguments().indexOf("--set-locale");
|
||||
if(index + 1 < app.arguments().length()) {
|
||||
qDebug("Enforcing locale: %s", app.arguments().at(index + 1).toUtf8().data());
|
||||
locale = app.arguments().at(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(translator.load("qcma_" + locale, ":/resources/translations")) {
|
||||
app.installTranslator(&translator);
|
||||
} else {
|
||||
qWarning() << "Cannot load translation for locale:" << locale;
|
||||
}
|
||||
|
||||
QTranslator system_translator;
|
||||
system_translator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||
app.installTranslator(&system_translator);
|
||||
|
||||
qDebug("Starting main thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
|
||||
|
||||
// set the organization/application for QSettings to work properly
|
||||
app.setOrganizationName("codestation");
|
||||
app.setApplicationName("qcma");
|
||||
|
||||
//TODO: check if this is actually needed since we don't have a main window by default
|
||||
QApplication::setQuitOnLastWindowClosed(false);
|
||||
|
||||
bool showSystray = !app.arguments().contains("--no-systray");
|
||||
|
||||
MainWidget widget;
|
||||
widget.prepareApplication(showSystray);
|
||||
|
||||
// receive the message from another process
|
||||
QObject::connect(&app, SIGNAL(messageAvailable(QString)), &widget, SLOT(receiveMessage(QString)));
|
||||
|
||||
return app.exec();
|
||||
}
|
281
gui/mainwidget.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mainwidget.h"
|
||||
#include "cmaclient.h"
|
||||
#include "cmautils.h"
|
||||
|
||||
#include "qlistdb.h"
|
||||
#include "sqlitedb.h"
|
||||
|
||||
#include "qtrayicon.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QGridLayout>
|
||||
#include <QLibrary>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
#include <QSettings>
|
||||
#include <QSpacerItem>
|
||||
|
||||
const QStringList MainWidget::path_list = QStringList() << "photoPath" << "musicPath" << "videoPath" << "appsPath" << "urlPath";
|
||||
|
||||
bool sleptOnce = false;
|
||||
|
||||
MainWidget::MainWidget(QWidget *obj_parent) :
|
||||
QWidget(obj_parent), db(NULL), configForm(NULL), managerForm(NULL), backupForm(NULL)
|
||||
{
|
||||
trayIcon = NULL;
|
||||
}
|
||||
|
||||
void MainWidget::checkSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
// make sure that all the paths are set, else show the config dialog
|
||||
foreach(const QString &path, path_list) {
|
||||
if(!settings.contains(path)) {
|
||||
first_run = true;
|
||||
configForm->show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
first_run = false;
|
||||
managerForm->start();
|
||||
}
|
||||
|
||||
void MainWidget::dialogResult(int result)
|
||||
{
|
||||
if(result == QDialog::Accepted) {
|
||||
if(first_run) {
|
||||
first_run = false;
|
||||
managerForm->start();
|
||||
}
|
||||
} else if(first_run) {
|
||||
qApp->quit();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::stopServer()
|
||||
{
|
||||
setTrayTooltip(tr("Shutting down..."));
|
||||
if(CmaClient::isRunning()) {
|
||||
receiveMessage(tr("Stopping QCMA (disconnect your PS Vita)"));
|
||||
}
|
||||
managerForm->stop();
|
||||
}
|
||||
|
||||
void MainWidget::deviceDisconnect()
|
||||
{
|
||||
#ifndef Q_OS_WIN32
|
||||
trayIcon->setIcon("qcma_off");
|
||||
#else
|
||||
trayIcon->setIcon("tray/qcma_off_16");
|
||||
#endif
|
||||
qDebug("Icon changed - disconnected");
|
||||
setTrayTooltip(tr("Disconnected"));
|
||||
receiveMessage(tr("The device has been disconnected"));
|
||||
}
|
||||
|
||||
void MainWidget::deviceConnect(QString message)
|
||||
{
|
||||
#ifndef Q_OS_WIN32
|
||||
trayIcon->setIcon("qcma_on");
|
||||
#else
|
||||
trayIcon->setIcon("tray/qcma_on_16");
|
||||
#endif
|
||||
qDebug("Icon changed - connected");
|
||||
setTrayTooltip(message);
|
||||
receiveMessage(message);
|
||||
}
|
||||
|
||||
void MainWidget::prepareApplication(bool showSystray)
|
||||
{
|
||||
//TODO: delete database before exit
|
||||
if(QSettings().value("useMemoryStorage", true).toBool()) {
|
||||
db = new QListDB();
|
||||
} else {
|
||||
db = new SQLiteDB();
|
||||
}
|
||||
|
||||
configForm = new ConfigWidget();
|
||||
backupForm = new BackupManagerForm(db, this);
|
||||
managerForm = new ClientManager(db, this);
|
||||
connectSignals();
|
||||
|
||||
if(showSystray) {
|
||||
createTrayIcon();
|
||||
}
|
||||
|
||||
checkSettings();
|
||||
}
|
||||
|
||||
void MainWidget::connectSignals()
|
||||
{
|
||||
connect(configForm, SIGNAL(finished(int)), this, SLOT(dialogResult(int)));
|
||||
connect(managerForm, SIGNAL(stopped()), qApp, SLOT(quit()));
|
||||
connect(managerForm, SIGNAL(deviceConnected(QString)), this, SIGNAL(deviceConnected(QString)));
|
||||
connect(managerForm, SIGNAL(deviceDisconnected()), this, SIGNAL(deviceDisconnected()));
|
||||
connect(managerForm, SIGNAL(messageSent(QString)), this, SIGNAL(messageReceived(QString)));
|
||||
connect(managerForm, SIGNAL(updated(int)), this, SIGNAL(databaseUpdated(int)));
|
||||
}
|
||||
|
||||
void MainWidget::setTrayTooltip(QString message)
|
||||
{
|
||||
if(trayIcon) {
|
||||
trayIcon->setToolTip(message);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::openManager()
|
||||
{
|
||||
backupForm->loadBackupListing(-1);
|
||||
backupForm->show();
|
||||
}
|
||||
|
||||
void MainWidget::showAboutDialog()
|
||||
{
|
||||
QMessageBox about;
|
||||
|
||||
about.setText(QString("Qcma ") + QCMA_VER);
|
||||
about.setWindowTitle(tr("About Qcma"));
|
||||
#ifndef QCMA_BUILD_HASH
|
||||
about.setInformativeText(tr("Copyright (C) 2015 Codestation") + "\n");
|
||||
#else
|
||||
about.setInformativeText(tr("Copyright (C) 2015 Codestation\n\nbuild hash: %1\nbuild branch: %2").arg(QCMA_BUILD_HASH).arg(QCMA_BUILD_BRANCH));
|
||||
#endif
|
||||
about.setStandardButtons(QMessageBox::Ok);
|
||||
about.setIconPixmap(QPixmap(":/main/resources/images/qcma.png"));
|
||||
about.setDefaultButton(QMessageBox::Ok);
|
||||
|
||||
// hack to expand the messagebox minimum size
|
||||
QSpacerItem* horizontalSpacer = new QSpacerItem(300, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
QGridLayout* widget_layout = (QGridLayout*)about.layout();
|
||||
widget_layout->addItem(horizontalSpacer, widget_layout->rowCount(), 0, 1, widget_layout->columnCount());
|
||||
|
||||
about.show();
|
||||
about.exec();
|
||||
}
|
||||
|
||||
void MainWidget::showAboutQt()
|
||||
{
|
||||
QMessageBox::aboutQt(this);
|
||||
}
|
||||
|
||||
void MainWidget::openConfig()
|
||||
{
|
||||
configForm->open();
|
||||
}
|
||||
|
||||
void MainWidget::refreshDatabase()
|
||||
{
|
||||
managerForm->refreshDatabase();
|
||||
}
|
||||
|
||||
TrayIndicator *MainWidget::createTrayObject(QWidget *obj_parent)
|
||||
{
|
||||
TrayFunctionPointer create_tray = NULL;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
QString desktop = getenv("XDG_CURRENT_DESKTOP");
|
||||
qDebug() << "Current desktop: " << desktop;
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
QString library_path = QApplication::applicationDirPath();
|
||||
#else
|
||||
QString library_path = "/usr/lib/qcma";
|
||||
#endif
|
||||
|
||||
if(desktop.toLower() == "kde")
|
||||
{
|
||||
#ifdef QT_DEBUG
|
||||
library_path += "/../kdenotifier";
|
||||
#endif
|
||||
// KDENotifier
|
||||
QLibrary library(library_path + "/libqcma_kdenotifier.so");
|
||||
if(library.load())
|
||||
create_tray = reinterpret_cast<TrayFunctionPointer>(library.resolve("createTrayIndicator"));
|
||||
else
|
||||
qWarning() << "Cannot load libqcma_kdenotifier plugin from" << library_path;
|
||||
}
|
||||
else
|
||||
// try to use the appindicator if is available
|
||||
// if(desktop.toLower() == "unity")
|
||||
{
|
||||
#ifdef QT_DEBUG
|
||||
library_path += "/../appindicator";
|
||||
#endif
|
||||
// AppIndicator
|
||||
QLibrary library(library_path + "/libqcma_appindicator.so");
|
||||
if(library.load())
|
||||
create_tray = reinterpret_cast<TrayFunctionPointer>(library.resolve("createTrayIndicator"));
|
||||
else
|
||||
qWarning() << "Cannot load libqcma_appindicator plugin from" << library_path;
|
||||
}
|
||||
#endif
|
||||
// else QSystemTrayIcon
|
||||
return (create_tray != NULL) ? create_tray(obj_parent) : createTrayIndicator(obj_parent);
|
||||
}
|
||||
|
||||
void MainWidget::createTrayIcon()
|
||||
{
|
||||
trayIcon = createTrayObject(this);
|
||||
trayIcon->init();
|
||||
|
||||
#ifndef Q_OS_WIN32
|
||||
trayIcon->setIcon("qcma_off");
|
||||
#else
|
||||
trayIcon->setIcon("tray/qcma_off_16");
|
||||
#endif
|
||||
trayIcon->show();
|
||||
|
||||
connect(trayIcon, SIGNAL(openConfig()), this, SLOT(openConfig()));
|
||||
connect(trayIcon, SIGNAL(openManager()), this, SLOT(openManager()));
|
||||
connect(trayIcon, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
|
||||
connect(trayIcon, SIGNAL(showAboutDialog()), this, SLOT(showAboutDialog()));
|
||||
connect(trayIcon, SIGNAL(showAboutQt()), this, SLOT(showAboutQt()));
|
||||
connect(trayIcon, SIGNAL(stopServer()), this, SLOT(stopServer()));
|
||||
|
||||
connect(managerForm, SIGNAL(deviceConnected(QString)), this, SLOT(deviceConnect(QString)));
|
||||
connect(managerForm, SIGNAL(deviceDisconnected()), this, SLOT(deviceDisconnect()));
|
||||
connect(managerForm, SIGNAL(messageSent(QString)), this, SLOT(receiveMessage(QString)));
|
||||
}
|
||||
|
||||
void MainWidget::receiveMessage(QString message)
|
||||
{
|
||||
// a timeout is added before the popups are displayed to prevent them from
|
||||
// appearing in the wrong location
|
||||
if(!sleptOnce) {
|
||||
Sleeper::sleep(1);
|
||||
sleptOnce = true;
|
||||
}
|
||||
|
||||
if(trayIcon->isVisible())
|
||||
trayIcon->showMessage(tr("Information"), message);
|
||||
}
|
||||
|
||||
MainWidget::~MainWidget()
|
||||
{
|
||||
if(trayIcon) {
|
||||
trayIcon->hide();
|
||||
}
|
||||
delete db;
|
||||
}
|
90
gui/mainwidget.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAINWIDGET_H
|
||||
#define MAINWIDGET_H
|
||||
|
||||
#include "cmaclient.h"
|
||||
#include "clientmanager.h"
|
||||
#include "forms/configwidget.h"
|
||||
#include "forms/backupmanagerform.h"
|
||||
#include "forms/progressform.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QWidget>
|
||||
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#include <vitamtp.h>
|
||||
|
||||
class TrayIndicator;
|
||||
|
||||
class MainWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWidget(QWidget *parent = 0);
|
||||
~MainWidget();
|
||||
|
||||
void prepareApplication(bool showSystray);
|
||||
|
||||
private:
|
||||
void connectSignals();
|
||||
void createTrayIcon();
|
||||
void checkSettings();
|
||||
TrayIndicator *createTrayObject(QWidget *parent);
|
||||
|
||||
bool first_run;
|
||||
|
||||
// database
|
||||
Database *db;
|
||||
|
||||
// forms
|
||||
ConfigWidget *configForm;
|
||||
ClientManager *managerForm;
|
||||
BackupManagerForm *backupForm;
|
||||
|
||||
TrayIndicator *trayIcon;
|
||||
|
||||
const static QStringList path_list;
|
||||
|
||||
signals:
|
||||
void deviceConnected(QString);
|
||||
void deviceDisconnected();
|
||||
void databaseUpdated(int count);
|
||||
void messageReceived(QString message);
|
||||
|
||||
public slots:
|
||||
void openConfig();
|
||||
void openManager();
|
||||
void showAboutQt();
|
||||
void showAboutDialog();
|
||||
void refreshDatabase();
|
||||
void stopServer();
|
||||
|
||||
private slots:
|
||||
void deviceConnect(QString message);
|
||||
void deviceDisconnect();
|
||||
void dialogResult(int result);
|
||||
void receiveMessage(QString message);
|
||||
void setTrayTooltip(QString message);
|
||||
};
|
||||
|
||||
#endif // MAINWIDGET_H
|
14
gui/qcma.1
Normal file
@@ -0,0 +1,14 @@
|
||||
.TH QCMA 1 "MARCH 2015"
|
||||
.SH NAME
|
||||
qcma \- Content manager for the PlayStation Vita
|
||||
.SH SYNOPSIS
|
||||
.B qcma
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBqcma\fR is a cross-platform application to provide an Open Source implementation
|
||||
of the original Content Manager Assistant that comes with the PS Vita.
|
||||
.TP
|
||||
Qcma will let you backup your games, songs, photos & videos via USB or wireless.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.I /usr/share/doc/qcma/README.md
|
1
gui/qcma.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "resources/images/qcma.ico"
|
117
gui/qtrayicon.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qtrayicon.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QMenu>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#undef signals
|
||||
extern "C" {
|
||||
#include <libnotify/notify.h>
|
||||
}
|
||||
#define signals public
|
||||
#endif
|
||||
|
||||
QTrayIcon::QTrayIcon(QWidget *obj_parent)
|
||||
: TrayIndicator(obj_parent)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
notify_init("qcma");
|
||||
#endif
|
||||
}
|
||||
|
||||
QTrayIcon::~QTrayIcon()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
notify_uninit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void QTrayIcon::init()
|
||||
{
|
||||
options = new QAction(tr("Settings"), this);
|
||||
reload = new QAction(tr("Refresh database"), this);
|
||||
backup = new QAction(tr("Backup Manager"), this);
|
||||
about = new QAction(tr("About QCMA"), this);
|
||||
about_qt = new QAction(tr("About Qt"), this);
|
||||
quit = new QAction(tr("Quit"), this);
|
||||
|
||||
connect(options, SIGNAL(triggered()), this, SIGNAL(openConfig()));
|
||||
connect(backup, SIGNAL(triggered()), this, SIGNAL(openManager()));
|
||||
connect(reload, SIGNAL(triggered()), this, SIGNAL(refreshDatabase()));
|
||||
connect(about, SIGNAL(triggered()), this, SIGNAL(showAboutDialog()));
|
||||
connect(about_qt, SIGNAL(triggered()), this, SIGNAL(showAboutQt()));
|
||||
connect(quit, SIGNAL(triggered()), this, SIGNAL(stopServer()));
|
||||
|
||||
QMenu *tray_icon_menu = new QMenu(this);
|
||||
|
||||
tray_icon_menu->addAction(options);
|
||||
tray_icon_menu->addAction(reload);
|
||||
tray_icon_menu->addAction(backup);
|
||||
tray_icon_menu->addSeparator();
|
||||
tray_icon_menu->addAction(about);
|
||||
tray_icon_menu->addAction(about_qt);
|
||||
tray_icon_menu->addSeparator();
|
||||
tray_icon_menu->addAction(quit);
|
||||
|
||||
m_tray_icon = new QSystemTrayIcon(this);
|
||||
m_tray_icon->setContextMenu(tray_icon_menu);
|
||||
}
|
||||
|
||||
|
||||
void QTrayIcon::showMessage(const QString &title, const QString &message)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
NotifyNotification *notif = notify_notification_new(qPrintable(title), qPrintable(message), "dialog-information");
|
||||
notify_notification_show(notif, NULL);
|
||||
g_object_unref(G_OBJECT(notif));
|
||||
#else
|
||||
m_tray_icon->showMessage(title, message);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool QTrayIcon::isVisible()
|
||||
{
|
||||
return m_tray_icon->isVisible();
|
||||
}
|
||||
|
||||
void QTrayIcon::setIcon(const QString &icon)
|
||||
{
|
||||
QIcon qicon(":/main/resources/images/" + icon + ".png");
|
||||
m_tray_icon->setIcon(qicon);
|
||||
}
|
||||
|
||||
void QTrayIcon::show()
|
||||
{
|
||||
m_tray_icon->show();
|
||||
}
|
||||
|
||||
void QTrayIcon::hide()
|
||||
{
|
||||
m_tray_icon->hide();
|
||||
}
|
||||
|
||||
// exported library function
|
||||
TrayIndicator *createTrayIndicator(QWidget *parent)
|
||||
{
|
||||
return new QTrayIcon(parent);
|
||||
}
|
53
gui/qtrayicon.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QTRAYICON_H
|
||||
#define QTRAYICON_H
|
||||
|
||||
#include "trayindicator.h"
|
||||
|
||||
class QAction;
|
||||
class QSystemTrayIcon;
|
||||
|
||||
class QTrayIcon : public TrayIndicator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QTrayIcon(QWidget *parent = 0);
|
||||
~QTrayIcon();
|
||||
void init();
|
||||
void setIcon(const QString &icon);
|
||||
bool isVisible();
|
||||
void show();
|
||||
void hide();
|
||||
void showMessage(const QString &title, const QString &message);
|
||||
|
||||
private:
|
||||
//system tray
|
||||
QAction *quit;
|
||||
QAction *reload;
|
||||
QAction *options;
|
||||
QAction *backup;
|
||||
QAction *about;
|
||||
QAction *about_qt;
|
||||
|
||||
QSystemTrayIcon *m_tray_icon;
|
||||
};
|
||||
|
||||
#endif // QTRAYICON_H
|
BIN
gui/resources/images/edit-clear-locationbar-rtl.png
Normal file
After Width: | Height: | Size: 859 B |
BIN
gui/resources/images/qcma.icns
Normal file
BIN
gui/resources/images/qcma.ico
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
gui/resources/images/qcma.png
Normal file
After Width: | Height: | Size: 994 B |
BIN
gui/resources/images/qcma_off.png
Normal file
After Width: | Height: | Size: 984 B |
BIN
gui/resources/images/qcma_on.png
Normal file
After Width: | Height: | Size: 994 B |
BIN
gui/resources/images/tray/qcma_off.png
Normal file
After Width: | Height: | Size: 336 B |
BIN
gui/resources/images/tray/qcma_off_16.png
Normal file
After Width: | Height: | Size: 301 B |
BIN
gui/resources/images/tray/qcma_on.png
Normal file
After Width: | Height: | Size: 387 B |
BIN
gui/resources/images/tray/qcma_on_16.png
Normal file
After Width: | Height: | Size: 344 B |
18
gui/resources/qcma.desktop
Normal file
@@ -0,0 +1,18 @@
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Exec=qcma
|
||||
GenericName=Content Manager Assistant
|
||||
GenericName[es]=Asistente del Gestor de Contenido
|
||||
GenericName[fr]=Gestionnaire de contenu
|
||||
Comment=Content Manager Assistant for the PS Vita
|
||||
Comment[es]=Asistente del Gestor de Contenido para PS Vita
|
||||
Comment[fr]=Gestionnaire de contenu pour la PS Vita
|
||||
Icon=qcma.png
|
||||
Name=QCMA
|
||||
Path=
|
||||
StartupNotify=false
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Version=1.0
|
||||
X-KDE-SubstituteUID=false
|
||||
Categories=Qt;Utility;
|
69
gui/singleapplication.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "singleapplication.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
const int SingleApplication::timeout = 500;
|
||||
const QString SingleApplication::SHARED_KEY = "QCMA_KEY";
|
||||
|
||||
SingleApplication::SingleApplication(int &s_argc, char **s_argv) :
|
||||
QApplication(s_argc, s_argv)
|
||||
{
|
||||
server = new QLocalServer(this);
|
||||
connect(server, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
|
||||
QLocalServer::removeServer(SHARED_KEY);
|
||||
server->listen(SHARED_KEY);
|
||||
}
|
||||
|
||||
void SingleApplication::receiveMessage()
|
||||
{
|
||||
QLocalSocket *socket = server->nextPendingConnection();
|
||||
|
||||
if(!socket->waitForReadyRead(timeout)) {
|
||||
qDebug() << socket->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray byteArray = socket->readAll();
|
||||
QString message = QString::fromUtf8(byteArray.constData());
|
||||
emit messageAvailable(message);
|
||||
socket->disconnectFromServer();
|
||||
}
|
||||
|
||||
bool SingleApplication::sendMessage(const QString &message)
|
||||
{
|
||||
QLocalSocket socket;
|
||||
socket.connectToServer(SHARED_KEY, QIODevice::WriteOnly);
|
||||
|
||||
if(!socket.waitForConnected(timeout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
socket.write(message.toUtf8());
|
||||
|
||||
if(!socket.waitForBytesWritten(timeout)) {
|
||||
qDebug() << socket.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
socket.disconnectFromServer();
|
||||
return true;
|
||||
}
|
50
gui/singleapplication.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2013 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SINGLEAPPLICATION_H
|
||||
#define SINGLEAPPLICATION_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QLocalSocket>
|
||||
#include <QLocalServer>
|
||||
#include <QSharedMemory>
|
||||
|
||||
class SingleApplication : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SingleApplication(int &argc, char **argv);
|
||||
|
||||
static bool sendMessage(const QString &message);
|
||||
|
||||
private:
|
||||
QLocalServer *server;
|
||||
|
||||
static const int timeout;
|
||||
static const QString SHARED_KEY;
|
||||
|
||||
signals:
|
||||
void messageAvailable(QString message);
|
||||
|
||||
|
||||
public slots:
|
||||
void receiveMessage();
|
||||
};
|
||||
|
||||
#endif // SINGLEAPPLICATION_H
|
62
gui/trayindicator.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRAYINDICATOR_H
|
||||
#define TRAYINDICATOR_H
|
||||
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
#include "trayindicator_global.h"
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
// in Qt4 signals are protected
|
||||
#undef signals
|
||||
#define signals public
|
||||
#endif
|
||||
|
||||
class TrayIndicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~TrayIndicator() {}
|
||||
virtual void init() = 0;
|
||||
virtual bool isVisible() = 0;
|
||||
virtual void setIcon(const QString &icon) = 0;
|
||||
virtual void showMessage(const QString &title, const QString &message) = 0;
|
||||
virtual void show() = 0;
|
||||
virtual void hide() = 0;
|
||||
|
||||
protected:
|
||||
TrayIndicator(QWidget *obj_parent = 0) : QWidget(obj_parent) {}
|
||||
|
||||
signals:
|
||||
void openConfig();
|
||||
void openManager();
|
||||
void refreshDatabase();
|
||||
void showAboutDialog();
|
||||
void showAboutQt();
|
||||
void stopServer();
|
||||
|
||||
};
|
||||
|
||||
typedef TrayIndicator *(*TrayFunctionPointer)(QWidget *parent);
|
||||
extern "C" TRAYINDICATORSHARED_EXPORT TrayIndicator *createTrayIndicator(QWidget *parent = 0);
|
||||
|
||||
#endif // TRAYINDICATOR_H
|
35
gui/trayindicator_global.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* QCMA: Cross-platform content manager assistant for the PS Vita
|
||||
*
|
||||
* Copyright (C) 2014 Codestation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRAYINDICATOR_GLOBAL_H
|
||||
#define TRAYINDICATOR_GLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#if defined(QCMA_TRAYINDICATOR_LIBRARY)
|
||||
# define TRAYINDICATORSHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define TRAYINDICATORSHARED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
# define TRAYINDICATORSHARED_EXPORT
|
||||
#endif
|
||||
|
||||
#endif // TRAYINDICATOR_GLOBAL_H
|