32 files changed, 3723 insertions, 111 deletions
diff --git a/apps/Applications/camera2.desktop b/apps/Applications/camera2.desktop new file mode 100644 index 0000000..4662080 --- a/dev/null +++ b/apps/Applications/camera2.desktop @@ -0,0 +1,26 @@ +[Desktop Entry] +Exec=camera2 +File=camera2 +Icon=camera2/Camera +Type=Application +Name=OpieCam2 +Comment=A Camera Program +Name[de]=Kamera2 +Comment[de]=Ein Kamera-Programm +Name[fr]=Photo2 +Comment[fr]=Gestionnaire de photos et images +Name[it]=Telecamera2 +Comment[it]=Programma per telecamera +Name[pt]=Câmera2 +Comment[pt]=Uma aplicação de câmera +Name[pt_BR]=Câmera2 +Comment[pt_BR]=Uma aplicação de câmera +Name[sl]=OpieKamera2 +Comment[sl]=Program za kamero +Naam[nl]=Camera2 +Comment[nl]=Een camerabesturingsprogramma +Name[ru]=Камера2 +Comment[ru]=Программа для управления (фото)камерой +Name[lv]=OpieCam2 +Comment[lv]=Opie Kameras Programma + diff --git a/library/backend/categories.h b/library/backend/categories.h index 91c93e7..6be3bc0 100644 --- a/library/backend/categories.h +++ b/library/backend/categories.h @@ -1,81 +1,82 @@ /********************************************************************** ** Copyright (C) 2000 Trolltech AS. All rights reserved. ** ** This file is part of Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included ** in the packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING ** THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A ** PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #ifndef QTPALMTOP_CATEGORIES_H #define QTPALMTOP_CATEGORIES_H #include <qstring.h> #include <qstringlist.h> #include <qmap.h> #include <qlistview.h> #include <qarray.h> #include "qpcglobal.h" #include "palmtopuidgen.h" class CategoryGroup; +QString categoryFileName(); #if defined(QPC_TEMPLATEDLL) // MOC_SKIP_BEGIN template class QPC_EXPORT QMap<int, QString>; template class QPC_EXPORT QMap<QString, int>; template class QPC_EXPORT QMap< QString, CategoryGroup >; // MOC_SKIP_END #endif class QPC_EXPORT CategoryGroup { friend class Categories; public: CategoryGroup(): mIdLabelMap(), mLabelIdMap() { } CategoryGroup( const CategoryGroup &c ) : mIdLabelMap( c.mIdLabelMap), mLabelIdMap( c.mLabelIdMap ) { } void clear() { mIdLabelMap.clear(); mLabelIdMap.clear(); } int add( const QString &label ); bool add( int uid, const QString &label ); bool remove( const QString &label ); bool remove( int uid ); bool rename( int uid, const QString &newLabel ); bool rename( const QString &oldLabel, const QString &newLabel ); bool contains(int id) const; bool contains(const QString &label) const; /** Returns label associated with the uid or QString::null if * not found */ const QString &label(int id) const; /** Returns the uid associated with label or 0 if not found */ int id(const QString &label) const; /** Returns a sorted list of labels */ QStringList labels() const; QStringList labels( const QArray<int> &catids ) const; const QMap<int, QString> &idMap() const { return mIdLabelMap; } private: void insert( int uid, const QString &label ); QMap<int, QString> mIdLabelMap; diff --git a/library/global.cpp b/library/global.cpp index ec87555..f7a0767 100644 --- a/library/global.cpp +++ b/library/global.cpp @@ -763,50 +763,99 @@ void Global::findDocuments(DocLnkSet* folder, const QString &mimefilter) } for (unsigned c = 0; c < subDirs.count();++c) { DocLnkSet ide( path+"/"+subDirs[c], mimefilter ); folder->appendFrom(ide); } } } else if ( (*it)->disk() == "/dev/mtdblock6" || (*it)->disk() == "tmpfs" ) { QString path = (*it)->path() + "/Documents"; DocLnkSet ide( path, mimefilter ); folder->appendFrom(ide); } } } QStringList Global::languageList() { QString lang = getenv("LANG"); QStringList langs; langs.append(lang); int i = lang.find("."); if ( i > 0 ) lang = lang.left( i ); i = lang.find( "_" ); if ( i > 0 ) langs.append(lang.left(i)); return langs; } QStringList Global::helpPath() { QString qpeDir = QPEApplication::qpeDir(); QStringList path; QStringList langs = Global::languageList(); for (QStringList::ConstIterator it = langs.fromLast(); it!=langs.end(); --it) { QString lang = *it; if ( !lang.isEmpty() ) path += qpeDir + "/help/" + lang + "/html"; } path += qpeDir + "/pics"; path += qpeDir + "/help/html"; /* we even put english into the en dir so try it as fallback as well for opie */ path += qpeDir + "/help/en/html"; path += qpeDir + "/docs"; return path; } +/*! + \internal + Truncate file to size specified + \a f must be an open file + \a size must be a positive value + */ +bool Global::truncateFile(QFile &f, int size){ + if (!f.isOpen()) + return FALSE; + + return ::ftruncate(f.handle(), size) != -1; +} + + + + +// #if defined(Q_OS_UNIX) && defined(Q_WS_QWS) +// extern int qws_display_id; +// #endif + +/*! + /internal + Returns the default system path for storing temporary files. + Note: This does not it ensure that the provided directory exists +*/ +QString Global::tempDir() +{ + QString result; +#ifdef Q_OS_UNIX +#ifdef Q_WS_QWS + result = QString("/tmp/qtopia-%1/").arg(QString::number(qws_display_id)); +#else + result="/tmp/"; +#endif +#else + if (getenv("TEMP")) + result = getenv("TEMP"); + else + result = getenv("TMP"); + + if (result[(int)result.length() - 1] != QDir::separator()) + result.append(QDir::separator()); +#endif + + return result; +} + +//#endif + #include "global.moc" diff --git a/library/global.h b/library/global.h index 1136b12..f32c498 100644 --- a/library/global.h +++ b/library/global.h @@ -1,90 +1,94 @@ /********************************************************************** ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** ** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #ifndef GLOBAL_H #define GLOBAL_H #include <qstringlist.h> #include <qguardedptr.h> class QDawg; class QLabel; class QWidget; class AppLnk; class DocLnkSet; - +class QFile; class Global { public: Global(); // Dictionaries static const QDawg& fixedDawg(); static const QDawg& addedDawg(); static const QDawg& dawg(const QString& name); static void addWords(const QStringList& word); static void addWords(const QString& dictname, const QStringList& word); // static void removeWords(const QStringList& word); -- if someone wants it static void createDocDir(); static void findDocuments(DocLnkSet* folder, const QString &mimefilter=QString::null); static QString applicationFileName(const QString& appname, const QString& filename); struct Command { const char *file; QWidget *(*func)( bool ); bool maximized; bool documentary; }; static void setBuiltinCommands( Command* ); static void execute( const QString &exec, const QString &document=QString::null ); static void setDocument( QWidget* receiver, const QString& document ); static bool terminateBuiltin( const QString& ); static void terminate( const AppLnk* ); static bool isBuiltinCommand( const QString &name ); // system messaging static void applyStyle(); static void statusMessage(const QString&); static QWidget *shutdown( bool = FALSE ); static QWidget *restart( bool = FALSE ); static void hideInputMethod(); static void showInputMethod(); static void writeHWClock(); static QString shellQuote(const QString& s); static QString stringQuote(const QString& s); #ifdef QTOPIA_INTERNAL_LANGLIST static QStringList languageList(); static QStringList helpPath(); #endif +//#ifdef QTOPIA_INTERNAL_FILEOPERATIONS + static bool truncateFile(QFile &f, int size); + static QString tempDir( ); +//#endif private: static void invoke( const QString &exec); static Command* builtin; static QGuardedPtr<QWidget> *running; }; #endif diff --git a/library/library.pro b/library/library.pro index 7143454..4142529 100644 --- a/library/library.pro +++ b/library/library.pro @@ -14,128 +14,130 @@ HEADERS = calendar.h \ qdawg.h \ datebookmonth.h \ fileselector.h \ fileselector_p.h \ imageedit.h \ qcopenvelope_qws.h \ qpedecoration_qws.h \ qpeapplication.h \ qpestyle.h \ qpedialog.h \ lightstyle.h \ config.h \ applnk.h \ sound.h \ tzselect.h \ qmath.h \ datebookdb.h \ alarmserver.h \ process.h \ password.h \ timestring.h \ fontfactoryinterface.h \ fontdatabase.h \ power.h \ storage.h \ qpemessagebox.h \ timeconversion.h \ qpedebug.h \ qpemenubar.h \ qpetoolbar.h \ backend/categories.h \ stringutil.h \ backend/palmtoprecord.h \ backend/task.h \ backend/event.h \ backend/contact.h\ categorymenu.h \ categoryedit_p.h \ categoryselect.h \ categorywidget.h \ ir.h \ backend/vobject_p.h \ findwidget_p.h \ finddialog.h \ lnkproperties.h \ windowdecorationinterface.h \ textcodecinterface.h \ imagecodecinterface.h \ + locationcombo.h \ qpeglobal.h SOURCES = calendar.cpp \ global.cpp \ xmlreader.cpp \ mimetype.cpp \ menubutton.cpp \ network.cpp \ networkinterface.cpp \ filemanager.cpp \ fontmanager.cpp \ qdawg.cpp \ datebookmonth.cpp \ fileselector.cpp \ imageedit.cpp \ resource.cpp \ qpedecoration_qws.cpp \ qcopenvelope_qws.cpp \ qpeapplication.cpp \ qpestyle.cpp \ qpedialog.cpp \ lightstyle.cpp \ config.cpp \ applnk.cpp \ sound.cpp \ tzselect.cpp \ qmath.c \ datebookdb.cpp \ alarmserver.cpp \ password.cpp \ process.cpp \ process_unix.cpp \ timestring.cpp \ fontdatabase.cpp \ power.cpp \ storage.cpp \ qpemessagebox.cpp \ backend/timeconversion.cpp \ qpedebug.cpp \ qpemenubar.cpp \ qpetoolbar.cpp \ backend/categories.cpp \ backend/stringutil.cpp \ backend/palmtoprecord.cpp \ backend/task.cpp \ backend/event.cpp \ backend/contact.cpp \ categorymenu.cpp \ categoryedit_p.cpp \ categoryselect.cpp \ categorywidget.cpp \ ir.cpp \ backend/vcc_yacc.cpp \ backend/vobject.cpp \ findwidget_p.cpp \ finddialog.cpp \ lnkproperties.cpp \ + locationcombo.cpp \ widget_showing.cpp # Qt 3 compatibility HEADERS += quuid.h qcom.h qlibrary.h qlibrary_p.h SOURCES += quuid.cpp qlibrary.cpp qlibrary_unix.cpp DEFINES += OPIE_INTERNAL_LIBRARY_BUILD INCLUDEPATH += $(OPIEDIR)/include backend LIBS += -ldl -lcrypt -lm INTERFACES = passwordbase_p.ui categoryeditbase_p.ui findwidgetbase_p.ui lnkpropertiesbase_p.ui TARGET = qpe DESTDIR = $(OPIEDIR)/lib$(PROJMAK) VERSION = 1.5.0.1 include( $(OPIEDIR)/include.pro ) contains( CONFIG, LIBQPE_WITHROHFEEDBACK ){ DEFINES += OPIE_WITHROHFEEDBACK SOURCES += backend/rohfeedback.cpp HEADERS += backend/rohfeedback.h } diff --git a/library/locationcombo.cpp b/library/locationcombo.cpp new file mode 100644 index 0000000..31429f5 --- a/dev/null +++ b/library/locationcombo.cpp @@ -0,0 +1,295 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "locationcombo.h" + +#include <qpe/ir.h> +#include <qpe/applnk.h> +#include <qpe/global.h> +#include <qpe/categorywidget.h> +#include <qpe/categoryselect.h> +#ifdef QWS +#include <qpe/qcopenvelope_qws.h> +#endif +#include <qpe/filemanager.h> +#include <qpe/config.h> +#include <qpe/storage.h> +#include <qpe/global.h> +#include <qtopia/qpemessagebox.h> + +#include <qlineedit.h> +#include <qtoolbutton.h> +#include <qpushbutton.h> +#include <qgroupbox.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qfile.h> +#include <qdir.h> +#include <qfileinfo.h> +#include <qmessagebox.h> +#include <qsize.h> +#include <qcombobox.h> +#include <qregexp.h> + +#include <qradiobutton.h> +#include <qlayout.h> + +#include <stdlib.h> + +/*! + \class LocationCombo locationcombo.h + \brief The LocationCombo class displays a list of available storage + locations. + + First availability: Qtopia 1.6 + + \ingroup qtopiaemb + \sa DocPropertiesDialog + */ + + +class LocationComboPrivate +{ +public: + LocationComboPrivate() : homeLocation(-1), fileSize(0), listEmpty(TRUE) {} + QString originalPath; + int homeLocation; + int fileSize; + bool listEmpty; +}; + +/*! + Constructs a LocationCombo with parent \a parent and name \a name. + */ +LocationCombo::LocationCombo( QWidget *parent, const char *name ) + : QComboBox( FALSE, parent, name ) +{ + storage = new StorageInfo; + d = new LocationComboPrivate; + setLocation( 0 ); + connect( this, SIGNAL(activated(int)), this, SIGNAL(newPath()) ); + connect( storage, SIGNAL(disksChanged()), this, SLOT(updatePaths()) ); +} + +/*! + Constructs a LocationCombo with parent \a parent and name \a name. + \a lnk is pointer to an existing AppLnk. + */ +LocationCombo::LocationCombo( const AppLnk * lnk, QWidget *parent, const char *name ) + : QComboBox( FALSE, parent, name ) +{ + storage = new StorageInfo; + d = new LocationComboPrivate; + setLocation(lnk); + connect( this, SIGNAL(activated(int)), this, SIGNAL(newPath()) ); + connect( storage, SIGNAL(disksChanged()), this, SLOT(updatePaths()) ); +} + +/*! + Destroys the widget. + */ +LocationCombo::~LocationCombo() +{ + delete storage; + delete d; +} + +/*! + Sets the display of the LocationCombo to the location associated with the + AppLnk \a lnk. + */ +void LocationCombo::setLocation( const AppLnk * lnk ) +{ + // NB: setLocation(const QString) assumes only lnk->file() is used. + + if ( lnk ) { + QFileInfo fi( lnk->file() ); + d->fileSize = fi.size(); + const FileSystem *fs = storage->fileSystemOf( lnk->file() ); + d->originalPath = fs ? fs->path() : QString::null; + } else { + d->fileSize = 0; + d->originalPath = QString::null; + } + + setupCombo(); + + int currentLocation = -1; + if ( lnk ) { + int n = locations.count(); + for ( int i = 0; i < n; i++ ) { + if ( lnk->file().contains( locations[i] ) ) + currentLocation = i; + } + } + if ( currentLocation == -1 ) + currentLocation = 0; //default to the first one + + setCurrentItem( currentLocation ); +} + +/*! + \internal +*/ +void LocationCombo::setupCombo() +{ + clear(); + locations.clear(); + + const QList<FileSystem> &fs = storage->fileSystems(); + QListIterator<FileSystem> it ( fs ); + QString s; + QString homeDir = QDir::homeDirPath(); + QString homeFs; + QString homeFsPath; + int index = 0; + for ( ; it.current(); ++it ) { + // we add 10k to the file size so we are sure we can also save the desktop file + if ( !d->fileSize || (*it)->path() == d->originalPath || + (ulong)(*it)->availBlocks() * (ulong)(*it)->blockSize() + > (ulong)d->fileSize + 10000 ) + { + if ( (*it)->isRemovable() ) { + insertItem( (*it)->name(), index ); + locations.append( (*it)->path() ); + index++; + } else if ( homeDir.contains( (*it)->path() ) && + (*it)->path().length() > homeFsPath.length() ) { + homeFs = (*it)->name(); + homeFsPath = (*it)->path(); + } + } + } + + // $HOME is *somewhere*, but not shown in Storage::fileSystems(), + // eg. because it's mounted in some unexpected way. + if ( homeFsPath.isEmpty() ) { + homeFs = StorageInfo::tr("Internal Storage"); + homeFsPath = homeDir; + } + + if ( !homeFsPath.isEmpty() ) { + d->homeLocation = 0; + insertItem( homeFs, d->homeLocation ); + locations.prepend( homeDir ); + } else { + d->homeLocation = -1; + } + + d->listEmpty = locations.count() == 0; + if ( d->listEmpty ) { + insertItem( tr("No FileSystems Available!"), 0 ); + locations.append( "" ); + } +} + +/*! + \internal + */ +void LocationCombo::updatePaths() +{ + QString oldPath = locations[currentItem()]; + + setupCombo(); + + int currentLocation = 0; + int n = locations.count(); + for ( int i = 0; i < n; i++ ) { + if ( oldPath == locations[i] ) { + currentLocation = i; + } + } + setCurrentItem( currentLocation ); + if ( locations[currentItem()] != oldPath ) + emit newPath(); +} + +/*! + Returns TRUE to indicate that the user has changed the location displayed + by the LocationCombo. Most useful when the LocationCombo is part of a + dialog; when the dialog is accept()ed, LocationCombo::isChanged() can be + examined to check for a change of location. + */ +bool LocationCombo::isChanged() const +{ + if ( const FileSystem *fs = storage->fileSystemOf(locations[currentItem()]) ) + return fs->path() != d->originalPath; + + return TRUE; +} + +/*! + Returns the default (home) location for the file associated with this + LocationCombo. + */ +QString LocationCombo::installationPath() const +{ + return currentItem() == d->homeLocation ? + QString("/") : locations[ currentItem() ]+"/"; +} + +/*! + Returns the document path associated with this LocationCombo. This + will be "\<path\>/Documents". + */ +QString LocationCombo::documentPath() const +{ + return locations[ currentItem() ]+"/Documents/"; +} + +/*! + Returns a pointer to FileSystem object, associated with the current + selection of the LocationCombo. + */ +const FileSystem *LocationCombo::fileSystem() const +{ + if ( d->listEmpty ) + return 0; + return storage->fileSystemOf( locations[ currentItem() ] ); +} + +/*! + \fn LocationCombo::newPath() + Emitted when the LocationCombo changes to a new location. + */ + + +#if 0 +void LocationCombo::apply() +{ +} +#endif + diff --git a/library/locationcombo.h b/library/locationcombo.h new file mode 100644 index 0000000..fab3dfc --- a/dev/null +++ b/library/locationcombo.h @@ -0,0 +1,88 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef LOCATIONCOMBO_H +#define LOCATIONCOMBO_H + +#include <qpe/qpeglobal.h> + +#ifdef Q_WS_QWS + +#include <qstringlist.h> +#include <qcombobox.h> + +class AppLnk; +class QListViewItem; +class DocLnk; +class FileSystem; +class StorageInfo; + + +class LocationComboPrivate; + +class LocationCombo : public QComboBox +{ + Q_OBJECT +public: + LocationCombo( QWidget *parent, const char *name=0 ); + LocationCombo( const AppLnk * lnk, QWidget *parent, const char *name=0 ); + + ~LocationCombo(); + + void setLocation( const QString& path ); // qtopia 2 + void setLocation( const AppLnk * ); + + QString installationPath() const; + QString documentPath() const; + const FileSystem *fileSystem() const; + + bool isChanged() const; + +signals: + void newPath(); + +private slots: + void updatePaths(); + +private: + void setupCombo(); + QStringList locations; + StorageInfo *storage; + LocationComboPrivate *d; +}; + + +#endif // QWS +#endif // LNKPROPERTIES_H diff --git a/library/qlibrary_unix.cpp b/library/qlibrary_unix.cpp index fee73c2..f4d60cb 100644 --- a/library/qlibrary_unix.cpp +++ b/library/qlibrary_unix.cpp @@ -153,91 +153,91 @@ bool QLibraryPrivate::freeLibrary() DyldLibDesc* desc = (DyldLibDesc*) pHnd; NSModule mod = desc->mod; NSObjectFileImage img = desc->img; bool success = NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE); if ( success ) { NSDestroyObjectFileImage(img); delete desc; pHnd = 0; } #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) else { qWarning( "Error in NSUnLinkModule()" ); } #endif return pHnd == 0; } void* QLibraryPrivate::resolveSymbol( const char* symbol ) { //qDebug("QLibraryPrivate::resolveSymbol\n"); //return FALSE; if ( !pHnd ) return 0; DyldLibDesc* desc = (DyldLibDesc*) pHnd; NSSymbol sym = NSLookupSymbolInModule(desc->mod, symbol); void* address = 0; if (sym != 0) { address = NSAddressOfSymbol(sym); } #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) if ( address == 0 ) qWarning( "Cannot find symbol: %s", symbol ); #endif return address; } #else // Something else, assuming POSIX #include <dlfcn.h> bool QLibraryPrivate::loadLibrary() { if ( pHnd ) return TRUE; QString filename = library->library(); - pHnd = dlopen( filename.latin1() , RTLD_LAZY ); + pHnd = ::dlopen( filename.latin1() , RTLD_LAZY ); // #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) if ( !pHnd ) qWarning( "%s", dlerror() ); // #endif return pHnd != 0; } bool QLibraryPrivate::freeLibrary() { if ( !pHnd ) return TRUE; - int ec = dlclose( pHnd ); + int ec = ::dlclose( pHnd ); if ( !ec ) pHnd = 0; #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) else { const char* error = dlerror(); if ( error ) qWarning( "%s", error ); } #endif return pHnd == 0; } void* QLibraryPrivate::resolveSymbol( const char* f ) { if ( !pHnd ) return 0; void* address = dlsym( pHnd, f ); #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) const char* error = dlerror(); if ( error ) qWarning( "%s", error ); #endif return address; } #endif // POSIX #endif // QT_NO_COMPONENT diff --git a/library/timestring.cpp b/library/timestring.cpp index 91c29ae..afd162d 100644 --- a/library/timestring.cpp +++ b/library/timestring.cpp @@ -1,365 +1,466 @@ /********************************************************************** -** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. ** ** This file is part of the Qtopia Environment. ** -** This file may be distributed and/or modified under the terms of the -** GNU General Public License version 2 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. +** 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 file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #include "timestring.h" #include <qobject.h> -#include <qpe/qpeapplication.h> //for qApp +#include <qdatetime.h> +#include <qapplication.h> #include "config.h" +#include <time.h> + -class TimeStringFormatKeeper : public QObject +class TimeStringFormat : public QObject { Q_OBJECT public: static DateFormat currentFormat() { if ( !self ) - self = new TimeStringFormatKeeper; + self = new TimeStringFormat; return self->format; } private slots: void formatChanged( DateFormat f ) { format = f; } private: - static TimeStringFormatKeeper *self; + static TimeStringFormat *self; DateFormat format; - TimeStringFormatKeeper() + TimeStringFormat() : QObject( qApp ) { Config config("qpe"); config.setGroup( "Date" ); - format = DateFormat(QChar(config.readEntry("Separator", "/")[0]), - (DateFormat::Order)config .readNumEntry("ShortOrder", DateFormat::DayMonthYear), - (DateFormat::Order)config.readNumEntry("LongOrder", DateFormat::DayMonthYear)); + format = ::DateFormat(QChar(config.readEntry("Separator", "/")[0]), + (::DateFormat::Order)config.readNumEntry("ShortOrder", ::DateFormat::DayMonthYear), + (::DateFormat::Order)config.readNumEntry("LongOrder", ::DateFormat::DayMonthYear)); connect( qApp, SIGNAL( dateFormatChanged(DateFormat) ), this, SLOT( formatChanged(DateFormat) ) ); } }; -TimeStringFormatKeeper *TimeStringFormatKeeper::self = 0; +TimeStringFormat *TimeStringFormat::self = 0; QString DateFormat::toNumberString() const { QString buf = ""; // for each part of the order for (int i = 0; i < 3; i++) { // switch on the relavent 3 bits. switch((_shortOrder >> (i * 3)) & 0x0007) { case 0x0001: - buf += QObject::tr( "D" , "Shortcut for Day"); + buf += TimeStringFormat::tr( "D", "first letter of the word 'Day'" ); break; case 0x0002: - buf += QObject::tr( "M", "Shortcur for Month" ); + buf += TimeStringFormat::tr( "M" , "first letter of the word 'Month'" ); break; case 0x0004: - buf += QObject::tr( "Y" ); + buf += TimeStringFormat::tr( "Y" , "first letter of the word 'Year'" ); break; } if (i < 2) buf += _shortSeparator; } return buf; } QString DateFormat::toWordString() const { QString buf = ""; // for each part of the order for (int i = 0; i < 3; i++) { // switch on the relavent 3 bits. switch((_longOrder >> (i * 3)) & 0x0007) { case 0x0001: - buf += QObject::tr( "day" ); + buf += TimeStringFormat::tr( "day", "in month" ); if (i < 2) { if ((_shortOrder << ((i+1) * 3)) & 0x0007) buf += ", "; else buf += " "; } break; case 0x0002: - buf += QObject::tr( "month" ); + buf += TimeStringFormat::tr( "month" ); if (i < 2) buf += " "; break; case 0x0004: - buf += QObject::tr( "year" ); + buf += TimeStringFormat::tr( "year" ); if (i < 2) buf += ", "; break; } } return buf; } QString DateFormat::numberDate(const QDate &d, int v) const { QString buf = ""; int pad = 2; // for each part of the order for (int i = 0; i < 3; i++) { // switch on the relavent 3 bits. switch((_shortOrder >> (i * 3)) & 0x0007) { case 0x0001: if (pad==2) buf += QString().sprintf("%02d",d.day()); else buf += QString().sprintf("%d",d.day()); break; case 0x0002: if (i==0) { // no padding with only MM/DD/YY format pad=0; } if (pad==2) buf += QString().sprintf("%02d",d.month()); else buf += QString().sprintf("%d",d.month()); break; case 0x0004: { int year = d.year(); if (!(v & longNumber)) year = year % 100; buf += QString().sprintf("%02d",year); } break; } if (i < 2) buf += _shortSeparator; } return buf; } +static const char* unTranslatedFullMonthNames[] = { + QT_TRANSLATE_NOOP( "QDate", "January" ), + QT_TRANSLATE_NOOP( "QDate", "February" ), + QT_TRANSLATE_NOOP( "QDate", "March" ), + QT_TRANSLATE_NOOP( "QDate", "April" ), + QT_TRANSLATE_NOOP( "QDate", "May" ), + QT_TRANSLATE_NOOP( "QDate", "June" ), + QT_TRANSLATE_NOOP( "QDate", "July" ), + QT_TRANSLATE_NOOP( "QDate", "August" ), + QT_TRANSLATE_NOOP( "QDate", "September" ), + QT_TRANSLATE_NOOP( "QDate", "October" ), + QT_TRANSLATE_NOOP( "QDate", "November" ), + QT_TRANSLATE_NOOP( "QDate", "December" ) +}; + +static const char* unTranslatedFullDayNames[] = { + QT_TRANSLATE_NOOP( "QDate", "Monday" ), + QT_TRANSLATE_NOOP( "QDate", "Tuesday" ), + QT_TRANSLATE_NOOP( "QDate", "Wednesday" ), + QT_TRANSLATE_NOOP( "QDate", "Thursday" ), + QT_TRANSLATE_NOOP( "QDate", "Friday" ), + QT_TRANSLATE_NOOP( "QDate", "Saturday" ), + QT_TRANSLATE_NOOP( "QDate", "Sunday" ) +}; + +#ifdef QTOPIA_DESKTOP +//translations in qt.qm +static const char* unTranslatedMediumDayNames[] = { + "Mon" , "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" +}; + +static const char* unTranslatedMediumMonthNames[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +#endif + +static QString dayname(const QDate& d, bool lng) +{ + if (lng && qApp) + return qApp->translate("QDate", unTranslatedFullDayNames[d.dayOfWeek()-1]); + else { +#ifdef QTOPIA_DESKTOP + if (qApp) + return qApp->translate("QDate", unTranslatedMediumDayNames[ d.dayOfWeek()-1]); +#endif + return d.dayName(d.dayOfWeek()); + } +} + QString DateFormat::wordDate(const QDate &d, int v) const { - QString buf = ""; // for each part of the order - if (v & showWeekDay) { - QString weekDay = d.dayName(d.dayOfWeek()); - if (!(v & longWord)) { - weekDay = weekDay.left(3); - } - buf += weekDay; - if ((_longOrder & 0x0007) == 0x0002) - buf += ' '; - else - buf += ", "; - } + QString weekDay; + if (v & showWeekDay) + weekDay = ::dayname(d,(v & longWord)); + QString date=""; + QString sep=""; for (int i = 0; i < 3; i++) { // switch on the relavent 3 bits. - switch((_longOrder >> (i * 3)) & 0x0007) { - case 0x0001: - if (i==1) { - buf += QString().sprintf("%02d, ",d.day()); - } else { - buf += QString().sprintf("%2d",d.day()); - if (separator()=='.') // 2002/1/11 - buf += ". "; - else - buf += " "; - } + int field = (_longOrder >> (i * 3)) & 0x0007; + if ( field && !date.isEmpty() ) + date += sep; + switch (field) { + case 0x0001: // Day + { + QString daysuffix = TimeStringFormat::tr("@day", "day suffix - applies to some asian languages (e.g. Japanese and Trad. Chinese). If it doesn't apply to your language it has to be translated to an '@day' " ); + if (i==1) { + date += QString().sprintf("%02d",d.day()); + if (daysuffix != "@day") + date+=daysuffix; + sep = TimeStringFormat::tr(",","day-date separator") + " "; + } else { + date += QString().sprintf("%2d",d.day()); + if (daysuffix == "@day") { + if (separator()=='.') // 2002/1/11 + sep = ". "; + else + sep = " "; + } else { + date += daysuffix+" "; + sep = " "; + } + } + } break; - case 0x0002: + case 0x0002: // Month { - QString monthName = d.monthName(d.month()); - if (!(v & longWord)) { - monthName = monthName.left(3); - } - buf += monthName; + QString monthName; + + if (v & longWord) + monthName = qApp->translate("QDate", unTranslatedFullMonthNames[d.month()-1] ); + else { +#ifdef QTOPIA_DESKTOP + monthName = qApp->translate("QDate", unTranslatedMediumMonthNames[d.month()-1] ); +#else + monthName = d.monthName( d.month() ); +#endif + } + date += monthName; } - if (i < 2) - buf += " "; + sep = " ";//TimeStringFormat::tr(" ","month-date separator"); break; - case 0x0004: + case 0x0004: // Year { int year = d.year(); if (!(v & longNumber)) year = year % 100; if (year < 10) - buf += "0"; + date += "0"; + + date += QString::number(year); + QString yearsuffix = TimeStringFormat::tr("@year", "year suffix - applies to some asian languages (e.g. Japanese and Trad. Chinese). If it doesn't apply to your language it has to be translated to an '@year' " ); + if (yearsuffix != "@year") + date += yearsuffix; - buf += QString::number(year); } - if (i < 2) - buf += ", "; + sep = TimeStringFormat::tr(",","year-date seperator") + " "; break; } } - return buf; + + QString r = ""; + if ( weekDay.isEmpty() ) + r = date; + else if ((_longOrder & 0x0007) == 0x0002) + r = TimeStringFormat::tr("%1 %2","1=Monday 2=January 12").arg(weekDay).arg(date); + else if ( _longOrder ) + r = TimeStringFormat::tr("%1, %2","1=Monday 2=12 January").arg(weekDay).arg(date); + else + r = weekDay; + return r; } #ifndef QT_NO_DATASTREAM void DateFormat::save(QDataStream &d) const { d << _shortSeparator.unicode(); uint v= _shortOrder; d << v; v = _longOrder; d << v; } void DateFormat::load(QDataStream &d) { ushort value; d >> value; _shortSeparator = QChar(value); uint v = 0; d >> v; _shortOrder = (Order)v; v = 0; d >> v; _longOrder = (Order)v; } QDataStream &operator<<(QDataStream &s, const DateFormat&df) { df.save(s); return s; } QDataStream &operator>>(QDataStream &s, DateFormat&df) { df.load(s); return s; } #endif QString TimeString::shortDate( const QDate &d, DateFormat dtf ) { return dtf.wordDate(d); } QString TimeString::dateString( const QDate &d, DateFormat dtf ) { - return QObject::tr( dtf.wordDate(d, DateFormat::longNumber | DateFormat::longWord) ); + return dtf.wordDate(d, DateFormat::longNumber); } QString TimeString::longDateString( const QDate &d, DateFormat dtf ) { - return QObject::tr( dtf.wordDate(d, DateFormat::showWeekDay | DateFormat::longNumber - | DateFormat::longWord) ); + return dtf.wordDate(d, DateFormat::showWeekDay | DateFormat::longNumber + | DateFormat::longWord); } DateFormat TimeString::currentDateFormat() { - return TimeStringFormatKeeper::currentFormat(); + return TimeStringFormat::currentFormat(); } QString TimeString::dateString( const QDateTime &dt, bool ampm, bool seconds, DateFormat dtf ) { const QDate& d = dt.date(); const QTime& t = dt.time(); // based on QDateTime::toString() QString buf = timeString(t,ampm,seconds); buf += " "; buf += longDateString( d, dtf ); return buf; } QString TimeString::timeString( const QTime &t, bool ampm, bool seconds ) { if ( !ampm ) { if ( seconds ) return t.toString(); QString r = QString::number(t.hour()); if ( t.hour() < 10 ) r.prepend( "0" ); r.append( ":" ); if ( t.minute() < 10 ) r.append( "0" ); r.append(QString::number(t.minute())); return r; } // ### else the hard case that should disappear in Qt 3.0 QString argString = seconds ? "%4:%5:%6 %7" : "%4:%5 %7"; int hour = t.hour(); QString strMin = QString::number( t.minute() ); QString strSec = QString::number( t.second() ); if ( hour > 12 ) argString = argString.arg( hour - 12, 2 ); else { if ( hour == 0 ) argString = argString.arg( 12 ); else argString = argString.arg( hour, 2 ); } if ( t.minute() < 10 ) strMin.prepend( "0" ); if ( t.second() < 10 ) strSec.prepend( "0" ); argString = argString.arg( strMin ); if ( seconds ) argString = argString.arg( strSec ); if ( hour >= 12 ) - argString = argString.arg( QObject::tr("PM") ); + argString = argString.arg( TimeStringFormat::tr("PM") ); else - argString = argString.arg( QObject::tr("AM") ); + argString = argString.arg( TimeStringFormat::tr("AM") ); return argString; } QString TimeString::shortTime( bool ampm, bool seconds ) { - static const char* const day[] = { - QT_TRANSLATE_NOOP( "QObject", "Mon" ), - QT_TRANSLATE_NOOP( "QObject", "Tue" ), - QT_TRANSLATE_NOOP( "QObject", "Wed" ), - QT_TRANSLATE_NOOP( "QObject", "Thu" ), - QT_TRANSLATE_NOOP( "QObject", "Fri" ), - QT_TRANSLATE_NOOP( "QObject", "Sat" ), - QT_TRANSLATE_NOOP( "QObject", "Sun" ) - }; // just create a shorter time String QDateTime dtTmp = QDateTime::currentDateTime(); - QString strTime; - strTime = QObject::tr( day[dtTmp.date().dayOfWeek()-1] ) + " " + - timeString( dtTmp.time(), ampm, seconds ); + QString strTime = TimeStringFormat::tr( "%1 %2", "1=Monday 2=12:45" ) + .arg(::dayname(dtTmp.date(),FALSE)) + .arg(timeString( dtTmp.time(), ampm, seconds )); return strTime; } QString TimeString::dateString( const QDateTime &t, bool ampm ) { return dateString(t,ampm,FALSE); } QString TimeString::timeString( const QTime &t, bool ampm) { return timeString(t,ampm,FALSE); } QString TimeString::shortTime( bool ampm ) { return shortTime(ampm,FALSE); } QString TimeString::numberDateString( const QDate &d, DateFormat dtf ) { return dtf.numberDate(d); } QString TimeString::longNumberDateString( const QDate &d, DateFormat dtf ) { return dtf.numberDate(d,DateFormat::longNumber); } +/*! + Returns date/time \a dt as a string, + showing year, month, date, hours, minutes, and seconds. + \a len determines the length of the resulting string. + + The format, including order depends on the user's settings. + + First availability: Qtopia 1.6 +*/ +//QString TimeString::localYMDHMS( const QDateTime &dt, Length len ) +//{ +// const QDate& d = dt.date(); +// const QTime& t = dt.time(); +// return LocalTimeFormat::tr("%1 %2","date,time").arg(localYMD(d,len)).arg(localHMS(t)); +//} + #include "timestring.moc" diff --git a/library/timestring.h b/library/timestring.h index 875c8bf..b8d1aea 100644 --- a/library/timestring.h +++ b/library/timestring.h @@ -1,150 +1,182 @@ /********************************************************************** -** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. ** ** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. ** -** This file may be distributed and/or modified under the terms of the -** GNU General Public License version 2 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** 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. ** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #ifndef _TIMESTRING_H_ #define _TIMESTRING_H_ #include <qdatetime.h> #include <qstring.h> +#include <qarray.h> #if (QT_VERSION-0 >= 0x030000) #define DateFormat QPEDateFormat #endif +#include <qtopia/qpeglobal.h> + +class QObject; + // return a string with the time based on whether or not you want // you want it in 12 hour form. if ampm is true, then return // it in 12 hour (am/pm) form otherwise return it in 24 hour form // in theory Qt 3,0 handles this better (hopefully obsoleteing this) -class DateFormat +class DateFormat { public: - // date format type 001,010,100 = day month year + // date format type 1,2,4 = day,month,year enum Order { - DayMonthYear = 0x0111, // 0x001 + 0x010(0x2 << 3) + 0x100(0x4 << 3) - MonthDayYear = 0x010A, - YearMonthDay = 0x0054 + DayMonthYear = 0421, // right-to-left + MonthDayYear = 0412, + YearMonthDay = 0124 }; DateFormat(QChar s = '/', Order so = MonthDayYear) : _shortOrder(so), _longOrder(so), _shortSeparator(s) { } DateFormat(QChar s, Order so, Order lo) : _shortOrder(so), _longOrder(lo), _shortSeparator(s) { } DateFormat(const DateFormat &o) : _shortOrder(o._shortOrder), _longOrder(o._longOrder), _shortSeparator(o._shortSeparator) { } bool operator==(const DateFormat &o) { if (o._shortOrder == _shortOrder && o._longOrder == _longOrder && o._shortSeparator == _shortSeparator) return TRUE; return FALSE; } // verbosity specifiers enum Verbosity { shortNumber = 0x01, // default longNumber = 0x02, padNumber = 0x04, shortWord = 0x08, // default longWord = 0x10, showWeekDay = 0x20 }; QString toNumberString() const; // the M/D/Y string. QString toWordString() const; // the Month day, year string. QString numberDate(const QDate &d, int v = 0) const; QString wordDate(const QDate &d, int v = 0) const; #ifndef QT_NO_DATASTREAM void load(QDataStream&); void save(QDataStream&) const; #endif QChar separator() const { return _shortSeparator; }; Order shortOrder() const { return _shortOrder; }; Order longOrder() const { return _longOrder; }; private: Order _shortOrder; Order _longOrder; QChar _shortSeparator; }; #ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &s, const DateFormat&df); QDataStream &operator>>(QDataStream &s, DateFormat&df); #endif class TimeString { public: - //enum DateFormat { MonthDayYear, DayMonthYear, ISO8601, + //enum DateFormat { MonthDayYear, DayMonthYear, ISO8601, //YearMonthDay = ISO8601 }; -/** - * @name Convience functions which use currentDateFormat - */ -//@{ - static QString shortDate( const QDate &d ) + +//private: + static QString shortDate( const QDate &d ) { return shortDate( d, currentDateFormat() ); } static QString dateString( const QDate &d ) { return dateString( d, currentDateFormat() ); } static QString longDateString( const QDate &d ) { return longDateString( d, currentDateFormat() ); } -//@} static QString dateString( const QDateTime &dt, bool ampm, bool seconds ) { return dateString( dt, ampm, seconds, currentDateFormat() ); } +public: + enum Length { Short, Medium, Long }; + static QString localH( int hour ); + static QString localHM( const QTime & ); + static QString localHM( const QTime &, Length ); // qtopia 2.1.0 + static QString localHMS( const QTime & ); + static QString localHMDayOfWeek( const QDateTime &t ); + static QString localHMSDayOfWeek( const QDateTime &t ); + static QString localMD( const QDate &, Length=Medium ); + static QString localYMD( const QDate &, Length=Medium ); + static QString localYMDHMS( const QDateTime &, Length=Medium ); + static QString localDayOfWeek( const QDate&, Length=Medium ); + static QString localDayOfWeek( int day1to7, Length=Medium ); + + static QString hourString( int hour, bool ampm ); + static bool currentAMPM(); + static DateFormat currentDateFormat(); + static QArray<DateFormat> formatOptions(); // qtopia 1.6.0 + + static void connectChange(QObject*,const char* member); + static void disconnectChange(QObject*,const char* member); - /** @name Do not use as they don't honor system settings for AMPM - * - */ - //@{ - static QString dateString( const QDateTime &t, bool ampm = false ); + // Not recommended to call these (they don't honor system ampm) + static QString dateString( const QDateTime &t, bool ampm ); static QString timeString( const QTime &t, bool ampm, bool seconds ); - static QString timeString( const QTime &t, bool ampm = false ); + static QString timeString( const QTime &t, bool ampm ); static QString shortTime( bool ampm, bool seconds ); - static QString shortTime( bool ampm = false ); - //@} + static QString shortTime( bool ampm ); static QString numberDateString( const QDate &d, DateFormat ); static QString numberDateString( const QDate &d ) { return numberDateString( d, currentDateFormat() ); } static QString longNumberDateString( const QDate &d, DateFormat ); static QString longNumberDateString( const QDate &d ) { return longNumberDateString( d, currentDateFormat() ); } static QString shortDate( const QDate &, DateFormat ); static QString dateString( const QDate &, DateFormat ); static QString longDateString( const QDate &, DateFormat ); - static DateFormat currentDateFormat(); - private: static QString dateString( const QDateTime &t, bool ampm, bool seconds, DateFormat ); - + }; #endif diff --git a/noncore/multimedia/camera2/camera2.pro b/noncore/multimedia/camera2/camera2.pro new file mode 100644 index 0000000..b6e2826 --- a/dev/null +++ b/noncore/multimedia/camera2/camera2.pro @@ -0,0 +1,27 @@ +DESTDIR = $(OPIEDIR)/bin +TEMPLATE = app +CONFIG += qte warn_on quick_app +INTERFACES=camerabase.ui camerasettings.ui +HEADERS = mainwindow.h \ + image.h \ + thumbbutton.h \ + videocaptureview.h +SOURCES = mainwindow.cpp\ + image.cpp \ + videocaptureview.cpp \ + main.cpp + +TARGET = camera2 +DEFINES += HAVE_VIDEO4LINUX + +LIBS += -lopiecore2 -lopieui2 +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +contains(CONFIG,quick-app) { + DESTDIR = $(OPIEDIR)/bin + DEFINES += NOQUICKLAUNCH +} + + +include( $(OPIEDIR)/include.pro ) + diff --git a/noncore/multimedia/camera2/camerabase.cpp b/noncore/multimedia/camera2/camerabase.cpp new file mode 100644 index 0000000..cbb1ba9 --- a/dev/null +++ b/noncore/multimedia/camera2/camerabase.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** Form implementation generated from reading ui file 'camerabase.ui' +** +** Created: Mon Jul 10 04:21:25 2006 +** by: The User Interface Compiler (uic) +** +** WARNING! All changes made in this file will be lost! +****************************************************************************/ +#include "camerabase.h" + +#include <qframe.h> +#include <qpushbutton.h> +#include "thumbbutton.h" +#include "videocaptureview.h" +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +/* + * Constructs a CameraBase which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + */ +CameraBase::CameraBase( QWidget* parent, const char* name, WFlags fl ) + : QWidget( parent, name, fl ) +{ + if ( !name ) + setName( "camera" ); + resize( 311, 381 ); + setCaption( tr( "Camera" ) ); + cameraLayout = new QGridLayout( this ); + cameraLayout->setSpacing( 0 ); + cameraLayout->setMargin( 0 ); + + Frame3 = new QFrame( this, "Frame3" ); + Frame3->setFrameShape( QFrame::Panel ); + Frame3->setFrameShadow( QFrame::Sunken ); + Frame3->setLineWidth( 4 ); + Frame3->setMargin( 4 ); + Frame3->setMidLineWidth( 3 ); + Frame3Layout = new QVBoxLayout( Frame3 ); + Frame3Layout->setSpacing( 6 ); + Frame3Layout->setMargin( 4 ); + + videocaptureview = new VideoCaptureView( Frame3, "videocaptureview" ); + videocaptureview->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)7, videocaptureview->sizePolicy().hasHeightForWidth() ) ); + Frame3Layout->addWidget( videocaptureview ); + + cameraLayout->addMultiCellWidget( Frame3, 0, 0, 0, 1 ); + + photo = new QPushButton( this, "photo" ); + photo->setText( tr( "Photo" ) ); + + cameraLayout->addWidget( photo, 1, 0 ); + + video = new QPushButton( this, "video" ); + video->setText( tr( "Video" ) ); + + cameraLayout->addWidget( video, 1, 1 ); + + thumbs = new QFrame( this, "thumbs" ); + thumbs->setFrameShape( QFrame::NoFrame ); + thumbs->setFrameShadow( QFrame::Plain ); + thumbsLayout = new QHBoxLayout( thumbs ); + thumbsLayout->setSpacing( 0 ); + thumbsLayout->setMargin( 0 ); + + thumb1 = new ThumbButton( thumbs, "thumb1" ); + thumbsLayout->addWidget( thumb1 ); + + thumb2 = new ThumbButton( thumbs, "thumb2" ); + thumbsLayout->addWidget( thumb2 ); + + thumb3 = new ThumbButton( thumbs, "thumb3" ); + thumbsLayout->addWidget( thumb3 ); + + thumb4 = new ThumbButton( thumbs, "thumb4" ); + thumbsLayout->addWidget( thumb4 ); + + thumb5 = new ThumbButton( thumbs, "thumb5" ); + thumbsLayout->addWidget( thumb5 ); + + cameraLayout->addMultiCellWidget( thumbs, 2, 2, 0, 1 ); +} + +/* + * Destroys the object and frees any allocated resources + */ +CameraBase::~CameraBase() +{ + // no need to delete child widgets, Qt does it all for us +} + diff --git a/noncore/multimedia/camera2/camerabase.h b/noncore/multimedia/camera2/camerabase.h new file mode 100644 index 0000000..77ab4f0 --- a/dev/null +++ b/noncore/multimedia/camera2/camerabase.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** Form interface generated from reading ui file 'camerabase.ui' +** +** Created: Mon Jul 10 04:21:22 2006 +** by: The User Interface Compiler (uic) +** +** WARNING! All changes made in this file will be lost! +****************************************************************************/ +#ifndef CAMERA_H +#define CAMERA_H + +#include <qvariant.h> +#include <qwidget.h> +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; +class QFrame; +class QPushButton; +class ThumbButton; +class VideoCaptureView; + +class CameraBase : public QWidget +{ + Q_OBJECT + +public: + CameraBase( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + ~CameraBase(); + + QFrame* Frame3; + VideoCaptureView* videocaptureview; + QPushButton* photo; + QPushButton* video; + QFrame* thumbs; + ThumbButton* thumb1; + ThumbButton* thumb2; + ThumbButton* thumb3; + ThumbButton* thumb4; + ThumbButton* thumb5; + +protected: + QGridLayout* cameraLayout; + QVBoxLayout* Frame3Layout; + QHBoxLayout* thumbsLayout; +}; + +#endif // CAMERA_H diff --git a/noncore/multimedia/camera2/camerabase.ui b/noncore/multimedia/camera2/camerabase.ui new file mode 100644 index 0000000..e102f79 --- a/dev/null +++ b/noncore/multimedia/camera2/camerabase.ui @@ -0,0 +1,209 @@ +<!DOCTYPE UI><UI> +<class>CameraBase</class> +<widget> + <class>QWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>camera</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>311</width> + <height>381</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Camera</string> + </property> + <grid> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>0</number> + </property> + <widget row="0" column="0" rowspan="1" colspan="2" > + <class>QFrame</class> + <property stdset="1"> + <name>name</name> + <cstring>Frame3</cstring> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>Panel</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Sunken</enum> + </property> + <property stdset="1"> + <name>lineWidth</name> + <number>4</number> + </property> + <property stdset="1"> + <name>margin</name> + <number>4</number> + </property> + <property stdset="1"> + <name>midLineWidth</name> + <number>3</number> + </property> + <property> + <name>layoutMargin</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>4</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>VideoCaptureView</class> + <property stdset="1"> + <name>name</name> + <cstring>videocaptureview</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + </sizepolicy> + </property> + </widget> + </vbox> + </widget> + <widget row="1" column="0" > + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>photo</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Photo</string> + </property> + </widget> + <widget row="1" column="1" > + <class>QPushButton</class> + <property stdset="1"> + <name>name</name> + <cstring>video</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Video</string> + </property> + </widget> + <widget row="2" column="0" rowspan="1" colspan="2" > + <class>QFrame</class> + <property stdset="1"> + <name>name</name> + <cstring>thumbs</cstring> + </property> + <property stdset="1"> + <name>frameShape</name> + <enum>NoFrame</enum> + </property> + <property stdset="1"> + <name>frameShadow</name> + <enum>Plain</enum> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>0</number> + </property> + <widget> + <class>ThumbButton</class> + <property stdset="1"> + <name>name</name> + <cstring>thumb1</cstring> + </property> + </widget> + <widget> + <class>ThumbButton</class> + <property stdset="1"> + <name>name</name> + <cstring>thumb2</cstring> + </property> + </widget> + <widget> + <class>ThumbButton</class> + <property stdset="1"> + <name>name</name> + <cstring>thumb3</cstring> + </property> + </widget> + <widget> + <class>ThumbButton</class> + <property stdset="1"> + <name>name</name> + <cstring>thumb4</cstring> + </property> + </widget> + <widget> + <class>ThumbButton</class> + <property stdset="1"> + <name>name</name> + <cstring>thumb5</cstring> + </property> + </widget> + </hbox> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>VideoCaptureView</class> + <header location="local">videocaptureview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>7</verdata> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>ThumbButton</class> + <header location="local">thumbbutton.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + </sizepolicy> + <pixmap>image1</pixmap> + </customwidget> +</customwidgets> +<images> + <image> + <name>image0</name> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data> + </image> + <image> + <name>image1</name> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753</data> + </image> +</images> +</UI> diff --git a/noncore/multimedia/camera2/camerasettings.cpp b/noncore/multimedia/camera2/camerasettings.cpp new file mode 100644 index 0000000..d284128 --- a/dev/null +++ b/noncore/multimedia/camera2/camerasettings.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** Form implementation generated from reading ui file 'camerasettings.ui' +** +** Created: Mon Jul 10 04:21:25 2006 +** by: The User Interface Compiler (uic) +** +** WARNING! All changes made in this file will be lost! +****************************************************************************/ +#include "camerasettings.h" + +#include <qcombobox.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qslider.h> +#include <qtopia/locationcombo.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +/* + * Constructs a CameraSettings which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ +CameraSettings::CameraSettings( QWidget* parent, const char* name, bool modal, WFlags fl ) + : QDialog( parent, name, modal, fl ) +{ + if ( !name ) + setName( "CameraSettings" ); + resize( 324, 465 ); + setCaption( tr( "Settings" ) ); + CameraSettingsLayout = new QVBoxLayout( this ); + CameraSettingsLayout->setSpacing( 6 ); + CameraSettingsLayout->setMargin( 11 ); + + location = new LocationCombo( this, "location" ); + CameraSettingsLayout->addWidget( location ); + + photo = new QGroupBox( this, "photo" ); + photo->setTitle( tr( "Photo" ) ); + photo->setColumnLayout(0, Qt::Vertical ); + photo->layout()->setSpacing( 0 ); + photo->layout()->setMargin( 0 ); + photoLayout = new QVBoxLayout( photo->layout() ); + photoLayout->setAlignment( Qt::AlignTop ); + photoLayout->setSpacing( 2 ); + photoLayout->setMargin( 4 ); + + Layout1 = new QHBoxLayout; + Layout1->setSpacing( 6 ); + Layout1->setMargin( 0 ); + + TextLabel1 = new QLabel( photo, "TextLabel1" ); + TextLabel1->setText( tr( "Size" ) ); + Layout1->addWidget( TextLabel1 ); + + photo_size = new QComboBox( FALSE, photo, "photo_size" ); + photo_size->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)0, photo_size->sizePolicy().hasHeightForWidth() ) ); + Layout1->addWidget( photo_size ); + photoLayout->addLayout( Layout1 ); + + Layout2 = new QHBoxLayout; + Layout2->setSpacing( 6 ); + Layout2->setMargin( 0 ); + + TextLabel2 = new QLabel( photo, "TextLabel2" ); + TextLabel2->setText( tr( "Quality" ) ); + Layout2->addWidget( TextLabel2 ); + + photo_quality = new QSlider( photo, "photo_quality" ); + photo_quality->setMinValue( 0 ); + photo_quality->setMaxValue( 100 ); + photo_quality->setValue( 75 ); + photo_quality->setOrientation( QSlider::Horizontal ); + Layout2->addWidget( photo_quality ); + + photo_quality_n = new QLabel( photo, "photo_quality_n" ); + photo_quality_n->setText( tr( "75" ) ); + Layout2->addWidget( photo_quality_n ); + photoLayout->addLayout( Layout2 ); + CameraSettingsLayout->addWidget( photo ); + + video = new QGroupBox( this, "video" ); + video->setTitle( tr( "Video" ) ); + video->setColumnLayout(0, Qt::Vertical ); + video->layout()->setSpacing( 0 ); + video->layout()->setMargin( 0 ); + videoLayout = new QVBoxLayout( video->layout() ); + videoLayout->setAlignment( Qt::AlignTop ); + videoLayout->setSpacing( 2 ); + videoLayout->setMargin( 4 ); + + Layout1_2 = new QHBoxLayout; + Layout1_2->setSpacing( 6 ); + Layout1_2->setMargin( 0 ); + + TextLabel1_2 = new QLabel( video, "TextLabel1_2" ); + TextLabel1_2->setText( tr( "Size" ) ); + Layout1_2->addWidget( TextLabel1_2 ); + + video_size = new QComboBox( FALSE, video, "video_size" ); + video_size->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)7, (QSizePolicy::SizeType)0, video_size->sizePolicy().hasHeightForWidth() ) ); + Layout1_2->addWidget( video_size ); + videoLayout->addLayout( Layout1_2 ); + + Layout2_2 = new QHBoxLayout; + Layout2_2->setSpacing( 6 ); + Layout2_2->setMargin( 0 ); + + TextLabel2_2 = new QLabel( video, "TextLabel2_2" ); + TextLabel2_2->setText( tr( "Quality" ) ); + Layout2_2->addWidget( TextLabel2_2 ); + + video_quality = new QSlider( video, "video_quality" ); + video_quality->setMinValue( 0 ); + video_quality->setMaxValue( 100 ); + video_quality->setValue( 75 ); + video_quality->setOrientation( QSlider::Horizontal ); + Layout2_2->addWidget( video_quality ); + + video_quality_n = new QLabel( video, "video_quality_n" ); + video_quality_n->setText( tr( "75" ) ); + Layout2_2->addWidget( video_quality_n ); + videoLayout->addLayout( Layout2_2 ); + + Layout6 = new QHBoxLayout; + Layout6->setSpacing( 6 ); + Layout6->setMargin( 0 ); + + TextLabel4 = new QLabel( video, "TextLabel4" ); + TextLabel4->setText( tr( "Frame rate" ) ); + Layout6->addWidget( TextLabel4 ); + + video_framerate = new QSlider( video, "video_framerate" ); + video_framerate->setMinValue( 1 ); + video_framerate->setMaxValue( 60 ); + video_framerate->setValue( 5 ); + video_framerate->setOrientation( QSlider::Horizontal ); + Layout6->addWidget( video_framerate ); + + TextLabel6 = new QLabel( video, "TextLabel6" ); + TextLabel6->setText( tr( "5" ) ); + Layout6->addWidget( TextLabel6 ); + videoLayout->addLayout( Layout6 ); + CameraSettingsLayout->addWidget( video ); + QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding ); + CameraSettingsLayout->addItem( spacer ); + + // signals and slots connections + connect( photo_quality, SIGNAL( valueChanged(int) ), photo_quality_n, SLOT( setNum(int) ) ); + connect( video_quality, SIGNAL( valueChanged(int) ), video_quality_n, SLOT( setNum(int) ) ); + connect( video_framerate, SIGNAL( valueChanged(int) ), TextLabel6, SLOT( setNum(int) ) ); +} + +/* + * Destroys the object and frees any allocated resources + */ +CameraSettings::~CameraSettings() +{ + // no need to delete child widgets, Qt does it all for us +} + diff --git a/noncore/multimedia/camera2/camerasettings.h b/noncore/multimedia/camera2/camerasettings.h new file mode 100644 index 0000000..dcc48a0 --- a/dev/null +++ b/noncore/multimedia/camera2/camerasettings.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** Form interface generated from reading ui file 'camerasettings.ui' +** +** Created: Mon Jul 10 04:21:22 2006 +** by: The User Interface Compiler (uic) +** +** WARNING! All changes made in this file will be lost! +****************************************************************************/ +#ifndef CAMERASETTINGS_H +#define CAMERASETTINGS_H + +#include <qvariant.h> +#include <qdialog.h> +class QVBoxLayout; +class QHBoxLayout; +class QGridLayout; +class LocationCombo; +class QComboBox; +class QGroupBox; +class QLabel; +class QSlider; + +class CameraSettings : public QDialog +{ + Q_OBJECT + +public: + CameraSettings( QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 ); + ~CameraSettings(); + + LocationCombo* location; + QGroupBox* photo; + QLabel* TextLabel1; + QComboBox* photo_size; + QLabel* TextLabel2; + QSlider* photo_quality; + QLabel* photo_quality_n; + QGroupBox* video; + QLabel* TextLabel1_2; + QComboBox* video_size; + QLabel* TextLabel2_2; + QSlider* video_quality; + QLabel* video_quality_n; + QLabel* TextLabel4; + QSlider* video_framerate; + QLabel* TextLabel6; + +protected: + QVBoxLayout* CameraSettingsLayout; + QVBoxLayout* photoLayout; + QHBoxLayout* Layout1; + QHBoxLayout* Layout2; + QVBoxLayout* videoLayout; + QHBoxLayout* Layout1_2; + QHBoxLayout* Layout2_2; + QHBoxLayout* Layout6; +}; + +#endif // CAMERASETTINGS_H diff --git a/noncore/multimedia/camera2/camerasettings.ui b/noncore/multimedia/camera2/camerasettings.ui new file mode 100644 index 0000000..276694b --- a/dev/null +++ b/noncore/multimedia/camera2/camerasettings.ui @@ -0,0 +1,433 @@ +<!DOCTYPE UI><UI> +<class>CameraSettings</class> +<widget> + <class>QDialog</class> + <property stdset="1"> + <name>name</name> + <cstring>CameraSettings</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>324</width> + <height>465</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Settings</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>11</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>LocationCombo</class> + <property stdset="1"> + <name>name</name> + <cstring>location</cstring> + </property> + </widget> + <widget> + <class>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>photo</cstring> + </property> + <property stdset="1"> + <name>title</name> + <string>Photo</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>4</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>2</number> + </property> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout1</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel1</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Size</string> + </property> + </widget> + <widget> + <class>QComboBox</class> + <property stdset="1"> + <name>name</name> + <cstring>photo_size</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout2</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Quality</string> + </property> + </widget> + <widget> + <class>QSlider</class> + <property stdset="1"> + <name>name</name> + <cstring>photo_quality</cstring> + </property> + <property stdset="1"> + <name>minValue</name> + <number>0</number> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>100</number> + </property> + <property stdset="1"> + <name>value</name> + <number>75</number> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Horizontal</enum> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>photo_quality_n</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>75</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget> + <class>QGroupBox</class> + <property stdset="1"> + <name>name</name> + <cstring>video</cstring> + </property> + <property stdset="1"> + <name>title</name> + <string>Video</string> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <vbox> + <property stdset="1"> + <name>margin</name> + <number>4</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>2</number> + </property> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout1_2</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel1_2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Size</string> + </property> + </widget> + <widget> + <class>QComboBox</class> + <property stdset="1"> + <name>name</name> + <cstring>video_size</cstring> + </property> + <property stdset="1"> + <name>sizePolicy</name> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout2_2</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel2_2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Quality</string> + </property> + </widget> + <widget> + <class>QSlider</class> + <property stdset="1"> + <name>name</name> + <cstring>video_quality</cstring> + </property> + <property stdset="1"> + <name>minValue</name> + <number>0</number> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>100</number> + </property> + <property stdset="1"> + <name>value</name> + <number>75</number> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Horizontal</enum> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>video_quality_n</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>75</string> + </property> + </widget> + </hbox> + </widget> + <widget> + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout6</cstring> + </property> + <hbox> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel4</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>Frame rate</string> + </property> + </widget> + <widget> + <class>QSlider</class> + <property stdset="1"> + <name>name</name> + <cstring>video_framerate</cstring> + </property> + <property stdset="1"> + <name>minValue</name> + <number>1</number> + </property> + <property stdset="1"> + <name>maxValue</name> + <number>60</number> + </property> + <property stdset="1"> + <name>value</name> + <number>5</number> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Horizontal</enum> + </property> + </widget> + <widget> + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>TextLabel6</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string>5</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <spacer> + <property> + <name>name</name> + <cstring>Spacer1</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Vertical</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>Expanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>LocationCombo</class> + <header location="global">qtopia/locationcombo.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image> + <name>image0</name> + <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data> + </image> +</images> +<connections> + <connection> + <sender>photo_quality</sender> + <signal>valueChanged(int)</signal> + <receiver>photo_quality_n</receiver> + <slot>setNum(int)</slot> + </connection> + <connection> + <sender>video_quality</sender> + <signal>valueChanged(int)</signal> + <receiver>video_quality_n</receiver> + <slot>setNum(int)</slot> + </connection> + <connection> + <sender>video_framerate</sender> + <signal>valueChanged(int)</signal> + <receiver>TextLabel6</receiver> + <slot>setNum(int)</slot> + </connection> +</connections> +</UI> diff --git a/noncore/multimedia/camera2/config.in b/noncore/multimedia/camera2/config.in new file mode 100644 index 0000000..8838008 --- a/dev/null +++ b/noncore/multimedia/camera2/config.in @@ -0,0 +1,7 @@ + config CAMERA2 + boolean "opie-camera2 (camera app to use with Video4Linux)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE && LIBOPIE2UI + comment "opie-camera needs a libqpe, libopie2core & libopie2ui" + depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE && LIBOPIE2UI ) + diff --git a/noncore/multimedia/camera2/image.cpp b/noncore/multimedia/camera2/image.cpp new file mode 100644 index 0000000..39b6d8b --- a/dev/null +++ b/noncore/multimedia/camera2/image.cpp @@ -0,0 +1,239 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "image.h" + +#include <qfileinfo.h> +#include <qimage.h> +#include <qstring.h> + +/*! + Returns an image created by loading the \a filename, + and scalining it, preserving aspect ratio, to fit in + \a width by \a height pixels. + + First availability: Qtopia 2.0 +*/ +QImage Image::loadScaled(const QString & filename, const int width, const int height, + ScaleMode mode) +{ + QImageIO iio; + QString param; + int w = width; + int h = height; + + if (width == 0 || height == 0) + return QImage(); + + iio.setFileName(filename); + + // + // Try and load and scale the image in one hit. + // + param.sprintf("GetHeaderInformation"); + iio.setParameters(param); + iio.read(); + + // + // If we don't have bits(), read() understands parameters, + // and we can setup for fast reading. Otherwise, take the + // performance hit and do things slowly. + // + if (!iio.image().bits()) { + if ((iio.image().width() < w) && (iio.image().height() < h)) { + param.sprintf("%s", "Fast"); // No Tr + } + else { + int shrink_factor = 1; + QString smode; + switch (mode) { + case ScaleMin: + smode = "ScaleMin"; + shrink_factor = QMAX(iio.image().width() / w, iio.image().height() / h); + break; + case ScaleMax: + smode = "ScaleMax"; + shrink_factor = QMIN(iio.image().width() / w, iio.image().height() / h); + break; + case ScaleFree: + smode = "ScaleFree"; + shrink_factor = QMIN(iio.image().width() / w, iio.image().height() / h); + break; + } + param.sprintf("Scale( %i, %i, %s )%s, Shrink( %i )", // No tr + w, h, smode.latin1(), ", Fast", shrink_factor); // No tr + } + + iio.setParameters(param); + iio.read(); + return iio.image(); + } + + if ((iio.image().width() > w) || (iio.image().height() > h)) { + QSize s = aspectScaleSize(iio.image().width(), iio.image().height(), w, h, mode); + return iio.image().smoothScale(s.width(), s.height()); + } + + return iio.image(); +} + +// +// Returns new size of image, scaled to target_width and target_height, +// whilst preserving aspect ratio. Useful when it's not possible to +// scale an image prior to using it (eg. using RichText). Should be in +// global image utils. +// +// NOTE +// - expensive for images whose drivers do not allow us to retrieve +// parameters without reading the entire image. Currently (20030930) +// only the jpeg driver allows parameter reading. +// +QSize Image::loadScaledImageSize(const QString & filename, int target_width, int target_height, + int maxscale, ScaleMode mode) +{ + QImageIO iio; + iio.setFileName(filename); + iio.setParameters("GetHeaderInformation"); + iio.read(); + + int w = iio.image().width(); + int h = iio.image().height(); + + // + // Scaling up small pictures can be very ugly. + // Leave them alone if they are too small. + // + if (maxscale && w * maxscale < target_width && h * maxscale < target_height) + return QSize(w * maxscale, h * maxscale); + + return aspectScaleSize(w, h, target_width, target_height, mode); +} + +// Load an image to be used as a portrait. Force its height to height, +// scale width to new height, and crop the width if it's still > width +// XXX : Should be using integer math +QImage Image::loadPortrait(const QString & filename, const int width, const int height) +{ + QImageIO iio; + QString param; + int w = width; + int h = height; + + if (width == 0 || height == 0) + return QImage(); + + iio.setFileName(filename); + + // + // Try and load and scale the image in one hit. + // + param.sprintf("GetHeaderInformation"); + iio.setParameters(param); + iio.read(); + + // + // If we don't have bits(), read() understands parameters, + // and we can setup for fast reading. Otherwise, take the + // performance hit and do things slowly. + // + if (!iio.image().bits()) { + + w = (int) ((double) iio.image().width() / (double) (iio.image().height()) * + (double) height); + param.sprintf("Scale( %i, %i, ScaleFree )%s", // No tr + w, h, ", Fast"); // No tr + + iio.setParameters(param); + iio.read(); + + if (w > width) { + int x = (int) ((double) (w - width) / 2); + QRect r(x, 0, width, height); + return iio.image().copy(r); + } + else + return iio.image(); + } + else + //scale width to the new height + return sizeToPortrait(iio.image(), width, height); +} + +QImage Image::sizeToPortrait(const QImage & image, const int width, const int height) +{ + int w = (image.width() * height) / image.height(); + if (w > width) { + int x = (w - width) / 2; + QRect r(x, 0, width, height); + return image.smoothScale(w, height).copy(r); + } + else + return image.smoothScale(width, height); +} + +// +// Return (w x h) scaled to (target_width x target_height) with aspect +// ratio preserved. +// +QSize + Image::aspectScaleSize(const int w, const int h, const int target_width, + const int target_height, ScaleMode mode) +{ + QSize s; + if (mode == ScaleFree) { + s = QSize(target_width, target_height); + } + else { + bool useHeight = TRUE; + int rw = target_height * w / h; + + if (mode == ScaleMin) { + useHeight = (rw <= target_width); + } + else { // mode == ScaleMax + useHeight = (rw >= target_width); + } + + if (useHeight) { + s = QSize(rw, target_height); + } + else { + s = QSize(target_width, target_width * h / w); + } + } + + return s; +} + diff --git a/noncore/multimedia/camera2/image.h b/noncore/multimedia/camera2/image.h new file mode 100644 index 0000000..36394ff --- a/dev/null +++ b/noncore/multimedia/camera2/image.h @@ -0,0 +1,53 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef IMAGE_H +#define IMAGE_H + +#include <qimage.h> +#include <qtopia/qpeglobal.h> + +class Image { +public: + // namespace + enum ScaleMode { ScaleFree, ScaleMin, ScaleMax }; + static QImage loadScaled(const QString &filename, const int width, const int height, ScaleMode mode=ScaleMin); + static QSize loadScaledImageSize(const QString &filename, int target_width, int target_height, int maxscale=1, ScaleMode mode=ScaleMin); + static QImage loadPortrait(const QString &filename, const int width, const int height); + static QImage sizeToPortrait(const QImage &image, const int width, const int height); + static QSize aspectScaleSize(const int w, const int h, const int target_width, const int target_height, ScaleMode mode=ScaleMin); +}; + +#endif // IMAGE_H diff --git a/noncore/multimedia/camera2/main.cpp b/noncore/multimedia/camera2/main.cpp new file mode 100644 index 0000000..00e21de --- a/dev/null +++ b/noncore/multimedia/camera2/main.cpp @@ -0,0 +1,44 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "mainwindow.h" +#include <opie2/oapplication.h> +#include <opie2/oapplicationfactory.h> + +using namespace Opie::Core; +OPIE_EXPORT_APP(OApplicationFactory < CameraMainWindow >) +// QTOPIA_ADD_APPLICATION("camera",CameraMainWindow) +// QTOPIA_MAIN + diff --git a/noncore/multimedia/camera2/mainwindow.cpp b/noncore/multimedia/camera2/mainwindow.cpp new file mode 100644 index 0000000..45f8cdf --- a/dev/null +++ b/noncore/multimedia/camera2/mainwindow.cpp @@ -0,0 +1,763 @@ +/********************************************************************** + ** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. + ** + ** This file is part of the Qtopia Environment. + ** + ** 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. + ** + ** A copy of the GNU GPL license version 2 is included in this package as + ** LICENSE.GPL. + ** + ** 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. + ** + ** In addition, as a special exception Trolltech gives permission to link + ** the code of this program with Qtopia applications copyrighted, developed + ** and distributed by Trolltech under the terms of the Qtopia Personal Use + ** License Agreement. You must comply with the GNU General Public License + ** in all respects for all of the code used other than the applications + ** licensed under the Qtopia Personal Use License Agreement. If you modify + ** this file, you may extend this exception to your version of the file, + ** but you are not obligated to do so. If you do not wish to do so, delete + ** this exception statement from your version. + ** + ** See http://www.trolltech.com/gpl/ for GPL licensing information. + ** + ** Contact info@trolltech.com if any conditions of this licensing are + ** not clear to you. + ** + **********************************************************************/ + +#define QTOPIA_INTERNAL_FILEOPERATIONS +#include "mainwindow.h" +#include "videocaptureview.h" +#include "camerasettings.h" +#include "thumbbutton.h" + +#include "image.h" + +/* OPIE */ +#include <opie2/odebug.h> +#include <opie2/oresource.h> +using namespace Opie::Core; + +#include <qpe/config.h> +#include <qpe/qpeapplication.h> +#include <qpe/locationcombo.h> +//#include <qtopia/contextmenu.h> +#include <qpe/qcopenvelope_qws.h> +#include <qpe/resource.h> +//#include <qtopia/services.h> +#include <qpe/categories.h> +#include <qpe/qpetoolbar.h> +#include <qpe/global.h> + +#include <qaction.h> +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qpushbutton.h> +#include <qgroupbox.h> +#include <qsignalmapper.h> +#include <qdir.h> +#include <qimage.h> +#include <qslider.h> +#include <qtimer.h> +#include <qmessagebox.h> + +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/stat.h> + +static const int thmarg = 2; +static const bool video_supported = FALSE; + +CameraMainWindow::CameraMainWindow(QWidget * parent, const char *name, WFlags f) +:QMainWindow(parent, name, f) +{ + setCaption(tr("Camera")); + + picfile = Global::tempDir() + "image.jpg"; + camera = new CameraBase(this); + setCentralWidget(camera); + + connect(qApp, SIGNAL(appMessage(const QCString &, const QByteArray &)), + this, SLOT(appMessage(const QCString &, const QByteArray &))); + connect(qApp, SIGNAL(linkChanged(const QString &)), this, SLOT(linkChanged(const QString &))); + + Categories cats; + cats.load(categoryFileName()); + camcat = cats.id("Document View", "_Camera"); // No tr + if (!camcat) { + camcat = cats.addCategory("Document View", "_Camera"); // No tr + cats.save(categoryFileName()); + } + + camera->photo->setFocus(); + + connect(camera->photo, SIGNAL(clicked()), this, SLOT(takePhoto())); + connect(camera->video, SIGNAL(clicked()), this, SLOT(toggleVideo())); + + refocusTimer = new QTimer(this); + connect(refocusTimer, SIGNAL(timeout()), this, SLOT(takePhotoNow())); + + thumb[0] = camera->thumb1; + thumb[1] = camera->thumb2; + thumb[2] = camera->thumb3; + thumb[3] = camera->thumb4; + thumb[4] = camera->thumb5; + cur_thumb = -1; + + QSignalMapper *sm = new QSignalMapper(this); + for (int i = 0; i < nthumb; i++) { + sm->setMapping(thumb[i], i); + connect(thumb[i], SIGNAL(clicked()), sm, SLOT(map())); + thumb[i]->installEventFilter(this); + } + connect(sm, SIGNAL(mapped(int)), this, SLOT(thumbClicked(int))); + +#warning fixme +// AppLnk picture_viewer = Service::appLnk("PhotoEdit"); +// AppLnk video_viewer = Service::appLnk("Open/video/mpeg"); + + a_pview = new QAction(tr("%1...", "app name").arg("" /*picture_viewer.name() */ ), + Resource::loadPixmap(NULL /*picture_viewer.icon() */ ), QString::null, 0, + this, 0); + connect(a_pview, SIGNAL(activated()), this, SLOT(viewPictures())); + a_vview = new QAction(tr("%1...", "app name").arg("" /*video_viewer.name() */ ), + Resource::loadIconSet(NULL /*video_viewer.icon() */ ), QString::null, 0, + this, 0); + connect(a_vview, SIGNAL(activated()), this, SLOT(viewVideos())); + + a_settings = + new QAction(tr("Settings..."), Opie::Core::OResource::loadPixmap("camera2/settings", Opie::Core::OResource::SmallIcon), + QString::null, 0, this, 0); + connect(a_settings, SIGNAL(activated()), this, SLOT(doSettings())); + + a_th_edit = new QAction(tr("Edit"), Opie::Core::OResource::loadPixmap("edit", Opie::Core::OResource::SmallIcon), + QString::null, 0, this, 0); + connect(a_th_edit, SIGNAL(activated()), this, SLOT(editThumb())); + a_th_del = new QAction(tr("Delete"), Opie::Core::OResource::loadPixmap("trash", Opie::Core::OResource::SmallIcon), + QString::null, 0, this, 0); + connect(a_th_del, SIGNAL(activated()), this, SLOT(delThumb())); + a_th_add = + new QAction(tr("Move to Contact..."), Opie::Core::OResource::loadPixmap("addressbook/generic-contact", Opie::Core::OResource::SmallIcon), + QString::null, 0, this, 0); + connect(a_th_add, SIGNAL(activated()), this, SLOT(moveToContact())); + a_send = + new QAction(tr("Beam to Contact..."), Opie::Core::OResource::loadPixmap("beam", Opie::Core::OResource::SmallIcon), + QString::null, 0, this, 0); + connect(a_send, SIGNAL(activated()), this, SLOT(sendFile())); + + +#ifndef QTOPIA_PHONE + // Create Toolbars + QPEToolBar *bar = new QPEToolBar(this); + bar->setHorizontalStretchable(TRUE); + setToolBarsMovable(FALSE); + + a_pview->addTo(bar); + if (video_supported) + a_vview->addTo(bar); + a_th_edit->addTo(bar); + a_th_del->addTo(bar); + a_th_add->addTo(bar); + a_send->addTo(bar); + a_settings->addTo(bar); +#else + ContextMenu *contextMenu = new ContextMenu(this); + a_pview->addTo(contextMenu); + if (video_supported) + a_vview->addTo(contextMenu); + a_th_edit->addTo(contextMenu); + a_th_del->addTo(contextMenu); + a_th_add->addTo(contextMenu); + a_send->addTo(contextMenu); + a_settings->addTo(contextMenu); +#endif + + installEventFilter(camera->photo); + installEventFilter(camera->video); + camera->photo->installEventFilter(this); + camera->video->installEventFilter(this); + + // Load the allowable sizes from the camera hardware. + photo_size = camera->videocaptureview->photoSizes(); + video_size = camera->videocaptureview->videoSizes(); + + settings = new CameraSettings(this, 0, TRUE); + // load settings from config + Config cfg("Camera"); + cfg.setGroup("General"); + QString l = cfg.readEntry("location"); + +#warning fixme + /*if ( !l.isEmpty() ) + settings->location->setLocation(l); + */ + + storagepath = settings->location->documentPath(); + cfg.setGroup("Photo"); + int w; + w = cfg.readNumEntry("width", camera->videocaptureview->recommendedPhotoSize().width()); + for (psize = 0; psize < (int) photo_size.count() - 1 && photo_size[psize].width() > w;) + psize++; + pquality = cfg.readNumEntry("quality", settings->photo_quality->value()); + cfg.setGroup("Video"); + w = cfg.readNumEntry("width", camera->videocaptureview->recommendedVideoSize().width()); + for (vsize = 0; vsize < (int) video_size.count() - 1 && video_size[vsize].width() > w;) + vsize++; + vquality = cfg.readNumEntry("quality", settings->video_quality->value()); + vframerate = cfg.readNumEntry("framerate", settings->video_framerate->value()); + + for (int i = 0; i < (int) photo_size.count(); i++) { + settings->photo_size->insertItem(tr("%1 x %2").arg(photo_size[i].width()). + arg(photo_size[i].height())); + } + for (int i = 0; i < (int) video_size.count(); i++) { + settings->video_size->insertItem(tr("%1 x %2").arg(video_size[i].width()). + arg(video_size[i].height())); + } + + namehint = 0; + recording = FALSE; + + preview(); + + if (!video_supported) { + // Room for longer text + camera->photo->setText(tr("Take Photo")); + camera->video->setEnabled(FALSE); + camera->video->hide(); + } +} + +CameraMainWindow::~CameraMainWindow() +{ +} + +void CameraMainWindow::resizeEvent(QResizeEvent *) +{ + thumbw = width() / 5 - 4; + thumbh = thumbw * 3 / 4; + thumb[0]->setFixedHeight(thumbh + thmarg * 2); + loadThumbs(); +} + +bool CameraMainWindow::event(QEvent * e) +{ + if (e->type() == QEvent::WindowActivate) { + if (cur_thumb < 0) + camera->videocaptureview->setLive(); + } + else if (e->type() == QEvent::WindowDeactivate) { + camera->videocaptureview->setLive(-1); + } + return QMainWindow::event(e); +} + +bool CameraMainWindow::eventFilter(QObject * o, QEvent * e) +{ + if (e->type() == QEvent::KeyPress) { + QKeyEvent *ke = (QKeyEvent *) e; + +#if QTOPIA_PHONE + if (!ke->isAutoRepeat()) { + if (ke->key() == Key_1) { + takePhoto(); + return TRUE; + } + else if (ke->key() == Key_2) { + toggleVideo(); + return TRUE; + } + } +#endif + if (ke->key() == Key_Up) { + camera->photo->setFocus(); + return TRUE; + } + else if (ke->key() == Key_Down) { + thumb[0]->setFocus(); + return TRUE; + } + else if (ke->key() == Key_Left) { + if (o == camera->video) { + camera->photo->setFocus(); + return TRUE; + } + else { + if (o == thumb[0]) + return TRUE; + for (int i = 1; i < nthumb; ++i) { + if (o == thumb[i]) { + thumb[i - 1]->setFocus(); + return TRUE; + } + } + } + } + else if (ke->key() == Key_Right) { + if (o == camera->photo) { + camera->video->setFocus(); + return TRUE; + } + else { + if (o == thumb[nthumb - 1]) + return TRUE; + for (int i = 0; i < nthumb - 1; ++i) { + if (o == thumb[i]) { + thumb[i + 1]->setFocus(); + return TRUE; + } + } + } + } + } + else if (e->type() == QEvent::FocusIn) { + if (o == camera->photo) + camera->photo->setText(tr("Take Photo")); + updateActions(); + } + else if (e->type() == QEvent::FocusOut) { + if (o == camera->photo) + camera->photo->setText(tr("Activate Camera")); + } + return QWidget::eventFilter(o, e); +} + +void CameraMainWindow::updateActions() +{ + bool p = FALSE, v = FALSE; + QWidget *foc = focusWidget(); + if (foc == camera->photo) { + p = TRUE; + v = FALSE; + } + else if (foc == camera->video) { + v = TRUE; + p = FALSE; + } + a_pview->setEnabled(p); + a_vview->setEnabled(v); + a_settings->setEnabled(p || v); + bool th = !p && !v; + if (th) { + int i; + for (i = 0; i < nthumb; i++) { + if (thumb[i] == foc) { + selectThumb(i); + break; + } + } + if (i == nthumb || !thumb[i]->pixmap()) + th = FALSE; + } + else { + selectThumb(-1); + } +} + +void CameraMainWindow::viewPictures() +{ +#warning fixme +// ServiceRequest req("PhotoEdit","showCategory(int)"); +// req << camcat; +// req.send(); +} + +void CameraMainWindow::viewVideos() +{ +#warning fixme +// Service::appLnk("Open/video/mpeg").execute(); +} + +void CameraMainWindow::doSettings() +{ + bool v = video_supported; +#ifdef QTOPIA_PHONE + bool p; + p = a_pview->isEnabled(); + v = v && a_vview->isEnabled(); + if (p) + settings->photo->show(); + else + settings->photo->hide(); +#endif + if (v) + settings->video->show(); + else + settings->video->hide(); + settings->photo_size->setCurrentItem(psize); + settings->video_size->setCurrentItem(vsize); + settings->photo_quality->setValue(pquality); + settings->video_quality->setValue(vquality); + settings->video_framerate->setValue(vframerate); + settings->video_quality_n->setFixedWidth(fontMetrics().width("100")); + settings->photo_quality_n->setFixedWidth(fontMetrics().width("100")); + + if (QPEApplication::execDialog(settings)) { + confirmSettings(); + } + else { +#warning fixme +// settings->location->setLocation(storagepath); + } +} + +void CameraMainWindow::confirmSettings() +{ + storagepath = settings->location->documentPath(); + psize = settings->photo_size->currentItem(); + vsize = settings->video_size->currentItem(); + pquality = settings->photo_quality->value(); + vquality = settings->video_quality->value(); + vframerate = settings->video_framerate->value(); + + // save settings + Config cfg("Camera"); + cfg.setGroup("General"); + cfg.writeEntry("location", storagepath); + cfg.setGroup("Photo"); + cfg.writeEntry("width", photo_size[psize].width()); + cfg.writeEntry("quality", pquality); + cfg.setGroup("Video"); + cfg.writeEntry("width", video_size[vsize].width()); + cfg.writeEntry("quality", vquality); + cfg.writeEntry("framerate", vframerate); + + loadThumbs(); + + preview(); +} + +static int cmpDocLnk(const void *a, const void *b) +{ + const DocLnk *la = *(const DocLnk **) a; + const DocLnk *lb = *(const DocLnk **) b; + QFileInfo fa(la->linkFileKnown()? la->linkFile() : la->file()); + QFileInfo fb(lb->linkFileKnown()? lb->linkFile() : lb->file()); + return fa.lastModified().secsTo(fb.lastModified()); +} + +void CameraMainWindow::loadThumbs() +{ + if (storagepath.isEmpty()) { + updateActions(); + return; + } + + DocLnkSet set(storagepath, "image/jpeg"); + const QList < DocLnk > &l = set.children(); + + DocLnk *lnk; + DocLnk **array = new DocLnk *[l.count()]; + int n = 0; + for (QListIterator < DocLnk > it(l); (lnk = it.current()); ++it) { + if (lnk->categories().contains(camcat)) + array[n++] = lnk; + } + qsort(array, n, sizeof(array[0]), cmpDocLnk); + for (int i = 0; i < nthumb; i++) { + QPixmap pm; + if (i < n) { + picturefile[i] = *array[i]; + QImage img = Image::loadScaled(picturefile[i].file(), thumbw, thumbh); + pm.convertFromImage(img); + } + if (pm.isNull()) { + thumb[i]->setText(""); + } + else { + thumb[i]->setPixmap(pm); + } + thumb[i]->setEnabled(!pm.isNull()); + } + if (cur_thumb >= 0) + selectThumb(cur_thumb); + + if (!camera->videocaptureview->available()) { + camera->photo->setEnabled(FALSE); + camera->video->setEnabled(FALSE); + if (!n) { + thumb[0]->setEnabled(FALSE); + } + else { + thumb[0]->setFocus(); + thumb[0]->setEnabled(TRUE); + } + } + + updateActions(); +} + +void CameraMainWindow::delThumb(int th) +{ + switch (QMessageBox::warning(0, tr("Confirmation"), + tr("<qt>Delete '%1'?</qt>", + "%1 = file name").arg(picturefile[th].name()), QMessageBox::Yes, + QMessageBox::No)) { + case QMessageBox::Yes: + picturefile[th].removeFiles(); + + // Rhys Hack - if we have just deleted the last image and there + // is no camera connected, then exit the application. This + // avoids a focus problem where it is impossible to exit with + // the back button due to the focus being in a stupid place. + loadThumbs(); + if (!camera->videocaptureview->available() && !(thumb[0]->isEnabled())) { + close(); + } + break; + default: + //nothing + break; + } +} + +void CameraMainWindow::pushThumb(const DocLnk & f, const QImage & img) +{ + for (int i = nthumb; --i;) { + bool en = thumb[i - 1]->isEnabled(); + thumb[i]->setEnabled(en); + picturefile[i] = picturefile[i - 1]; + const QPixmap *pm = thumb[i - 1]->pixmap(); + if (en && pm) { + thumb[i]->setPixmap(*pm); + } + else { + thumb[i]->setText(""); + } + } + QPixmap pm; + QSize sz = Image::aspectScaleSize(img.width(), img.height(), thumbw, thumbh); + QImage simg = img.smoothScale(sz.width(), sz.height()); + pm.convertFromImage(simg); + thumb[0]->setPixmap(pm); + thumb[0]->setEnabled(TRUE); + picturefile[0] = f; +} + +void CameraMainWindow::takePhoto() +{ + if (camera->photo != focusWidget()) { + camera->photo->setFocus(); + return; + } + QSize size = photo_size[psize]; + if (size == camera->videocaptureview->captureSize() || + camera->videocaptureview->refocusDelay() == 0) { + + // We can grab the current image immediately. + takePhotoNow(); + + } + else { + + // Change the camera size and then wait for the camera to refocus. + camera->videocaptureview->setCaptureSize(size); + refocusTimer->start(camera->videocaptureview->refocusDelay(), TRUE); + + } +} + +void CameraMainWindow::takePhotoNow() +{ + QImage img = camera->videocaptureview->image(); + + if (inSnapMode()) { + QCopEnvelope e(snap_ch, "valueSupplied(QString,QImage)"); + QSize s = Image::aspectScaleSize(img.width(), img.height(), snap_maxw, snap_maxh); + e << snap_id << img.smoothScale(s.width(), s.height()); + setSnapMode(FALSE); + close(); + } + else { + DocLnk f; + //f.setLocation(storagepath); + f.setType("image/jpeg"); + QDateTime dt = QDateTime::currentDateTime(); + QString date = dt.toString(); + f.setName(tr("Photo, " + date)); + + QArray < int >c(1); + c[0] = camcat; + f.setCategories(c); + img.save(f.file(), "JPEG", pquality); // Save the image in its original size. + f.writeLink(); + pushThumb(f, img); + } + + preview(); +} + +bool CameraMainWindow::inSnapMode() const +{ + return !snap_ch.isEmpty(); +} + +void CameraMainWindow::setSnapMode(bool y) +{ + if (y) { + camera->thumbs->hide(); + camera->video->hide(); + } + else { + camera->thumbs->show(); + if (video_supported) + camera->video->show(); + else + camera->video->hide(); + snap_ch = QString::null; + } +} + +void CameraMainWindow::toggleVideo() +{ + if (recording) + stopVideo(); + else + startVideo(); + recording = !recording; + camera->video->setText(recording ? tr("Stop") : tr("Video")); + camera->photo->setEnabled(!recording); + for (int i = 0; i < nthumb; i++) + thumb[i]->setEnabled(!recording && thumb[i]->pixmap()); +} + +void CameraMainWindow::startVideo() +{ + // XXX eg. MJPG +} +void CameraMainWindow::stopVideo() +{ +} + +void CameraMainWindow::thumbClicked(int i) +{ + selectThumb(i); +} + +void CameraMainWindow::editThumb() +{ + picturefile[cur_thumb].execute(); +} + +void CameraMainWindow::selectThumb(int i) +{ + cur_thumb = i; + if (i >= 0) { + QImage img(picturefile[i].file()); + camera->videocaptureview->setStill(img); + thumb[i]->setFocus(); + } + else { + camera->videocaptureview->setLive(); + } + a_th_edit->setEnabled(i >= 0); + a_th_del->setEnabled(i >= 0); + a_th_add->setEnabled(i >= 0); + a_send->setEnabled(i >= 0); +} + +void CameraMainWindow::moveToContact() +{ + if (cur_thumb >= 0) { +#warning fixme +// QCopEnvelope e(Service::channel("Contacts"),"setContactImage(QImage)"); +// QImage img; +// img.load(picturefile[cur_thumb].file()); +// e << img; + } +} + +void CameraMainWindow::delThumb() +{ + if (cur_thumb >= 0) { + int d = cur_thumb; + if (cur_thumb > 0) + selectThumb(cur_thumb - 1); + delThumb(d); + } +} + +void CameraMainWindow::linkChanged(const QString &) +{ + loadThumbs(); +} + +void CameraMainWindow::appMessage(const QCString & msg, const QByteArray & data) +{ + if (msg == "getImage(QCString,QString,int,int,QImage)") { + QDataStream ds(data, IO_ReadOnly); + ds >> snap_ch >> snap_id >> snap_maxw >> snap_maxh; + setSnapMode(TRUE); + QPEApplication::setKeepRunning(); + } +} + +void CameraMainWindow::preview() +{ + if (camera->videocaptureview->refocusDelay() > 200) { + camera->videocaptureview->setCaptureSize(photo_size[psize]); + } + else { + camera->videocaptureview->setCaptureSize(camera->videocaptureview-> + recommendedPreviewSize()); + } +} + +void CameraMainWindow::sendFile() +{ + if (cur_thumb >= 0) { + //copy file + QFile input(picturefile[cur_thumb].file()); + if (!input.open(IO_ReadOnly)) { + return; //error + } + QFile output(picfile); + if (!output.open(IO_WriteOnly)) { + return; + } + + const int BUFFER_SIZE = 1024; + Q_INT8 buffer[BUFFER_SIZE]; + + QDataStream srcStr(&input); + QDataStream destStr(&output); + + while (!srcStr.atEnd()) { + int i = 0; + while (!srcStr.atEnd() && i < BUFFER_SIZE) { + srcStr >> buffer[i]; + i++; + } + for (int k = 0; k < i; k++) { + destStr << buffer[k]; + } + } + +#warning fixme +// QCopEnvelope e(Service::channel("Email"),"writeMessage(QString,QString,QStringList,QStringList)"); +// e << QString() << QString() << QStringList() << QStringList( QString( picfile ) ); + } +} + +void ThumbButton::drawButtonLabel(QPainter * p) +{ + const QPixmap *pm = pixmap(); + if (pm) { + QSize s = (size() - pm->size()) / 2; + p->drawPixmap(s.width(), s.height(), *pm); + } +} + +ThumbButton::ThumbButton(QWidget * parent, const char *name):QToolButton(parent, name) +{ +} + diff --git a/noncore/multimedia/camera2/mainwindow.h b/noncore/multimedia/camera2/mainwindow.h new file mode 100644 index 0000000..d6c5a7e --- a/dev/null +++ b/noncore/multimedia/camera2/mainwindow.h @@ -0,0 +1,132 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "camerabase.h" +#include <qvaluelist.h> +#include <qmainwindow.h> +#include <qpe/applnk.h> + +class LocationCombo; +class QAction; +class QTimer; +class CameraSettings; + + +class CameraMainWindow : public QMainWindow +{ + Q_OBJECT +public: + static QString appName() { return QString::fromLatin1("camera2"); } + + CameraMainWindow( QWidget *parent=0, const char *name=0, WFlags fl=0 ); + ~CameraMainWindow(); + +public slots: + void takePhoto(); + void toggleVideo(); + void selectThumb(int i); + void thumbClicked(int i); + +private slots: + void viewPictures(); + void viewVideos(); + void doSettings(); + void appMessage(const QCString& msg, const QByteArray& data); + void editThumb(); + void delThumb(); + void moveToContact(); + void takePhotoNow(); + void sendFile(); + void linkChanged(const QString&); + +private: + bool event(QEvent* e); + void updateActions(); + void resizeEvent(QResizeEvent*); + + bool eventFilter(QObject*, QEvent*); + QString nextFileName(); + void loadThumbs(); + void pushThumb(const DocLnk& f, const QImage& img); + static const int nthumb = 5; + QToolButton* thumb[nthumb]; + DocLnk picturefile[nthumb]; + int cur_thumb; + void delThumb(int th); + + // Settings + void confirmSettings(); + CameraSettings *settings; + QString storagepath; + int thumbw; + int thumbh; + int psize; + int vsize; + int pquality; + int vquality; + int vframerate; + + // Snap + QCString snap_ch; + QString snap_id; + int snap_maxw, snap_maxh; + bool inSnapMode() const; + void setSnapMode(bool); + + CameraBase *camera; + + int namehint; + QAction *a_pview, *a_vview, *a_settings; + QAction *a_th_edit, *a_th_del, *a_th_add; + QAction *a_send; + QValueList<QSize> photo_size; + QValueList<QSize> video_size; + + QTimer *refocusTimer; + QString picfile; + + bool recording; + void stopVideo(); + void startVideo(); + + void preview(); + + int camcat; +}; + +#endif + diff --git a/noncore/multimedia/camera2/opie-camera2.control b/noncore/multimedia/camera2/opie-camera2.control new file mode 100644 index 0000000..a2d0700 --- a/dev/null +++ b/noncore/multimedia/camera2/opie-camera2.control @@ -0,0 +1,10 @@ +Package: opie-camera2 +Files: bin/camerapics/camera2 apps/Applications/camera2.desktop +Priority: optional +Section: opie/multimedia +Maintainer: Lorn "ljp" Potter <lorn.potter@trolltech.com> +Architecture: arm +Version: 1.0.1$EXTRAVERSION +Depends: libqpe1, libopiecore2, libopieui2 +Description: A Camera Application + A Camera Application to use with Video4Linux. diff --git a/noncore/multimedia/camera2/thumbbutton.h b/noncore/multimedia/camera2/thumbbutton.h new file mode 100644 index 0000000..f7ca3b4 --- a/dev/null +++ b/noncore/multimedia/camera2/thumbbutton.h @@ -0,0 +1,50 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef THUMBBUTTON_H +#define THUMBBUTTON_H + +#include <qtoolbutton.h> + +class ThumbButton : public QToolButton +{ + Q_OBJECT +public: + ThumbButton( QWidget *parent, const char* name ); + + void drawButtonLabel( QPainter * ); +}; + +#endif + diff --git a/noncore/multimedia/camera2/videocaptureview.cpp b/noncore/multimedia/camera2/videocaptureview.cpp new file mode 100644 index 0000000..410634a --- a/dev/null +++ b/noncore/multimedia/camera2/videocaptureview.cpp @@ -0,0 +1,599 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "videocaptureview.h" +#include <qimage.h> +#include <qpainter.h> +#ifdef Q_WS_QWS +#include <qgfx_qws.h> +#include <qdirectpainter_qws.h> +#endif + +#ifdef __linux__ +#define HAVE_VIDEO4LINUX 1 +#endif + +#ifdef HAVE_VIDEO4LINUX + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <fcntl.h> +#include <linux/videodev.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <sys/mman.h> + +#endif /* HAVE_VIDEO4LINUX */ + +class VideoCapture { + public: + VideoCapture(); + ~VideoCapture(); + + bool hasCamera() const; + void getCameraImage(QImage & img, bool copy = FALSE); + + QValueList < QSize > photoSizes() const; + QValueList < QSize > videoSizes() const; + + QSize recommendedPhotoSize() const; + QSize recommendedVideoSize() const; + QSize recommendedPreviewSize() const; + + QSize captureSize() const; + void setCaptureSize(QSize size); + + uint refocusDelay() const; + int minimumFramePeriod() const; + + private: +#ifdef HAVE_VIDEO4LINUX + int fd; + int width, height; + struct video_capability caps; + struct video_mbuf mbuf; + unsigned char *frames; + int currentFrame; + + void setupCamera(QSize size); + void shutdown(); +#endif +}; + +#ifdef HAVE_VIDEO4LINUX + +#define VIDEO_DEVICE "/dev/video" + +bool VideoCapture::hasCamera() const +{ + return (fd != -1); +} + +QSize VideoCapture::captureSize() const +{ + return QSize(width, height); +} + +uint VideoCapture::refocusDelay() const +{ + return 250; +} + +int VideoCapture::minimumFramePeriod() const +{ + return 40; // milliseconds +} + +VideoCapture::VideoCapture() +{ + setupCamera(QSize(0, 0)); +} + +VideoCapture::~VideoCapture() +{ + shutdown(); +} + +void VideoCapture::setupCamera(QSize size) +{ + qWarning(" VideoCapture::setupCamera"); + // Clear important variables. + frames = 0; + currentFrame = 0; + width = 640; + height = 480; + caps.minwidth = width; + caps.minheight = height; + caps.maxwidth = width; + caps.maxheight = height; + + // Open the video device. + fd = open(VIDEO_DEVICE, O_RDWR); + if (fd == -1) { + qWarning("%s: %s", VIDEO_DEVICE, strerror(errno)); + return; + } + + // Get the device's current capabilities. + memset(&caps, 0, sizeof(caps)); + if (ioctl(fd, VIDIOCGCAP, &caps) < 0) { + qWarning("%s: could not retrieve the video capabilities", VIDEO_DEVICE); + close(fd); + fd = -1; + return; + } + + // Change the channel to the first-connected camera, skipping TV inputs. + // If there are multiple cameras, this may need to be modified. + int chan; + struct video_channel chanInfo; + qWarning("available video capture inputs:"); + for (chan = 0; chan < caps.channels; ++chan) { + chanInfo.channel = chan; + if (ioctl(fd, VIDIOCGCHAN, &chanInfo) >= 0) { + if (chanInfo.type == VIDEO_TYPE_CAMERA) + qWarning(" %s (camera)", chanInfo.name); + else if (chanInfo.type == VIDEO_TYPE_TV) + qWarning(" %s (tv)", chanInfo.name); + else + qWarning(" %s (unknown)", chanInfo.name); + } + } + for (chan = 0; chan < caps.channels; ++chan) { + chanInfo.channel = chan; + if (ioctl(fd, VIDIOCGCHAN, &chanInfo) >= 0) { + if (chanInfo.type == VIDEO_TYPE_CAMERA) { + qWarning("selecting camera on input %s", chanInfo.name); + if (ioctl(fd, VIDIOCSCHAN, &chan) < 0) { + qWarning("%s: could not set the channel", VIDEO_DEVICE); + } + break; + } + } + } + + // Set the desired picture mode to RGB32. + struct video_picture pict; + memset(&pict, 0, sizeof(pict)); + ioctl(fd, VIDIOCGPICT, &pict); + pict.palette = VIDEO_PALETTE_RGB32; + if (ioctl(fd, VIDIOCSPICT, &pict) < 0) { + qWarning("%s: could not set the picture mode", VIDEO_DEVICE); + close(fd); + fd = -1; + return; + } + + // Determine the capture size to use. Zero indicates "preview mode". + if (size.width() == 0) { + size = QSize(caps.minwidth, caps.minheight); + } + + // Get the current capture window. + struct video_window wind; + memset(&wind, 0, sizeof(wind)); + ioctl(fd, VIDIOCGWIN, &wind); + + // Adjust the capture size to match the camera's aspect ratio. + if (caps.maxwidth > 0 && caps.maxheight > 0) { + if (size.width() > size.height()) { + size = QSize(size.height() * caps.maxwidth / caps.maxheight, size.height()); + } + else { + size = QSize(size.width(), size.width() * caps.maxheight / caps.maxwidth); + } + } + + // Set the new capture window. + wind.x = 0; + wind.y = 0; + wind.width = size.width(); + wind.height = size.height(); + if (ioctl(fd, VIDIOCSWIN, &wind) < 0) { + qWarning("%s: could not set the capture window", VIDEO_DEVICE); + } + + // Re-read the capture window, to see what it was adjusted to. + ioctl(fd, VIDIOCGWIN, &wind); + width = wind.width; + height = wind.height; + + // Enable mmap-based access to the camera. + memset(&mbuf, 0, sizeof(mbuf)); + if (ioctl(fd, VIDIOCGMBUF, &mbuf) < 0) { + qWarning("%s: mmap-based camera access is not available", VIDEO_DEVICE); + close(fd); + fd = -1; + return; + } + + // Mmap the designated memory region. + frames = (unsigned char *) mmap(0, mbuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (!frames || frames == (unsigned char *) (long) (-1)) { + qWarning("%s: could not mmap the device", VIDEO_DEVICE); + close(fd); + fd = -1; + return; + } + + // Start capturing of the first frame. + struct video_mmap capture; + currentFrame = 0; + capture.frame = currentFrame; + capture.width = width; + capture.height = height; + capture.format = VIDEO_PALETTE_RGB32; + ioctl(fd, VIDIOCMCAPTURE, &capture); +} + +void VideoCapture::shutdown() +{ + if (frames != 0) { + munmap(frames, mbuf.size); + frames = 0; + } + if (fd != -1) { + int flag = 0; + ioctl(fd, VIDIOCSYNC, 0); + ioctl(fd, VIDIOCCAPTURE, &flag); + close(fd); + fd = -1; + } +} + +void VideoCapture::getCameraImage(QImage & img, bool copy) +{ + if (fd == -1) { + if (img.isNull()) { + img.create(width, height, 32); + } + return; + } + + // Start capturing the next frame (we alternate between 0 and 1). + int frame = currentFrame; + struct video_mmap capture; + if (mbuf.frames > 1) { + currentFrame = !currentFrame; + capture.frame = currentFrame; + capture.width = width; + capture.height = height; + capture.format = VIDEO_PALETTE_RGB32; + ioctl(fd, VIDIOCMCAPTURE, &capture); + } + + // Wait for the current frame to complete. + ioctl(fd, VIDIOCSYNC, &frame); + + // Create an image that refers directly to the kernel's + // frame buffer, to avoid having to copy the data. + if (!copy) { + img = QImage(frames + mbuf.offsets[frame], width, height, 32, 0, 0, QImage::IgnoreEndian); + } + else { + img.create(width, height, 32); + memcpy(img.bits(), frames + mbuf.offsets[frame], width * height * 4); + } + + // Queue up another frame if the device only supports one at a time. + if (mbuf.frames <= 1) { + capture.frame = currentFrame; + capture.width = width; + capture.height = height; + capture.format = VIDEO_PALETTE_RGB32; + ioctl(fd, VIDIOCMCAPTURE, &capture); + } +} + +QValueList < QSize > VideoCapture::photoSizes() const +{ + QValueList < QSize > list; + list.append(QSize(caps.maxwidth, caps.maxheight)); + if (caps.maxwidth != caps.minwidth || caps.maxheight != caps.minheight) + list.append(QSize(caps.minwidth, caps.minheight)); + return list; +} + +QValueList < QSize > VideoCapture::videoSizes() const +{ + // We use the same sizes for both. + return photoSizes(); +} + +QSize VideoCapture::recommendedPhotoSize() const +{ + return QSize(caps.maxwidth, caps.maxheight); +} + +QSize VideoCapture::recommendedVideoSize() const +{ + return QSize(caps.minwidth, caps.minheight); +} + +QSize VideoCapture::recommendedPreviewSize() const +{ + return QSize(caps.minwidth, caps.minheight); +} + +void VideoCapture::setCaptureSize(QSize size) +{ + if (size.width() != width || size.height() != height) { + shutdown(); + setupCamera(size); + } +} + +#else /* !HAVE_VIDEO4LINUX */ + +// Dummy implementation for systems without video. + +VideoCapture::VideoCapture() +{ +} + +VideoCapture::~VideoCapture() +{ +} + +bool VideoCapture::hasCamera() const +{ + return TRUE; +} + +QSize VideoCapture::captureSize() const +{ + return QSize(640, 480); +} + +uint VideoCapture::refocusDelay() const +{ + return 0; +} + +int VideoCapture::minimumFramePeriod() const +{ + return 100; +} + +static unsigned int nextrand() +{ +#define A 16807 +#define M 2147483647 +#define Q 127773 +#define R 2836 + static unsigned int rnd = 1; + unsigned long hi = rnd / Q; + unsigned long lo = rnd % Q; + unsigned long test = A * lo - R * hi; + if (test > 0) + rnd = test; + else + rnd = test + M; + return rnd; +} + +void VideoCapture::getCameraImage(QImage & img, bool) +{ + // Just generate something dynamic (rectangles) + static QImage cimg; + int x, y, w, h; + if (cimg.isNull()) { + x = y = 0; + w = 640; + h = 480; + cimg.create(w, h, 32); + } + else { + w = nextrand() % (cimg.width() - 10) + 10; + h = nextrand() % (cimg.height() - 10) + 10; + x = nextrand() % (cimg.width() - w); + y = nextrand() % (cimg.height() - h); + } + QRgb c = qRgb(nextrand() % 255, nextrand() % 255, nextrand() % 255); + for (int j = 0; j < h; j++) { + QRgb *l = (QRgb *) cimg.scanLine(y + j) + x; + for (int i = 0; i < w; i++) + l[i] = c; + } + img = cimg; +} + +QValueList < QSize > VideoCapture::photoSizes() constconst +{ + QValueList < QSize > list; + list.append(QSize(640, 480)); + list.append(QSize(320, 240)); + return list; +} + +QValueList < QSize > VideoCapture::videoSizes() constconst +{ + QValueList < QSize > list; + list.append(QSize(640, 480)); + list.append(QSize(320, 240)); + return list; +} + +QSize VideoCapture::recommendedPhotoSize() const +{ + return QSize(640, 480); +} + +QSize VideoCapture::recommendedVideoSize() const +{ + return QSize(320, 240); +} + +QSize VideoCapture::recommendedPreviewSize() const +{ + return QSize(320, 240); +} + +void VideoCapture::setCaptureSize(QSize size) +{ +} + +#endif /* !HAVE_VIDEO4LINUX */ + +VideoCaptureView::VideoCaptureView(QWidget * parent, const char *name, WFlags fl):QWidget(parent, + name, fl) +{ + capture = new VideoCapture(); + QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Expanding); + setSizePolicy(sp); + tid_update = 0; + setLive(); +} + +VideoCaptureView::~VideoCaptureView() +{ + delete capture; +} + +void VideoCaptureView::setLive(int period) +{ + if (tid_update) + killTimer(tid_update); + if (period == 0) + tid_update = startTimer(capture->minimumFramePeriod()); + else if (period > 0) + tid_update = startTimer(period); + else + tid_update = 0; +} + +void VideoCaptureView::setStill(const QImage & i) +{ + setLive(-1); + img = i; + repaint(TRUE); +} + +QValueList < QSize > VideoCaptureView::photoSizes() const +{ + return capture->photoSizes(); +} + +QValueList < QSize > VideoCaptureView::videoSizes() const +{ + return capture->videoSizes(); +} + +QSize VideoCaptureView::recommendedPhotoSize() const +{ + return capture->recommendedPhotoSize(); +} + +QSize VideoCaptureView::recommendedVideoSize() const +{ + return capture->recommendedVideoSize(); +} + +QSize VideoCaptureView::recommendedPreviewSize() const +{ + return capture->recommendedPreviewSize(); +} + +QSize VideoCaptureView::captureSize() const +{ + return capture->captureSize(); +} + +void VideoCaptureView::setCaptureSize(QSize size) +{ + capture->setCaptureSize(size); +} + +uint VideoCaptureView::refocusDelay() const +{ + return capture->refocusDelay(); +} + +bool VideoCaptureView::available() const +{ + return capture->hasCamera(); +} + +void VideoCaptureView::paintEvent(QPaintEvent *) +{ + if (tid_update && !capture->hasCamera()) { + QPainter p(this); + p.drawText(rect(), AlignCenter, tr("No Camera")); + return; + } + + if (tid_update) + capture->getCameraImage(img); + int w = img.width(); + int h = img.height(); + + if (!w || !h) + return; + + if (width() * w > height() * h) { + w = w * height() / h; + h = height(); + } + else { + h = h * width() / w; + w = width(); + } + + if (qt_screen->transformOrientation() == 0) { + // Stretch and draw the image. + QDirectPainter p(this); + QGfx *gfx = p.internalGfx(); + if (gfx) { + gfx->setSource(&img); + gfx->setAlphaType(QGfx::IgnoreAlpha); + gfx->stretchBlt((width() - w) / 2, (height() - h) / 2, w, h, img.width(), img.height()); + } + } + else { + // This code is nowhere near efficient enough (hence the above). + // TODO - handle rotations during direct painting. + QImage scimg = img.smoothScale(w, h); + QPainter p(this); + p.drawImage((width() - w) / 2, (height() - h) / 2, scimg); + } +} + +void VideoCaptureView::timerEvent(QTimerEvent *) +{ + repaint(FALSE); +} + diff --git a/noncore/multimedia/camera2/videocaptureview.h b/noncore/multimedia/camera2/videocaptureview.h new file mode 100644 index 0000000..68c3b68 --- a/dev/null +++ b/noncore/multimedia/camera2/videocaptureview.h @@ -0,0 +1,82 @@ +/********************************************************************** +** Copyright (C) 2000-2006 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** 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. +** +** A copy of the GNU GPL license version 2 is included in this package as +** LICENSE.GPL. +** +** 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. +** +** In addition, as a special exception Trolltech gives permission to link +** the code of this program with Qtopia applications copyrighted, developed +** and distributed by Trolltech under the terms of the Qtopia Personal Use +** License Agreement. You must comply with the GNU General Public License +** in all respects for all of the code used other than the applications +** licensed under the Qtopia Personal Use License Agreement. If you modify +** this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef VIDEOVIEW_H +#define VIDEOVIEW_H + +#include <qwidget.h> +#include <qimage.h> +#include <qvaluelist.h> + +class VideoCapture; + + +class VideoCaptureView : public QWidget +{ + Q_OBJECT + +public: + VideoCaptureView( QWidget *parent=0, const char *name=0, WFlags fl=0 ); + ~VideoCaptureView(); + + bool available() const; + + QImage image() const { return img; } + void setLive(int period=0); + void setStill(const QImage&); + + QValueList<QSize> photoSizes() const; + QValueList<QSize> videoSizes() const; + + QSize recommendedPhotoSize() const; + QSize recommendedVideoSize() const; + QSize recommendedPreviewSize() const; + + QSize captureSize() const; + void setCaptureSize( QSize size ); + + uint refocusDelay() const; + +protected: + void paintEvent(QPaintEvent*); + void timerEvent(QTimerEvent*); + +private: + QImage img; + int tid_update; + VideoCapture *capture; +}; + +#endif + @@ -1,70 +1,71 @@ CONFIG_ABOUTAPPLET core/applets/aboutapplet aboutapplet.pro CONFIG_ADDRESSBOOK core/pim/addressbook addressbook.pro CONFIG_ADVANCEDFM noncore/apps/advancedfm advancedfm.pro CONFIG_APPEARANCE2 noncore/settings/appearance2 appearance2.pro CONFIG_APPSKEY noncore/settings/appskey appskey.pro CONFIG_AQPKG noncore/settings/aqpkg aqpkg.pro CONFIG_AUTOROTATEAPPLET noncore/applets/autorotateapplet autorotateapplet.pro CONFIG_BACKGAMMON noncore/games/backgammon backgammon.pro CONFIG_BACKUP noncore/settings/backup backup.pro CONFIG_BARTENDER noncore/apps/opie-bartender bartender.pro CONFIG_BATTERYAPPLET core/applets/batteryapplet batteryapplet.pro CONFIG_BEND noncore/unsupported/mail2/bend bend.pro CONFIG_BIGSCREEN_EXAMPLE unsupported/libopie/big-screen/example osplitter_mail.pro CONFIG_BLUE-PIN noncore/net/opietooth/blue-pin blue-pin.pro CONFIG_BOUNCE noncore/games/bounce bounce.pro CONFIG_BRIGHTNESSAPPLET noncore/applets/brightnessapplet brightnessapplet.pro CONFIG_BUTTON-SETTINGS core/settings/button button.pro CONFIG_BUZZWORD noncore/games/buzzword buzzword.pro CONFIG_CALC2 noncore/tools/calc2 calc2.pro CONFIG_CALCULATOR noncore/tools/calculator calculator.pro CONFIG_CALIBRATE core/apps/calibrate calibrate.pro CONFIG_CAMERA noncore/multimedia/camera camera.pro +CONFIG_CAMERA2 noncore/multimedia/camera2 camera2.pro CONFIG_CARDMON core/applets/cardmon cardmon.pro CONFIG_CHECKBOOK noncore/apps/checkbook checkbook.pro CONFIG_CITYTIME core/settings/citytime citytime.pro CONFIG_CLIPBOARDAPPLET core/applets/clipboardapplet clipboardapplet.pro CONFIG_CLOCKAPPLET core/applets/clockapplet clockapplet.pro CONFIG_CLOCK noncore/tools/clock clock.pro CONFIG_CONFEDIT noncore/apps/confedit confedit.pro CONFIG_DAGGER noncore/apps/dagger dagger.pro CONFIG_DASHER inputmethods/dasher dasher.pro CONFIG_DATEBOOK2 core/pim/datebook2 datebook2.pro CONFIG_DATEBOOK core/pim/datebook datebook.pro CONFIG_DATEBOOK_BIRTHDAYS_HOLIDAY core/pim/datebook/holiday/birthday birthdays.pro CONFIG_DATEBOOK_CHRISTIAN_HOLIDAY core/pim/datebook/holiday/christian christian-holidays.pro CONFIG_DATEBOOK_NATIONAL_HOLIDAY core/pim/datebook/holiday/national national-holidays.pro CONFIG_DECO_FLAT noncore/decorations/flat flat.pro CONFIG_DECO_LIQUID noncore/decorations/liquid liquid.pro CONFIG_DECO_POLISHED noncore/decorations/polished polished.pro CONFIG_DICTIONARY noncore/apps/dictionary dictionary.pro CONFIG_DOCTAB noncore/settings/doctab doctab.pro CONFIG_DRAWPAD noncore/graphics/drawpad drawpad.pro CONFIG_DVORAK inputmethods/dvorak dvorak.pro CONFIG_EMBEDDEDKONSOLE core/apps/embeddedkonsole embeddedkonsole.pro CONFIG_EUROCONV noncore/tools/euroconv/ euroconv.pro CONFIG_EXAMPLE_APPLET examples/applet applet.pro CONFIG_EXAMPLE_BOARD examples/inputmethod inputmethod.pro CONFIG_EXAMPLE_LIBOPIE2BLUEZ examples/opiebluez opiebluez.pro CONFIG_EXAMPLE_LIBOPIE2CORE examples/opiecore opiecore.pro CONFIG_EXAMPLE_LIBOPIE2DB examples/opiedb opiedb.pro CONFIG_EXAMPLE_LIBOPIE2MM examples/opiemm opiemm.pro CONFIG_EXAMPLE_LIBOPIE2NET examples/opienet opienet.pro CONFIG_EXAMPLE_LIBOPIE2PIM examples/opiepim opiepim.pro CONFIG_EXAMPLE_LIBOPIE2SECURITY examples/opiesecurity opiesecurity.pro CONFIG_EXAMPLE_LIBOPIE2UI examples/opieui opieui.pro CONFIG_EXAMPLE_MENU examples/menuapplet menuapplet.pro CONFIG_EXAMPLE_VPN examples/networksettings networksettings.pro CONFIG_FIFTEEN noncore/games/fifteen fifteen.pro CONFIG_FILEBROWSER noncore/unsupported/filebrowser filebrowser.pro CONFIG_FLAT noncore/styles/flat flat.pro CONFIG_FORMATTER noncore/tools/formatter formatter.pro CONFIG_FREETYPE freetype freetype.pro CONFIG_FRESH noncore/styles/fresh fresh.pro CONFIG_FTPLIB noncore/net/ftplib ftplib.pro CONFIG_GO noncore/games/go go.pro CONFIG_GSMTOOL noncore/unsupported/gsmtool gsmtool.pro CONFIG_GUTENBROWSER noncore/apps/opie-gutenbrowser opie-gutenbrowser.pro CONFIG_HANDWRITING inputmethods/handwriting handwriting.pro CONFIG_HELPBROWSER core/apps/helpbrowser helpbrowser.pro CONFIG_HOMEAPPLET core/applets/homeapplet homeapplet.pro diff --git a/pics/camera2/Camera.png b/pics/camera2/Camera.png Binary files differnew file mode 100644 index 0000000..e619c11 --- a/dev/null +++ b/pics/camera2/Camera.png diff --git a/pics/camera2/Camera_48.png b/pics/camera2/Camera_48.png Binary files differnew file mode 100644 index 0000000..00b8585 --- a/dev/null +++ b/pics/camera2/Camera_48.png diff --git a/pics/camera2/Camera_48_anim.mng b/pics/camera2/Camera_48_anim.mng Binary files differnew file mode 100644 index 0000000..6b19394 --- a/dev/null +++ b/pics/camera2/Camera_48_anim.mng diff --git a/pics/camera2/settings.png b/pics/camera2/settings.png Binary files differnew file mode 100644 index 0000000..05bfdf7 --- a/dev/null +++ b/pics/camera2/settings.png |