Workout Library Part 1 of 3

Implementing a workout library that keeps
track of media and workouts that can be used
in train view.

This first part implements;
- library.xml to record search paths
- search dialog to find media/workouts

Part 2 and 3 will bring:
- Sqllite libraryDB to store found details
- Update traintool to use libraryDB and display
  icons, duration/distance, IF and TSS in list
- import and drag-n-drop of new media/workouts
This commit is contained in:
Mark Liversedge
2012-12-20 13:30:49 +00:00
parent 595f378464
commit 3752c80f52
15 changed files with 833 additions and 67 deletions

View File

@@ -21,6 +21,25 @@
#include <stdint.h>
#include "Units.h"
// Supported file types
static QStringList supported;
static bool setSupported()
{
::supported << ".erg";
::supported << ".mrc";
::supported << ".crs";
::supported << ".pgmf";
return true;
}
static bool isinit = setSupported();
bool ErgFile::isWorkout(QString name)
{
foreach(QString extension, supported) {
if (name.endsWith(extension, Qt::CaseInsensitive))
return true;
}
return false;
}
ErgFile::ErgFile(QString filename, int &mode, double Cp, MainWindow *main) :
Cp(Cp), filename(filename), main(main), mode(mode)
{

View File

@@ -72,6 +72,7 @@ class ErgFile
~ErgFile(); // delete the contents
static ErgFile *fromContent(QString, MainWindow *); // read from memory
static bool isWorkout(QString); // is this a supported workout?
void reload(); // reload after messed about
void parseComputrainer(QString p = ""); // its an erg,crs or mrc file

View File

@@ -111,7 +111,13 @@ class HourTimeScaleDraw: public QwtScaleDraw
public:
HourTimeScaleDraw() { }
virtual QwtText label(double v) const { return QString("%1").arg(round(v/60000)); }
virtual QwtText label(double v) const {
v /= 1000;
QTime t = QTime().addSecs(v);
if (scaleMap().sDist() > 5)
return t.toString("hh:mm");
return t.toString("hh:mm:ss");
}
};
class ErgFilePlot : public QwtPlot

416
src/Library.cpp Normal file
View File

@@ -0,0 +1,416 @@
/*
* Copyright (c) 2012 Mark Liversedge (liversedge@gmail.com)
*
* 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 2 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, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Library.h"
#include "Settings.h"
#include "LibraryParser.h"
#include <QVBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QApplication>
#include <QDirIterator>
#include <QFileInfo>
// helpers
#ifdef Q_OS_MAC
#include "QtMacVideoWindow.h"
#else
#include "VideoWindow.h"
#endif
#include "ErgFile.h"
QList<Library*> libraries; // keep track of all the library search paths (global)
//
// MAINTAIN 'libraries' GLOBAL
//
Library *
Library::findLibrary(QString name)
{
foreach(Library *l, ::libraries)
if (l->name == name)
return l;
return NULL;
}
void
Library::initialise(QDir home)
{
// Search paths from library.xml
if (libraries.count() == 0) {
// it sits above all cyclist directories
home.cdUp();
// lets read library.xml, if not there then add workout config
// if thats not set then add home
QFile libraryXML(home.absolutePath() + "/library.xml");
if (libraryXML.exists() == true) {
// parse it!
QXmlInputSource source(&libraryXML);
QXmlSimpleReader xmlReader;
LibraryParser(handler);
xmlReader.setContentHandler(&handler);
xmlReader.setErrorHandler(&handler);
xmlReader.parse( source );
libraries = handler.getLibraries();
} else {
Library *one = new Library;
one->name = "Media Library";
QString spath = appsettings->value(NULL, GC_WORKOUTDIR).toString();
if (spath == "") spath = home.absolutePath();
one->paths.append(spath);
libraries.append(one);
}
}
}
//
// SEARCHDIALOG -- user select paths and files and run a search
//
LibrarySearchDialog::LibrarySearchDialog(MainWindow *mainWindow) : mainWindow(mainWindow)
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(tr("Search for Workouts and Media"));
setMinimumWidth(600);
searcher = NULL;
findWorkouts = new QCheckBox(tr("Workout files (.erg, .mrc etc)"), this);
findWorkouts->setChecked(true);
findMedia = new QCheckBox(tr("Video files (.mp4, .avi etc)"), this);
findMedia->setChecked(true);
addPath = new QPushButton("+", this);
removePath = new QPushButton("-", this);
#ifndef Q_OS_MAC
addPath->setFixedSize(20,20);
removePath->setFixedSize(20,20);
#endif
searchPathTable = new QTreeWidget(this);
#ifdef Q_OS_MAC
// get rid of annoying focus rectangle
searchPathTable->setAttribute(Qt::WA_MacShowFocusRect, 0);
#endif
searchPathTable->setColumnCount(1);
searchPathTable->setIndentation(0);
searchPathTable->headerItem()->setText(0, tr("Search Path"));
searchPathTable->setSelectionMode(QAbstractItemView::SingleSelection);
searchPathTable->setAlternatingRowColors (false);
library = Library::findLibrary("Media Library");
if (library) {
int i=1;
foreach (QString path, library->paths) {
QTreeWidgetItem *item = new QTreeWidgetItem(searchPathTable->invisibleRootItem(), i++);
item->setText(0, path);
}
}
pathLabelTitle = new QLabel(tr("Searching..."), this);
pathLabel = new QLabel(this);
mediaCountTitle = new QLabel(tr("Videos"), this);
mediaCount = new QLabel(this);
workoutCountTitle = new QLabel(tr("Workouts"), this);
workoutCount = new QLabel(this);
cancelButton = new QPushButton(tr("Cancel"), this);
cancelButton->setDefault(false);
searchButton = new QPushButton(tr("Search"), this);
searchButton->setDefault(true);
QLabel *searchLabel = new QLabel(tr("Files to search for:"), this);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(searchLabel);
mainLayout->addWidget(findWorkouts, Qt::AlignCenter);
mainLayout->addWidget(findMedia, Qt::AlignCenter);
QHBoxLayout *editButtons = new QHBoxLayout;
QVBoxLayout *tableLayout = new QVBoxLayout;
editButtons->addWidget(addPath);
editButtons->addWidget(removePath);
editButtons->addStretch();
editButtons->setSpacing(2);
tableLayout->setSpacing(2);
tableLayout->addWidget(searchPathTable);
tableLayout->addLayout(editButtons);
mainLayout->addLayout(tableLayout);
QGridLayout *progressLayout = new QGridLayout;
progressLayout->addWidget(pathLabelTitle, 0,0);
progressLayout->addWidget(mediaCountTitle, 0,1);
progressLayout->addWidget(workoutCountTitle, 0,2);
progressLayout->addWidget(pathLabel, 1,0);
progressLayout->addWidget(mediaCount, 1,1);
progressLayout->addWidget(workoutCount, 1,2);
progressLayout->setColumnStretch(0, 7);
progressLayout->setColumnStretch(1, 1);
progressLayout->setColumnStretch(2, 1);
mainLayout->addLayout(progressLayout);
QHBoxLayout *buttons = new QHBoxLayout;
buttons->addStretch();
buttons->addWidget(cancelButton);
buttons->addWidget(searchButton);
mainLayout->addStretch();
mainLayout->addLayout(buttons);
setSearching(false);
connect(addPath, SIGNAL(clicked()), this, SLOT(addDirectory()));
connect(removePath, SIGNAL(clicked()), this, SLOT(removeDirectory()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancel()));
connect(searchButton, SIGNAL(clicked()), this, SLOT(search()));
}
void
LibrarySearchDialog::setWidgets()
{
if (searching) {
setFixedHeight(200);
searchButton->hide();
cancelButton->setText(tr("Abort Search"));
searchPathTable->hide();
addPath->hide();
removePath->hide();
pathLabelTitle->show();
pathLabel->show();
mediaCountTitle->show();
mediaCount->show();
workoutCountTitle->show();
workoutCount->show();
} else {
setFixedHeight(300);
searchButton->show();
cancelButton->setText(tr("Cancel"));
searchPathTable->show();
addPath->show();
removePath->show();
pathLabelTitle->hide();
pathLabel->hide();
mediaCountTitle->hide();
mediaCount->hide();
workoutCountTitle->hide();
workoutCount->hide();
}
}
void
LibrarySearchDialog::search()
{
if (searchButton->text() == tr("Save")) {
// first lets update the library paths to
// reflect the user selections
if (library) {
library->paths.clear();
for(int i=0; i<searchPathTable->invisibleRootItem()->childCount(); i++) {
QTreeWidgetItem *item = searchPathTable->invisibleRootItem()->child(i);
QString path = item->text(0);
library->paths.append(path);
}
// now write to disk..
LibraryParser::serialize(mainWindow->home);
}
// ok, we;ve completed a search without aborting
// so lets rebuild the database of workouts and videos
// using what we found...
updateDB();
close();
}
if (searching) {
// do next search path...
if (++pathIndex >= searchPathTable->invisibleRootItem()->childCount()) {
searcher = NULL;
pathLabel->setText(tr("Search completed."));
pathLabelTitle->setText("");
searchButton->setText(tr("Save"));
searchButton->show();
cancelButton->hide();
return;
} else {
QTreeWidgetItem *item = searchPathTable->invisibleRootItem()->child(pathIndex);
QString path = item->text(0);
searcher = new LibrarySearch(path);
}
} else {
setSearching(true);
workoutCountN = videoCountN = pathIndex = 0;
workoutCount->setText(QString("%1").arg(++workoutCountN));
mediaCount->setText(QString("%1").arg(++videoCountN));
QTreeWidgetItem *item = searchPathTable->invisibleRootItem()->child(pathIndex);
QString path = item->text(0);
searcher = new LibrarySearch(path);
}
connect(searcher, SIGNAL(done()), this, SLOT(search()));
connect(searcher, SIGNAL(searching(QString)), this, SLOT(pathsearching(QString)));
connect(searcher, SIGNAL(foundVideo(QString)), this, SLOT(foundVideo(QString)));
connect(searcher, SIGNAL(foundWorkout(QString)), this, SLOT(foundWorkout(QString)));
searcher->start();
}
void
LibrarySearchDialog::pathsearching(QString text)
{
pathLabel->setText(text);
}
void
LibrarySearchDialog::foundWorkout(QString name)
{
workoutCount->setText(QString("%1").arg(++workoutCountN));
workoutsFound << name;
}
void
LibrarySearchDialog::foundVideo(QString name)
{
mediaCount->setText(QString("%1").arg(++videoCountN));
videosFound << name;
qDebug()<<"vid:"<<name;
}
void
LibrarySearchDialog::cancel()
{
if (searching) {
if (searcher) {
searcher->abort();
searcher = NULL;
// we will NOT get a done signal...
}
// ...so lets clean up
setSearching(false);
return;
}
// lets close
accept();
}
void
LibrarySearchDialog::addDirectory()
{
QString dir = QFileDialog::getExistingDirectory(this, tr("Select Directory"),
"", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
// add to tree
if (dir != "") {
QTreeWidgetItem *item = new QTreeWidgetItem(searchPathTable->invisibleRootItem(),
searchPathTable->invisibleRootItem()->childCount()+1);
item->setText(0, dir);
}
}
void
LibrarySearchDialog::removeDirectory()
{
// remove the currently selected item
if (searchPathTable->selectedItems().isEmpty()) return;
QTreeWidgetItem *which = searchPathTable->selectedItems().first();
if (which) {
searchPathTable->invisibleRootItem()->removeChild(which);
delete which;
}
}
void
LibrarySearchDialog::updateDB()
{
// update the database of workouts and videos
//XXX update db here...
}
//
// SEARCH -- traverse a directory looking for files and signal to notify of progress etc
//
LibrarySearch::LibrarySearch(QString path) : path(path)
{
aborted = false;
}
void
LibrarySearch::run()
{
MediaHelper helper;
// file tree walking
QDirIterator directory_walker(path, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
while(directory_walker.hasNext()){
directory_walker.next();
// whizz through every file in the directory
// if it has the right extension then we are happy
QString name = directory_walker.filePath();
// skip . files
if (QFileInfo(name).fileName().startsWith(",")) continue;
emit searching(QFileInfo(name).filePath());
// we've been told to stop!
if (aborted) {
// we don't emit done -- since it kicks off another search
return;
}
// is a video?
if (helper.isMedia(name)) emit foundVideo(name);
// is a workout?
if (ErgFile::isWorkout(name)) emit foundWorkout(name);
}
emit done();
};
void
LibrarySearch::abort()
{
aborted = true;
}

119
src/Library.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2012 Mark Liversedge (liversedge@gmail.com)
*
* 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 2 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, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _Library_h
#define _Library_h
#include "GoldenCheetah.h"
#include <QDir>
#include <QLabel>
#include <QDialog>
#include <QCheckBox>
#include <QPushButton>
#include <QTextEdit>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QThread>
class Library
{
public:
QString name; // e.g. Media Library
QList<QString> paths; // array of search paths for files in this library
static void initialise(QDir); // init
static Library *findLibrary(QString);
};
extern QList<Library *> libraries; // keep track of all Library search paths for all users
class LibrarySearch;
class LibrarySearchDialog : public QDialog
{
Q_OBJECT
public:
LibrarySearchDialog(MainWindow *mainWindow);
private slots:
void search();
void cancel();
void pathsearching(QString);
void foundWorkout(QString);
void foundVideo(QString);
void addDirectory();
void removeDirectory();
void updateDB();
private:
MainWindow *mainWindow;
Library *library;
LibrarySearch *searcher;
bool searching;
int pathIndex, workoutCountN, videoCountN;
QStringList workoutsFound, videosFound;
// let us know we are searching
void setSearching(bool amsearching) {
searching = amsearching;
setWidgets();
}
// update widgets to switch between searching and not searching
void setWidgets();
// gui widgets
QCheckBox *findWorkouts,
*findMedia;
QPushButton *addPath,
*removePath;
QTreeWidget *searchPathTable;
QTreeWidgetItem *allPaths;
QLabel *pathLabelTitle, *mediaCountTitle, *workoutCountTitle;
QLabel *pathLabel, *mediaCount, *workoutCount;
QPushButton *cancelButton,
*searchButton;
};
class LibrarySearch : public QThread
{
Q_OBJECT
public:
LibrarySearch(QString path);
void run();
public slots:
void abort();
signals:
void searching(QString);
void done();
void foundVideo(QString);
void foundWorkout(QString);
private:
volatile bool aborted;
QString path;
};
#endif // _Library_h

99
src/LibraryParser.cpp Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2012 Mark Liversedge (liversedge@gmail.com)
*
* 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 2 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, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Library.h"
#include "LibraryParser.h"
#include <QDebug>
static inline QString unquote(QString quoted)
{
return quoted.mid(1,quoted.length()-2);
}
bool LibraryParser::startDocument()
{
buffer.clear();
return TRUE;
}
bool LibraryParser::endElement( const QString&, const QString&, const QString &qName )
{
if(qName == "library") {
libraries.append(library);
}
// another search path for this library
if (qName == "path") {
library->paths.append(buffer.trimmed());
}
return TRUE;
}
bool LibraryParser::startElement( const QString&, const QString&, const QString &name, const QXmlAttributes &attrs)
{
// start of a new library definition
buffer.clear();
if(name == "library") {
library = new Library();
for(int i=0; i<attrs.count(); i++) {
if (attrs.qName(i) == "name") library->name = attrs.value(i);
}
}
return TRUE;
}
bool LibraryParser::characters(const QString& str)
{
buffer += str;
return TRUE;
}
bool
LibraryParser::serialize(QDir home)
{
// we write to root of all cyclists
home.cdUp();
// open file - truncate contents
QString filename = home.absolutePath() + "/library.xml";
QFile file(filename);
file.open(QFile::WriteOnly);
file.resize(0);
QTextStream out(&file);
out.setCodec("UTF-8");
// write out to file
foreach (Library *l, ::libraries) {
// begin document
out << QString("<library name=\"%1\">\n").arg(l->name);
// paths...
foreach(QString p, l->paths)
out << QString("\t<path>%1</path>\n").arg(p);
// end document
out << "</library>\n";
}
// close file
file.close();
return true; // success
}

51
src/LibraryParser.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2012 Mark Liversedge (liversedge@gmail.com)
*
* 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 2 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, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LibraryParser_h
#define _LibraryParser_h
#include "GoldenCheetah.h"
#include <QXmlDefaultHandler>
#include "Library.h"
class LibraryParser : public QXmlDefaultHandler
{
public:
// save
static bool serialize(QDir);
// restore
bool startDocument();
bool endElement(const QString&, const QString&, const QString &qName);
bool startElement(const QString&, const QString&, const QString &name, const QXmlAttributes &attrs);
bool characters(const QString& str);
QList<Library*> &getLibraries() { return libraries; }
protected:
// state whilst parsing
QString buffer;
Library *library; // the one being currently processed
// all libraries read
QList<Library *> libraries;
};
#endif //LibraryParser

View File

@@ -119,8 +119,10 @@
#include <boost/scoped_ptr.hpp>
#include <boost/version.hpp>
QList<MainWindow *> mainwindows; // keep track of all the MainWindows we have open
#include "Library.h"
#include "LibraryParser.h"
QList<MainWindow *> mainwindows; // keep track of all the MainWindows we have open
MainWindow::MainWindow(const QDir &home) :
home(home), session(0), isclean(false), ismultisave(false),
@@ -136,7 +138,13 @@ MainWindow::MainWindow(const QDir &home) :
static const QIcon tileIcon(":images/toolbar/main/tile.png");
static const QIcon fullIcon(":images/toolbar/main/togglefull.png");
mainwindows.append(this); // add us to the list of open windows
/*----------------------------------------------------------------------
* Basic State / Config
*--------------------------------------------------------------------*/
mainwindows.append(this); // add us to the list of open windows
// search paths
Library::initialise(home);
// Network proxy
QNetworkProxyQuery npq(QUrl("http://www.google.com"));
@@ -800,6 +808,7 @@ MainWindow::MainWindow(const QDir &home) :
optionsMenu->addSeparator();
optionsMenu->addAction(tr("Workout Wizard"), this, SLOT(showWorkoutWizard()));
optionsMenu->addAction(tr("Get Workouts from ErgDB"), this, SLOT(downloadErgDB()));
optionsMenu->addAction(tr("Manage Media/Workout Library"), this, SLOT(manageLibrary()));
#ifdef GC_HAVE_ICAL
optionsMenu->addSeparator();
@@ -1972,6 +1981,16 @@ MainWindow::downloadErgDB()
}
}
/*----------------------------------------------------------------------
* Workout/Media Library
*--------------------------------------------------------------------*/
void
MainWindow::manageLibrary()
{
LibrarySearchDialog *search = new LibrarySearchDialog(this);
search->exec();
}
/*----------------------------------------------------------------------
* TrainingPeaks.com
*--------------------------------------------------------------------*/

View File

@@ -70,6 +70,7 @@ class ChartSettings;
class QtMacSegmentedButton;
class GcScopeBar;
class RideFileCache;
class Library;
extern QList<MainWindow *> mainwindows; // keep track of all the MainWindows we have open
@@ -261,6 +262,7 @@ class MainWindow : public QMainWindow
void uploadRideWithGPSAction();
void uploadTtb();
void downloadErgDB();
void manageLibrary();
void manualProcess(QString);
#ifdef GC_HAVE_SOAP
void uploadTP();

View File

@@ -58,8 +58,10 @@ class MediaHelper
// get a list of supported media
// found in the supplied directory
QStringList listMedia(QDir directory);
bool isMedia(QString);
private:
QStringList supported;
};
class QtMacMovieView : public QMacCocoaViewContainer

View File

@@ -26,6 +26,28 @@
#include "QtMacVideoWindow.h"
static inline NSString *darwinQStringToNSString (const QString &aString)
{
return [reinterpret_cast<const NSString *> (CFStringCreateWithCharacters
(0, reinterpret_cast<const UniChar *> (aString.unicode()), aString.length())) autorelease];
}
static QString qt_mac_NSStringToQString(const NSString *nsstr)
{
NSRange range;
range.location = 0;
range.length = [nsstr length];
QString result(range.length, QChar(0));
unichar *chars = new unichar[range.length];
[nsstr getCharacters:chars range:range];
result = QString::fromUtf16(chars, range.length);
delete[] chars;
return result;
}
VideoWindow::VideoWindow(MainWindow *parent, const QDir &home) :
GcWindow(parent), home(home), main(parent), hasMovie(false)
{
@@ -99,13 +121,6 @@ void VideoWindow::seekPlayback(long ms)
[movie setCurrentTime:newTime];
}
static inline NSString *darwinQStringToNSString (const QString &aString)
{
return [reinterpret_cast<const NSString *> (CFStringCreateWithCharacters
(0, reinterpret_cast<const UniChar *> (aString.unicode()), aString.length())) autorelease];
}
void VideoWindow::mediaSelected(QString filename)
{
NativeQTMovieRef old = movie; // so we can invalidate once View has been reset
@@ -141,41 +156,41 @@ void VideoWindow::mediaSelected(QString filename)
if (old) [old invalidate];
}
MediaHelper::MediaHelper() { }
MediaHelper::MediaHelper()
{
// get a QTMove object to get the extensions we need
#if 0
NSArray *types = [QTMovie movieFileTypes:QTIncludeCommonTypes];
for (unsigned int i=0; i<[types count]; ++i) {
QString type = qt_mac_NSStringToQString([types objectAtIndex:i]);
if (type.startsWith("'")) continue; // skip 'xxx ' types
// weird file format associations for QTKit (?) .. probably a few others too...
if (type == "gif") continue; // skip image formats
if (type == "pdf") continue; // skip document formats
if (type == "wav") continue; // skip document formats
if (type == "snd") continue; // skip sound ..
supported << QString(".%1").arg(type); // .xxx added
}
#endif
// too many non video formats are returned, so we just list the main
// formats we know are video and supported
supported << ".mp4";
supported << ".mov";
supported << ".avi";
supported << ".avi";
supported << ".3gp";
supported << ".3g2";
}
MediaHelper::~MediaHelper() { }
// convert an NSString to a QString
static QString qt_mac_NSStringToQString(const NSString *nsstr)
{
NSRange range;
range.location = 0;
range.length = [nsstr length];
QString result(range.length, QChar(0));
unichar *chars = new unichar[range.length];
[nsstr getCharacters:chars range:range];
result = QString::fromUtf16(chars, range.length);
delete[] chars;
return result;
}
QStringList
MediaHelper::listMedia(QDir dir)
{
QStringList supported;
QStringList returning;
// get a QTMove object to get the extensions we need
NSArray *types = [QTMovie movieFileTypes:QTIncludeCommonTypes];
for (unsigned int i=0; i<[types count]; ++i) {
QString type = qt_mac_NSStringToQString([types objectAtIndex:i]);
if (type.startsWith("'")) continue; // skip 'xxx ' types
supported << QString(".%1").arg(type); // .xxx added
}
// go through the sub directories
QDirIterator directory_walker(dir, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
@@ -198,6 +213,16 @@ MediaHelper::listMedia(QDir dir)
return returning;
}
bool
MediaHelper::isMedia(QString filename)
{
foreach(QString extension, supported) {
if (filename.endsWith(extension, Qt::CaseInsensitive))
return true;
}
return false;
}
QtMacMovieView::QtMacMovieView (QWidget *parent) : QMacCocoaViewContainer (0, parent)
{
#if QT_VERSION >= 0x040800 // see QT-BUG 22574, QMacCocoaContainer on 4.8 is "broken"

View File

@@ -192,8 +192,8 @@ TrainTool::TrainTool(MainWindow *parent, const QDir &home) : GcWindow(parent), h
intensitySlider = new QSlider(Qt::Horizontal, this);
intensitySlider->setAutoFillBackground(false);
intensitySlider->setFocusPolicy(Qt::NoFocus);
intensitySlider->setMinimum(50);
intensitySlider->setMaximum(150);
intensitySlider->setMinimum(75);
intensitySlider->setMaximum(125);
intensitySlider->setValue(100);
slideLayout->addStretch();
slideLayout->addWidget(intensitySlider);

View File

@@ -193,6 +193,25 @@ void VideoWindow::mediaSelected(QString filename)
MediaHelper::MediaHelper()
{
// construct a list of supported types
// Using the basic list from the VLC
// Wiki here: http://www.videolan.org/vlc/features.html and then looked for
// the common extensions used from here: http://www.fileinfo.com/filetypes/video
supported << ".3GP";
supported << ".ASF";
supported << ".AVI";
supported << ".DIVX";
supported << ".FLV";
supported << ".M4V";
supported << ".MKV";
supported << ".MOV";
supported << ".MP4";
supported << ".MPEG";
supported << ".MPG";
supported << ".MXF";
supported << ".VOB";
supported << ".WMV";
}
MediaHelper::~MediaHelper()
@@ -202,35 +221,8 @@ MediaHelper::~MediaHelper()
QStringList
MediaHelper::listMedia(QDir dir)
{
QStringList supported;
QStringList returning;
// construct a list of supported types
// Using the basic list from the VLC
// Wiki here: http://www.videolan.org/vlc/features.html and then looked for
// the common extensions used from here: http://www.fileinfo.com/filetypes/video
supported << ".3GP";
supported << ".ASF";
supported << ".AVI";
supported << ".DIVX";
supported << ".FLAC";
supported << ".FLV";
supported << ".M4V";
supported << ".MKV";
supported << ".MOV";
supported << ".MP4";
supported << ".MPEG";
supported << ".MPG";
supported << ".MXF";
supported << ".Nut";
supported << ".OGG";
supported << ".OGM";
supported << ".RM";
supported << ".VOB";
supported << ".WAV";
supported << ".WMA";
supported << ".WMV";
// go through the sub directories
QDirIterator directory_walker(dir, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
@@ -252,3 +244,13 @@ MediaHelper::listMedia(QDir dir)
}
return returning;
}
bool
MediaHelper::isMedia(QString name)
{
foreach (QString extension, supported) {
if (name.endsWith(extension, Qt::CaseInsensitive))
return true;
}
return false;
}

View File

@@ -53,9 +53,10 @@ class MediaHelper
// get a list of supported media
// found in the supplied directory
QStringList listMedia(QDir directory);
bool isMedia(QString filename);
private:
QStringList supported;
libvlc_instance_t * inst;
};

View File

@@ -288,6 +288,8 @@ HEADERS += \
IntervalTreeView.h \
JouleDevice.h \
JsonRideFile.h \
Library.h \
LibraryParser.h \
LogTimeScaleDraw.h \
LogTimeScaleEngine.h \
LTMCanvasPicker.h \
@@ -480,6 +482,8 @@ SOURCES += \
IntervalTreeView.cpp \
JouleDevice.cpp \
LeftRightBalance.cpp \
Library.cpp \
LibraryParser.cpp \
LogTimeScaleDraw.cpp \
LogTimeScaleEngine.cpp \
LTMCanvasPicker.cpp \