summaryrefslogtreecommitdiff
path: root/library
Side-by-side diff
Diffstat (limited to 'library') (more/less context) (ignore whitespace changes)
-rw-r--r--library/alarmserver.cpp9
-rw-r--r--library/applnk.cpp1
-rw-r--r--library/tzselect.cpp1
3 files changed, 6 insertions, 5 deletions
diff --git a/library/alarmserver.cpp b/library/alarmserver.cpp
index 48ab9c1..ba7b015 100644
--- a/library/alarmserver.cpp
+++ b/library/alarmserver.cpp
@@ -1,507 +1,506 @@
/**********************************************************************
** 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.
**
**********************************************************************/
-#include <qdir.h>
-
+#include "alarmserver.h"
+#include <qpe/global.h>
#include <qpe/qpeapplication.h>
-
#include <qpe/qcopenvelope_qws.h>
-#include "alarmserver.h"
#include <qpe/timeconversion.h>
+#include <qdir.h>
+
#include <sys/types.h>
#include <sys/stat.h>
-
#include <stdlib.h>
#include <unistd.h>
#undef USE_ATD // not used anymore -- we run opie-alarm on suspend/resume
struct timerEventItem
{
time_t UTCtime;
QCString channel, message;
int data;
bool operator==( const timerEventItem &right ) const
{
return ( UTCtime == right.UTCtime
&& channel == right.channel
&& message == right.message
&& data == right.data );
}
};
class TimerReceiverObject : public QObject
{
public:
TimerReceiverObject()
{ }
~TimerReceiverObject()
{ }
void resetTimer();
void setTimerEventItem();
void deleteTimer();
protected:
void timerEvent( QTimerEvent *te );
#ifdef USE_ATD
private:
QString atfilename;
#endif
};
TimerReceiverObject *timerEventReceiver = NULL;
QList<timerEventItem> timerEventList;
timerEventItem *nearestTimerEvent = NULL;
// set the timer to go off on the next event in the list
void setNearestTimerEvent()
{
nearestTimerEvent = NULL;
QListIterator<timerEventItem> it( timerEventList );
if ( *it )
nearestTimerEvent = *it;
for ( ; *it; ++it )
if ( (*it)->UTCtime < nearestTimerEvent->UTCtime )
nearestTimerEvent = *it;
if (nearestTimerEvent)
timerEventReceiver->resetTimer();
else
timerEventReceiver->deleteTimer();
}
//store current state to file
//Simple implementation. Should run on a timer.
static void saveState()
{
QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
if ( timerEventList.isEmpty() ) {
unlink( savefilename );
return ;
}
QFile savefile(savefilename + ".new");
if ( savefile.open(IO_WriteOnly) ) {
QDataStream ds( &savefile );
//save
QListIterator<timerEventItem> it( timerEventList );
for ( ; *it; ++it ) {
ds << it.current()->UTCtime;
ds << it.current()->channel;
ds << it.current()->message;
ds << it.current()->data;
}
savefile.close();
unlink( savefilename );
QDir d;
d.rename(savefilename + ".new", savefilename);
}
}
/*!
Sets up the alarm server. Restoring to previous state (session management).
*/
void AlarmServer::initialize()
{
//read autosave file and put events in timerEventList
QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
QFile savefile(savefilename);
if ( savefile.open(IO_ReadOnly) ) {
QDataStream ds( &savefile );
while ( !ds.atEnd() ) {
timerEventItem *newTimerEventItem = new timerEventItem;
ds >> newTimerEventItem->UTCtime;
ds >> newTimerEventItem->channel;
ds >> newTimerEventItem->message;
ds >> newTimerEventItem->data;
timerEventList.append( newTimerEventItem );
}
savefile.close();
if (!timerEventReceiver)
timerEventReceiver = new TimerReceiverObject;
setNearestTimerEvent();
}
}
#ifdef USE_ATD
static const char* atdir = "/var/spool/at/";
static bool triggerAtd( bool writeHWClock = FALSE )
{
QFile trigger(QString(atdir) + "trigger");
if ( trigger.open(IO_WriteOnly | IO_Raw) ) {
if ( trigger.writeBlock("\n", 2) != 2 ) {
QMessageBox::critical( 0, QObject::tr( "Out of Space" ),
QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) );
trigger.close();
QFile::remove
( trigger.name() );
return FALSE;
}
return TRUE;
}
return FALSE;
}
#else
static bool writeResumeAt ( time_t wakeup )
{
FILE *fp = ::fopen ( "/var/run/resumeat", "w" );
if ( fp ) {
::fprintf ( fp, "%d\n", (int) wakeup );
::fclose ( fp );
}
else
qWarning ( "Failed to write wakeup time to /var/run/resumeat" );
return ( fp );
}
#endif
void TimerReceiverObject::deleteTimer()
{
#ifdef USE_ATD
if ( !atfilename.isEmpty() ) {
unlink( atfilename );
atfilename = QString::null;
triggerAtd( FALSE );
}
#else
writeResumeAt ( 0 );
#endif
}
void TimerReceiverObject::resetTimer()
{
const int maxsecs = 2147000;
QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime);
QDateTime now = QDateTime::currentDateTime();
if ( nearest < now )
nearest = now;
int secs = TimeConversion::secsTo( now, nearest );
if ( secs > maxsecs ) {
// too far for millisecond timing
secs = maxsecs;
}
// System timer (needed so that we wake from deep sleep),
// from the Epoch in seconds.
//
int at_secs = TimeConversion::toUTC(nearest);
// qDebug("reset timer to %d seconds from Epoch",at_secs);
#ifdef USE_ATD
QString fn = atdir + QString::number(at_secs) + "."
+ QString::number(getpid());
if ( fn != atfilename ) {
QFile atfile(fn + ".new");
if ( atfile.open(IO_WriteOnly | IO_Raw) ) {
int total_written;
// just wake up and delete the at file
QString cmd = "#!/bin/sh\nrm " + fn;
total_written = atfile.writeBlock(cmd.latin1(), cmd.length());
if ( total_written != int(cmd.length()) ) {
QMessageBox::critical( 0, tr("Out of Space"),
tr("Unable to schedule alarm.\n"
"Please free up space and try again") );
atfile.close();
QFile::remove
( atfile.name() );
return ;
}
atfile.close();
unlink( atfilename );
QDir d;
d.rename(fn + ".new", fn);
chmod(fn.latin1(), 0755);
atfilename = fn;
triggerAtd( FALSE );
}
else {
qWarning("Cannot open atd file %s", fn.latin1());
}
}
#else
writeResumeAt ( at_secs );
#endif
// Qt timers (does the actual alarm)
// from now in milliseconds
//
qDebug("AlarmServer waiting %d seconds", secs);
startTimer( 1000 * secs + 500 );
}
void TimerReceiverObject::timerEvent( QTimerEvent * )
{
bool needSave = FALSE;
killTimers();
if (nearestTimerEvent) {
if ( nearestTimerEvent->UTCtime
<= TimeConversion::toUTC(QDateTime::currentDateTime()) ) {
#ifndef QT_NO_COP
QCopEnvelope e( nearestTimerEvent->channel,
nearestTimerEvent->message );
e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime )
<< nearestTimerEvent->data;
#endif
timerEventList.remove( nearestTimerEvent );
needSave = TRUE;
}
setNearestTimerEvent();
}
else {
resetTimer();
}
if ( needSave )
saveState();
}
/*!
\class AlarmServer alarmserver.h
\brief The AlarmServer class allows alarms to be scheduled and unscheduled.
Applications can schedule alarms with addAlarm() and can
unschedule alarms with deleteAlarm(). When the time for an alarm
to go off is reached the specified \link qcop.html QCop\endlink
message is sent on the specified channel (optionally with
additional data).
Scheduling an alarm using this class is important (rather just using
a QTimer) since the machine may be asleep and needs to get woken up using
the Linux kernel which implements this at the kernel level to minimize
battery usage while asleep.
A small example on how to use AlarmServer.
First we need to connect a slot the AppMessage QCOP call. appMessage
will be emitted if QPE/Application/appname gets called.
\code
TestApp::TestApp(QWidget *parent, const char* name, WFlags fl )
: QMainWindow(parent,name,fl){
connect(qApp,SIGNAL(appMessage(const QCString&,const QByteArray&)),
this,SLOT(slotAppMessage(const QCString&,const QByteArray&)));
}
\endcode
To add / delete an alarm, you can use the static method AlarmServer::addAlarm and
AlarmServer::deleteAlarm. Note that an old (expired) alarm will automatically be deleted
from the alarmserver list, but a change in timing will have the effect, that both
alarms will be emitted. So if you change an Alarm be sure to delete the old one!
@see addAlarm
\code
QDateTime oldDt = oldAlarmDateTime();
QPEApplication::execDialog(ourDlg);
QDateTime newDt = ourDlg->dateTime();
if(newDt == oldDt ) return;
@slash* code is missing for unsetting an alarm *@slash
AlarmServer::deleteAlarm(oldDt,"QPE/Application/appname","checkAlarm(QDateTime,int)",0);
AlarmServer::addAlarm( newDt,"QPE/AlarmServer/appname","checkAlarm(QDateTime,int)",0);
\endcode
Now once the Alarm is emitted you need to check the appMessage and then do what you want.
\code
void TestApp::slotAppMessage(const QCString& str, const QByteArray& ar ){
QDataStream stream(ar,IO_ReadOnly);
if(str == "checkAlarm(QDateTime,int)" ){
QDateTime dt;
int a;
stream >> dt >> a;
// fire up alarm
}
}
\endcode
\ingroup qtopiaemb
\sa QCopEnvelope
@see QPEApplication::appMessage(const QCString&,const QByteArray&)
@see OPimMainWindow
@see ODevice::alarmSound()
@see Sound::soundAlarm()
*/
/*!
Schedules an alarm to go off at (or soon after) time \a when. When
the alarm goes off, the \link qcop.html QCop\endlink \a message will
be sent to \a channel, with \a data as a parameter.
If this function is called with exactly the same data as a previous
call the subsequent call is ignored, so there is only ever one alarm
with a given set of parameters.
Once an alarm is emitted. The \a channel with a \a message will be emitted
and data will be send.
The QDateTime and int are the two parameters included in the QCOP message.
You can specify channel, message and the integer parameter. QDateTime will be
the datetime of the QCop call.
@param when The QDateTime of the alarm
@param channel The channel which gets called once the alarm is emitted
@param message The message to be send to the channel
@param data Additional data as integer
@see QCopChannel
\sa deleteAlarm()
*/
void AlarmServer::addAlarm ( QDateTime when, const QCString& channel,
const QCString& message, int data)
{
if ( qApp->type() == QApplication::GuiServer ) {
bool needSave = FALSE;
// Here we are the server so either it has been directly called from
// within the server or it has been sent to us from a client via QCop
if (!timerEventReceiver)
timerEventReceiver = new TimerReceiverObject;
timerEventItem *newTimerEventItem = new timerEventItem;
newTimerEventItem->UTCtime = TimeConversion::toUTC( when );
newTimerEventItem->channel = channel;
newTimerEventItem->message = message;
newTimerEventItem->data = data;
// explore the case of already having the event in here...
QListIterator<timerEventItem> it( timerEventList );
for ( ; *it; ++it )
if ( *(*it) == *newTimerEventItem )
return ;
// if we made it here, it is okay to add the item...
timerEventList.append( newTimerEventItem );
needSave = TRUE;
// quicker than using setNearestTimerEvent()
if ( nearestTimerEvent ) {
if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) {
nearestTimerEvent = newTimerEventItem;
timerEventReceiver->killTimers();
timerEventReceiver->resetTimer();
}
}
else {
nearestTimerEvent = newTimerEventItem;
timerEventReceiver->resetTimer();
}
if ( needSave )
saveState();
}
else {
#ifndef QT_NO_COP
QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" );
e << when << channel << message << data;
#endif
}
}
/*!
Deletes previously scheduled alarms which match \a when, \a channel,
\a message, and \a data.
Passing null values for \a when, \a channel, or for the \link
qcop.html QCop\endlink \a message, acts as a wildcard meaning "any".
Similarly, passing -1 for \a data indicates "any".
If there is no matching alarm, nothing happens.
\sa addAlarm()
*/
void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data)
{
if ( qApp->type() == QApplication::GuiServer) {
bool needSave = FALSE;
if ( timerEventReceiver != NULL ) {
timerEventReceiver->killTimers();
// iterate over the list of events
QListIterator<timerEventItem> it( timerEventList );
time_t deleteTime = TimeConversion::toUTC( when );
for ( ; *it; ++it ) {
// if its a match, delete it
if ( ( (*it)->UTCtime == deleteTime || when.isNull() )
&& ( channel.isNull() || (*it)->channel == channel )
&& ( message.isNull() || (*it)->message == message )
&& ( data == -1 || (*it)->data == data ) ) {
// if it's first, then we need to update the timer
if ( (*it) == nearestTimerEvent ) {
timerEventList.remove(*it);
setNearestTimerEvent();
}
else {
timerEventList.remove(*it);
}
needSave = TRUE;
}
}
if ( nearestTimerEvent )
timerEventReceiver->resetTimer();
}
if ( needSave )
saveState();
}
else {
#ifndef QT_NO_COP
QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" );
e << when << channel << message << data;
#endif
}
}
/*!
The implementation depends on the mode of AlarmServer. If the AlarmServer
uses atd the current system time will be written to the hardware clock.
If the AlarmServer relies on opie-alarm the time will be written once the
device gets suspended. opie-alarm is used by the Zaurus, iPAQs and SIMpad
*/
void Global::writeHWClock()
{
#ifdef USE_ATD
if ( !triggerAtd( TRUE ) ) {
// atd not running? set it ourselves
system("/sbin/hwclock --systohc"); // ##### UTC?
}
#else
// hwclock is written on suspend
#endif
}
diff --git a/library/applnk.cpp b/library/applnk.cpp
index e9d519e..1c1a227 100644
--- a/library/applnk.cpp
+++ b/library/applnk.cpp
@@ -1,1496 +1,1497 @@
/**********************************************************************
** 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.
**
**********************************************************************/
#define QTOPIA_INTERNAL_MIMEEXT
#define QTOPIA_INTERNAL_PRELOADACCESS
#define QTOPIA_INTERNAL_APPLNKASSIGN
#include "applnk.h"
#include <qpe/qpeapplication.h>
#include <qpe/categories.h>
#include <qpe/categoryselect.h>
+#include <qpe/global.h>
#include <qpe/qcopenvelope_qws.h>
#include <qpe/mimetype.h>
#include <qpe/config.h>
#include <qpe/storage.h>
#include <qpe/resource.h>
#include <qdir.h>
#include <stdlib.h>
int AppLnk::lastId = 5000;
static int smallSize = 14;
static int bigSize = 32;
static QString safeFileName(const QString& n)
{
QString safename=n;
safename.replace(QRegExp("[^0-9A-Za-z.]"),"_");
safename.replace(QRegExp("^[^A-Za-z]*"),"");
if ( safename.isEmpty() )
safename = "_";
return safename;
}
static bool prepareDirectories(const QString& lf)
{
if ( !QFile::exists(lf) ) {
// May need to create directories
QFileInfo fi(lf);
if ( system(("mkdir -p "+fi.dirPath(TRUE))) )
return FALSE;
}
return TRUE;
}
class AppLnkPrivate
{
public:
/* the size of the Pixmap */
enum Size {Normal = 0, Big };
AppLnkPrivate() {
/* we want one normal and one big item */
QPixmap pix;
mPixmaps.insert(0, pix );
mPixmaps.insert(1, pix);
}
QStringList mCatList; // always correct
QArray<int> mCat; // cached value; correct if not empty
QMap<int, QPixmap> mPixmaps;
void updateCatListFromArray()
{
Categories cat( 0 );
cat.load( categoryFileName() );
// we need to update the names for the mCat... to mCatList
mCatList.clear();
for (uint i = 0; i < mCat.count(); i++ )
mCatList << cat.label("Document View", mCat[i] );
}
void setCatArrayDirty()
{
mCat.resize(0);
}
void ensureCatArray()
{
if ( mCat.count() > 0 || mCatList.count()==0 )
return;
Categories cat( 0 );
cat.load( categoryFileName() );
mCat.resize( mCatList.count() );
int i;
QStringList::ConstIterator it;
for ( i = 0, it = mCatList.begin(); it != mCatList.end();
++it, i++ ) {
bool number;
int id = (*it).toInt( &number );
if ( !number ) {
id = cat.id( "Document View", *it );
if ( id == 0 )
id = cat.addCategory( "Document View", *it );
}
mCat[i] = id;
}
}
};
/*!
\class AppLnk applnk.h
\brief The AppLnk class represents an application available on the system.
Every Qtopia application \e app has a corresponding \e app.desktop
file. When one of these files is read its data is stored as an
AppLnk object.
The AppLnk class introduces some Qtopia-specific concepts, and
provides a variety of functions, as described in the following
sections.
\tableofcontents
\target Types
\section1 Types
Every AppLnk object has a \e type. For applications, games and
settings the type is \c Application; for documents the
type is the document's MIME type.
\target files-and-links
\section1 Files and Links
When you create an AppLnk (or more likely, a \link doclnk.html
DocLnk\endlink), you don't deal directly with filenames in the
filesystem. Instead you do this:
\code
DocLnk d;
d.setType("text/plain");
d.setName("My Nicely Named Document / Whatever"); // Yes, "/" is legal.
\endcode
At this point, the file() and linkFile() are unknown. Normally
this is uninteresting, and the names become automatically known,
and more importantly, becomes reserved, when you ask what they are:
\code
QString fn = d.file();
\endcode
This invents a filename, and creates the file on disk (an empty
reservation file) to prevent the name being used by another
application.
In some circumstances, you don't want to create the file if it
doesn't already exist (e.g. in the Document tab, some of the \link
doclnk.html DocLnk\endlink objects represented by icons are
DocLnk's created just for that view - they don't have
corresponding \c .desktop files. To avoid littering empty
reservation files around, we check in a few places to see whether
the file really needs to exist).
\section1 Functionality
AppLnk objects are created by calling the constructor with the
name of a \e .desktop file. The object can be checked for validity
using isValid().
The following functions are used to set or retrieve information
about the application:
\table
\header \i Get Function \i Set Function \i Short Description
\row \i \l name() \i \l setName() \i application's name
\row \i \l pixmap() \i \e none \i application's icon
\row \i \l bigPixmap() \i \e none \i application's large icon
\row \i \e none \i setIcon() \i sets the icon's filename
\row \i \l type() \i \l setType() \i see \link #Types Types\endlink above
\row \i \l rotation() \i \e none \i 0, 90, 180 or 270 degrees
\row \i \l comment() \i \l setComment() \i text for the Details dialog
\row \i \l exec() \i \l setExec() \i executable's filename
\row \i \l file() \i \e none \i document's filename
\row \i \l linkFile() \i \l setLinkFile() \i \e .desktop filename
\row \i \l mimeTypes() \i \e none \i the mime types the application can view or edit
\row \i \l categories() \i \l setCategories() \i \e{see the function descriptions}
\row \i \l fileKnown() \i \e none \i see \link
#files-and-links Files and Links\endlink above
\row \i \l linkFileKnown() \i \e none \i see \link
#files-and-links Files and Links\endlink above
\row \i \l property() \i \l setProperty() \i any AppLnk property
can be retrieved or set (if writeable) using these
\endtable
To save an AppLnk to disk use writeLink(). To execute the
application that the AppLnk object refers to, use execute().
AppLnk's can be deleted from disk using removeLinkFile(). To
remove both the link and the application's executable use
removeFiles().
Icon sizes can be globally changed (but only for AppLnk objects
created after the calls) with setSmallIconSize() and
setBigIconSize().
\ingroup qtopiaemb
*/
/*!
Sets the size used for small icons to \a small pixels.
Only affects AppLnk objects created after the call.
\sa smallIconSize() setIcon()
*/
void AppLnk::setSmallIconSize(int small)
{
smallSize = small;
}
/*!
Returns the size used for small icons.
\sa setSmallIconSize() setIcon()
*/
int AppLnk::smallIconSize()
{
return smallSize;
}
/*!
Sets the size used for large icons to \a big pixels.
Only affects AppLnk objects created after the call.
\sa bigIconSize() setIcon()
*/
void AppLnk::setBigIconSize(int big)
{
bigSize = big;
}
/*!
Returns the size used for large icons.
\sa setBigIconSize() setIcon()
*/
int AppLnk::bigIconSize()
{
return bigSize;
}
/*!
\fn QString AppLnk::name() const
Returns the Name property. This is the user-visible name for the
document or application, not the filename.
See \link #files-and-links Files and Links\endlink.
\sa setName()
*/
/*!
\fn QString AppLnk::exec() const
Returns the Exec property. This is the name of the executable
program associated with the AppLnk.
\sa setExec()
*/
/*!
\fn QString AppLnk::rotation() const
Returns the Rotation property. The value is 0, 90, 180 or 270
degrees.
*/
/*!
\fn QString AppLnk::comment() const
Returns the Comment property.
\sa setComment()
*/
/*!
\fn QStringList AppLnk::mimeTypes() const
Returns the MimeTypes property. This is the list of MIME types
that the application can view or edit.
*/
/*!
\fn const QArray<int>& AppLnk::categories() const
Returns the Categories property.
See the CategoryWidget for more details.
\sa setCategories()
*/
const QArray<int>& AppLnk::categories() const
{
d->ensureCatArray();
return d->mCat;
}
/*!
\fn int AppLnk::id() const
Returns the id of the AppLnk. If the AppLnk is not in an AppLnkSet,
this value is 0, otherwise it is a value that is unique for the
duration of the current process.
\sa AppLnkSet::find()
*/
/*!
\fn bool AppLnk::isValid() const
Returns TRUE if this AppLnk is valid; otherwise returns FALSE.
*/
/*!
\fn bool AppLnk::fileKnown() const
If the with the AppLnk associated file is not equal to QString::null
*/
/*!
\fn bool AppLnk::linkFileKnown()const
The filename of the AppLnk
*/
/*!
\fn void AppLnk::setRotation( const QString& )
The default rotation of the associated application. This
function is included inline for binary compatible issues
*/
/*!
Creates an invalid AppLnk.
\sa isValid()
*/
AppLnk::AppLnk()
{
mId = 0;
d = new AppLnkPrivate();
}
/*!
Loads \a file (e.g. \e app.desktop) as an AppLnk.
\sa writeLink()
*/
AppLnk::AppLnk( const QString &file )
{
QStringList sl;
d = new AppLnkPrivate();
if ( !file.isNull() ) {
Config config( file, Config::File );
if ( config.isValid() ) {
config.setGroup( "Desktop Entry" );
mName = config.readEntry( "Name", file );
mExec = config.readEntry( "Exec" );
mType = config.readEntry( "Type", QString::null );
mIconFile = config.readEntry( "Icon", QString::null );
mRotation = config.readEntry( "Rotation", "" );
mComment = config.readEntry( "Comment", QString::null );
// MIME types are case-insensitive.
mMimeTypes = config.readListEntry( "MimeType", ';' );
for (QStringList::Iterator it=mMimeTypes.begin(); it!=mMimeTypes.end(); ++it)
*it = (*it).lower();
mMimeTypeIcons = config.readListEntry( "MimeTypeIcons", ';' );
mLinkFile = file;
mFile = config.readEntry("File", QString::null);
if ( !mExec. isEmpty ( )) {
mFile = QString::null;
}
else if ( mFile[0] != '/' ) {
int slash = file.findRev('/');
if ( slash >= 0 ) {
mFile = file.left(slash) + '/' + mFile;
}
}
d->mCatList = config.readListEntry("Categories", ';');
if ( d->mCatList[0].toInt() < -1 ) {
// numeric cats in file! convert to text
Categories cat( 0 );
cat.load( categoryFileName() );
d->mCat.resize( d->mCatList.count() );
int i;
QStringList::ConstIterator it;
for ( i = 0, it = d->mCatList.begin(); it != d->mCatList.end();
++it, i++ ) {
bool number;
int id = (*it).toInt( &number );
if ( !number ) {
// convert from text
id = cat.id( "Document View", *it );
if ( id == 0 )
id = cat.addCategory( "Document View", *it );
}
d->mCat[i] = id;
}
d->updateCatListFromArray();
}
}
}
mId = 0;
}
AppLnk& AppLnk::operator=(const AppLnk &copy)
{
if ( this == &copy ) return *this;
if ( mId )
qWarning("Deleting AppLnk that is in an AppLnkSet");
if ( d )
delete d;
mName = copy.mName;
/* remove for Qtopia 3.0 -zecke */
mPixmap = copy.mPixmap;
mBigPixmap = copy.mBigPixmap;
mExec = copy.mExec;
mType = copy.mType;
mRotation = copy.mRotation;
mComment = copy.mComment;
mFile = copy.mFile;
mLinkFile = copy.mLinkFile;
mIconFile = copy.mIconFile;
mMimeTypes = copy.mMimeTypes;
mMimeTypeIcons = copy.mMimeTypeIcons;
mId = 0;
d = new AppLnkPrivate();
d->mCat = copy.d->mCat;
d->mCatList = copy.d->mCatList;
d->mPixmaps = copy.d->mPixmaps;
return *this;
}
/*!
protected internally to share code
should I document that at all?
I don't know the TT style for that
*/
const QPixmap& AppLnk::pixmap( int pos, int size ) const {
if ( d->mPixmaps[pos].isNull() ) {
AppLnk* that = (AppLnk*)this;
if ( mIconFile.isEmpty() ) {
MimeType mt(type());
that->d->mPixmaps[pos] = pos ? mt.bigPixmap() : mt.pixmap();
if ( that->d->mPixmaps[pos].isNull() )
that->d->mPixmaps[pos].convertFromImage(
Resource::loadImage("UnknownDocument")
.smoothScale( size, size ) );
return that->d->mPixmaps[pos];
}
QImage unscaledIcon = Resource::loadImage( that->mIconFile );
if ( unscaledIcon.isNull() ) {
// qDebug( "Cannot find icon: %s", that->mIconFile.latin1() );
that->d->mPixmaps[pos].convertFromImage(
Resource::loadImage("UnknownDocument")
.smoothScale( size, size ) );
} else {
that->d->mPixmaps[0].convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
that->d->mPixmaps[1].convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
}
return that->d->mPixmaps[pos];
}
return d->mPixmaps[pos];
}
/*!
Returns a small pixmap associated with the application.
\sa bigPixmap() setIcon()
*/
const QPixmap& AppLnk::pixmap() const
{
if ( d->mPixmaps[0].isNull() ) {
return pixmap(AppLnkPrivate::Normal, smallSize );
}
return d->mPixmaps[0];
}
/*!
Returns a large pixmap associated with the application.
\sa pixmap() setIcon()
*/
const QPixmap& AppLnk::bigPixmap() const
{
if ( d->mPixmaps[1].isNull() ) {
return pixmap( AppLnkPrivate::Big, bigSize );
}
return d->mPixmaps[1];
}
/*!
Returns the type of the AppLnk. For applications, games and
settings the type is \c Application; for documents the type is the
document's MIME type.
*/
QString AppLnk::type() const
{
if ( mType.isNull() ) {
AppLnk* that = (AppLnk*)this;
QString f = file();
if ( !f.isNull() ) {
MimeType mt(f);
that->mType = mt.id();
return that->mType;
}
}
return mType;
}
/*!
Returns the file associated with the AppLnk.
\sa exec() name()
*/
QString AppLnk::file() const
{
if ( mExec.isEmpty ( ) && mFile.isNull() ) {
AppLnk* that = (AppLnk*)this;
QString ext = MimeType(mType).extension();
if ( !ext.isEmpty() )
ext = "." + ext;
if ( !mLinkFile.isEmpty() ) {
that->mFile =
mLinkFile.right(8)==".desktop" // 8 = strlen(".desktop")
? mLinkFile.left(mLinkFile.length()-8) : mLinkFile;
qDebug("mFile now == %s", mFile.latin1());
} else if ( mType.contains('/') ) {
that->mFile =
QString(getenv("HOME"))+"/Documents/"+mType+"/"+safeFileName(that->mName);
/*
* A file with the same name or a .desktop file already exists
*/
if ( QFile::exists(that->mFile+ext) || QFile::exists(that->mFile+".desktop") ) {
int n=1;
QString nn;
while (QFile::exists((nn=(that->mFile+"_"+QString::number(n)))+ext)
|| QFile::exists(nn+".desktop"))
n++;
that->mFile = nn;
}
that->mLinkFile = that->mFile+".desktop";
that->mFile += ext;
}
prepareDirectories(that->mFile);
if ( !that->mFile.isEmpty() ) {
QFile f(that->mFile);
if ( !f.open(IO_WriteOnly) )
that->mFile = QString::null;
return that->mFile;
}
}
return mFile;
}
/*!
Returns the desktop file corresponding to this AppLnk.
\sa file() exec() name()
*/
QString AppLnk::linkFile() const
{
if ( mLinkFile.isNull() ) {
AppLnk* that = (AppLnk*)this;
if ( type().contains('/') ) {
StorageInfo storage;
const FileSystem *fs = storage.fileSystemOf( that->mFile );
/* tmpfs + and ramfs are available too but not removable
* either we fix storage or add this
*/
if ( fs && ( fs->isRemovable() || fs->disk() == "/dev/mtdblock6" || fs->disk() == "tmpfs") ) {
that->mLinkFile = fs->path();
} else
that->mLinkFile = getenv( "HOME" );
that->mLinkFile += "/Documents/"+type()+"/"+safeFileName(that->mName);
/* the desktop file exists make sure we don't point to the same file */
if ( QFile::exists(that->mLinkFile+".desktop") ) {
AppLnk lnk( that->mLinkFile + ".desktop" );
/* the linked is different */
if(that->file() != lnk.file() ) {
int n = 1;
QString nn;
while (QFile::exists((nn=that->mLinkFile+"_"+QString::number(n))+".desktop")) {
n++;
/* just to be sure */
AppLnk lnk(nn );
if (lnk.file() == that->file() )
break;
}
that->mLinkFile = nn;
}
}
that->mLinkFile += ".desktop";
storeLink();
}
return that->mLinkFile;
}
return mLinkFile;
}
/*!
Copies \a copy.
*/
AppLnk::AppLnk( const AppLnk &copy )
{
mName = copy.mName;
mPixmap = copy.mPixmap;
mBigPixmap = copy.mBigPixmap;
mExec = copy.mExec;
mType = copy.mType;
mRotation = copy.mRotation;
mComment = copy.mComment;
mFile = copy.mFile;
mLinkFile = copy.mLinkFile;
mIconFile = copy.mIconFile;
mMimeTypes = copy.mMimeTypes;
mMimeTypeIcons = copy.mMimeTypeIcons;
mId = 0;
d = new AppLnkPrivate();
d->mCat = copy.d->mCat;
d->mCatList = copy.d->mCatList;
d->mPixmaps = copy.d->mPixmaps;
}
/*!
Destroys the AppLnk. Note that if the AppLnk is currently a member
of an AppLnkSet, this will produce a run-time warning.
\sa AppLnkSet::add() AppLnkSet::remove()
*/
AppLnk::~AppLnk()
{
if ( mId )
qWarning("Deleting AppLnk that is in an AppLnkSet");
if ( d )
delete d;
}
/*!
\overload
Executes the application associated with this AppLnk.
\sa exec()
*/
void AppLnk::execute() const
{
execute( QStringList::split( ' ', property( "Arguments" ) ) );
}
/*!
Executes the application associated with this AppLnk, with
\a args as arguments.
\sa exec()
*/
void AppLnk::execute(const QStringList& args) const
{
#ifdef Q_WS_QWS
if ( !mRotation.isEmpty() ) {
// ######## this will only work in the server
int rot = QPEApplication::defaultRotation();
rot = (rot+mRotation.toInt())%360;
QCString old = getenv("QWS_DISPLAY");
setenv("QWS_DISPLAY", QString("Transformed:Rot%1:0").arg(rot), 1);
invoke(args);
setenv("QWS_DISPLAY", old.data(), 1);
} else
#endif
invoke(args);
}
/*!
Invokes the application associated with this AppLnk, with
\a args as arguments. Rotation is not taken into account by
this function, so you should not call it directly.
\sa execute()
*/
void AppLnk::invoke(const QStringList& args) const
{
if ( property( "Arguments" ).isEmpty() )
Global::execute( exec(), args[0] );
else
Global::execute( exec(), args.join( " " ) );
}
/*!
Sets the Exec property to \a exec.
\sa exec() name()
*/
void AppLnk::setExec( const QString& exec )
{
mExec = exec;
}
#if 0 // this was inlined for better BC
/*!
Sets the Rotation property to \a rot.
\sa rotation()
*/
void AppLnk::setRotation ( const QString &rot )
{
mRotation = rot;
}
#endif
/*!
Sets the Name property to \a docname.
\sa name()
*/
void AppLnk::setName( const QString& docname )
{
mName = docname;
}
/*!
Sets the File property to \a filename.
\sa file() name()
*/
void AppLnk::setFile( const QString& filename )
{
mFile = filename;
}
/*!
Sets the LinkFile property to \a filename.
\sa linkFile()
*/
void AppLnk::setLinkFile( const QString& filename )
{
mLinkFile = filename;
}
/*!
Sets the Comment property to \a comment.
This text is displayed in the 'Details Dialog', for example if the
user uses the 'press-and-hold' gesture.
\sa comment()
*/
void AppLnk::setComment( const QString& comment )
{
mComment = comment;
}
/*!
Sets the Type property to \a type.
For applications, games and settings the type should be \c
Application; for documents the type should be the document's MIME
type.
\sa type()
*/
void AppLnk::setType( const QString& type )
{
mType = type;
}
/*!
\fn QString AppLnk::icon() const
Returns the Icon property.
\sa setIcon()
*/
/*!
Sets the Icon property to \a iconname. This is the filename from
which the pixmap() and bigPixmap() are obtained.
\sa icon() setSmallIconSize() setBigIconSize()
*/
void AppLnk::setIcon( const QString& iconname )
{
mIconFile = iconname;
QImage unscaledIcon = Resource::loadImage( mIconFile );
d->mPixmaps[0].convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
d->mPixmaps[1].convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
}
/*!
Sets the Categories property to \a c.
See the CategoryWidget for more details.
\sa categories()
*/
void AppLnk::setCategories( const QArray<int>& c )
{
d->mCat = c;
d->updateCatListFromArray();
}
/*!
\fn QStringList AppLnk::mimeTypeIcons() const
Returns the MimeTypeIcons property of the AppLnk.
*/
/*!
Attempts to ensure that the link file for this AppLnk exists,
including creating any required directories. Returns TRUE if
successful; otherwise returns FALSE.
You should not need to use this function.
*/
bool AppLnk::ensureLinkExists() const
{
QString lf = linkFile();
return prepareDirectories(lf);
}
/*!
Commits the AppLnk to disk. Returns TRUE if the operation succeeded;
otherwise returns FALSE.
In addition, the "linkChanged(QString)" message is sent to the
"QPE/System" \link qcop.html QCop\endlink channel.
*/
bool AppLnk::writeLink() const
{
// Only re-writes settable parts
QString lf = linkFile();
if ( !ensureLinkExists() )
return FALSE;
storeLink();
return TRUE;
}
/*!
\internal
*/
void AppLnk::storeLink() const
{
Config config( mLinkFile, Config::File );
config.setGroup("Desktop Entry");
config.writeEntry("Name",mName);
if ( !mIconFile.isNull() ) config.writeEntry("Icon",mIconFile);
config.writeEntry("Type",type());
if(!rotation().isEmpty())
config.writeEntry("Rotation",rotation());
else
config.removeEntry("Rotation");
if ( !mComment.isNull() ) config.writeEntry("Comment",mComment);
QString f = file();
int i = 0;
while ( i < (int)f.length() && i < (int)mLinkFile.length() && f[i] == mLinkFile[i] )
i++;
while ( i && f[i] != '/' )
i--;
// simple case where in the same directory
if ( mLinkFile.find( '/', i + 1 ) < 0 )
f = f.mid(i+1);
// ### could do relative ie ../../otherDocs/file.doc
config.writeEntry("File",f);
config.writeEntry( "Categories", d->mCatList, ';' );
#ifndef QT_NO_COP
QCopEnvelope e("QPE/System", "linkChanged(QString)");
e << mLinkFile;
#endif
}
/*!
Sets the property named \a key to \a value.
\sa property()
*/
void AppLnk::setProperty(const QString& key, const QString& value)
{
if ( ensureLinkExists() ) {
Config cfg(linkFile(), Config::File);
cfg.writeEntry(key,value);
}
}
/*!
Returns the property named \a key.
\sa setProperty()
*/
QString AppLnk::property(const QString& key) const
{
QString lf = linkFile();
if ( !QFile::exists(lf) )
return QString::null;
Config cfg(lf, Config::File);
return cfg.readEntry(key);
}
bool AppLnk::isPreloaded() const {
// Preload information is stored in the Launcher config in v1.5.
Config cfg("Launcher");
cfg.setGroup("Preload");
QStringList apps = cfg.readListEntry("Apps",',');
if (apps.contains(exec()))
return true;
return false;
}
void AppLnk::setPreloaded(bool yesNo) {
// Preload information is stored in the Launcher config in v1.5.
Config cfg("Launcher");
cfg.setGroup("Preload");
QStringList apps = cfg.readListEntry("Apps", ',');
if (apps.contains(exec()) && !yesNo)
apps.remove(exec());
else if (yesNo && !apps.contains(exec()))
apps.append(exec());
cfg.writeEntry("Apps", apps, ',');
}
/*!
Deletes both the linkFile() and the file() associated with this AppLnk.
\sa removeLinkFile()
*/
void AppLnk::removeFiles()
{
bool valid = isValid();
if ( !valid || !linkFileKnown() || QFile::remove(linkFile()) ) {
if ( QFile::remove(file()) ) {
#ifndef QT_NO_COP
QCopEnvelope e("QPE/System", "linkChanged(QString)");
if ( linkFileKnown() )
e << linkFile();
else
e << file();
#endif
} else if ( valid ) {
// restore link
writeLink();
}
}
}
/*!
Deletes the linkFile(), leaving any file() untouched.
\sa removeFiles()
*/
void AppLnk::removeLinkFile()
{
if ( isValid() && linkFileKnown() && QFile::remove(linkFile()) ) {
#ifndef QT_NO_COP
QCopEnvelope e("QPE/System", "linkChanged(QString)");
e << linkFile();
#endif
}
}
class AppLnkSetPrivate {
public:
AppLnkSetPrivate()
{
typPix.setAutoDelete(TRUE);
typPixBig.setAutoDelete(TRUE);
typName.setAutoDelete(TRUE);
}
QDict<QPixmap> typPix;
QDict<QPixmap> typPixBig;
QDict<QString> typName;
};
/*!
\class AppLnkSet applnk.h
\brief The AppLnkSet class is a set of AppLnk objects.
*/
/*!
\fn QStringList AppLnkSet::types() const
Returns the list of \link applnk.html#Types types\endlink in the set.
For applications, games and settings the type is \c Application;
for documents the type is the document's MIME type.
\sa AppLnk::type(), typeName(), typePixmap(), typeBigPixmap()
*/
/*!
\fn const QList<AppLnk>& AppLnkSet::children() const
Returns the members of the set.
*/
/*!
Constructs an empty AppLnkSet.
*/
AppLnkSet::AppLnkSet() :
d(new AppLnkSetPrivate)
{
}
/*!
Constructs an AppLnkSet that contains AppLnk objects representing
all the files in the given \a directory (and any subdirectories
recursively).
\omit
The directories may contain ".directory" files which override
any AppLnk::type() values for AppLnk objects found in the directory.
This allows simple localization of application types.
\endomit
*/
AppLnkSet::AppLnkSet( const QString &directory ) :
d(new AppLnkSetPrivate)
{
QDir dir( directory );
mFile = directory;
findChildren(directory,QString::null,QString::null);
}
/*!
Detaches all AppLnk objects from the set. The set become empty and
the caller becomes responsible for deleting the AppLnk objects.
*/
void AppLnkSet::detachChildren()
{
QListIterator<AppLnk> it( mApps );
for ( ; it.current(); ) {
AppLnk* a = *it;
++it;
a->mId = 0;
}
mApps.clear();
}
/*!
Destroys the set, deleting all the AppLnk objects it contains.
\sa detachChildren()
*/
AppLnkSet::~AppLnkSet()
{
QListIterator<AppLnk> it( mApps );
for ( ; it.current(); ) {
AppLnk* a = *it;
++it;
a->mId = 0;
delete a;
}
delete d;
}
void AppLnkSet::findChildren(const QString &dr, const QString& typ, const QString& typName, int depth)
{
depth++;
if ( depth > 10 )
return;
QDir dir( dr );
QString typNameLocal = typName;
if ( dir.exists( ".directory" ) ) {
Config config( dr + "/.directory", Config::File );
config.setGroup( "Desktop Entry" );
typNameLocal = config.readEntry( "Name", typNameLocal );
if ( !typ.isEmpty() ) {
QString iconFile = config.readEntry( "Icon", "AppsIcon" );
QImage unscaledIcon = Resource::loadImage( iconFile );
QPixmap pm, bpm;
pm.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
bpm.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
d->typPix.insert(typ, new QPixmap(pm));
d->typPixBig.insert(typ, new QPixmap(bpm));
d->typName.insert(typ, new QString(typNameLocal));
}
}
const QFileInfoList *list = dir.entryInfoList();
if ( list ) {
QFileInfo* fi;
bool cadded=FALSE;
for ( QFileInfoListIterator it(*list); (fi=*it); ++it ) {
QString bn = fi->fileName();
// qDebug("findChildren "+bn);
if ( bn[0] != '.' && bn != "CVS" ) {
if ( fi->isDir() ) {
QString c = typ.isNull() ? bn : typ+"/"+bn;
QString d = typNameLocal.isNull() ? bn : typNameLocal+"/"+bn;
findChildren(fi->filePath(), c, d, depth );
} else {
if ( fi->extension(FALSE) == "desktop" ) {
AppLnk* app = new AppLnk( fi->filePath() );
#ifdef QT_NO_QWS_MULTIPROCESS
if ( !Global::isBuiltinCommand( app->exec() ) )
delete app;
else
#endif
{
if ( !typ.isEmpty() ) {
if ( !cadded ) {
typs.append(typ);
cadded = TRUE;
}
app->setType(typ);
}
add(app);
}
}
}
}
}
}
}
/*!
Adds AppLnk \a f to the set. The set takes responsibility for
deleting \a f.
\sa remove()
*/
void AppLnkSet::add( AppLnk *f )
{
if ( f->mId == 0 ) {
AppLnk::lastId++;
f->mId = AppLnk::lastId;
mApps.append( f );
} else {
qWarning("Attempt to add an AppLnk twice");
}
}
/*!
Removes AppLnk \a f to the set. The caller becomes responsible for
deleting \a f. Returns TRUE if \a f was in the set; otherwise
returns FALSE.
\sa add()
*/
bool AppLnkSet::remove( AppLnk *f )
{
if ( mApps.remove( f ) ) {
f->mId = 0;
return TRUE;
}
return FALSE;
}
/*!
Returns the localized name for type \a t.
For applications, games and settings the type is \c Application;
for documents the type is the document's MIME type.
*/
QString AppLnkSet::typeName( const QString& t ) const
{
QString *st = d->typName.find(t);
return st ? *st : QString::null;
}
/*!
Returns the small pixmap associated with type \a t.
For applications, games and settings the type is \c Application;
for documents the type is the document's MIME type.
*/
QPixmap AppLnkSet::typePixmap( const QString& t ) const
{
QPixmap *pm = d->typPix.find(t);
return pm ? *pm : QPixmap();
}
/*!
Returns the large pixmap associated with type \a t.
For applications, games and settings the type is \c Application;
for documents the type is the document's MIME type.
*/
QPixmap AppLnkSet::typeBigPixmap( const QString& t ) const
{
QPixmap *pm = d->typPixBig.find(t);
return pm ? *pm : QPixmap();
}
/*!
Returns the AppLnk with the given \a id.
*/
const AppLnk *AppLnkSet::find( int id ) const
{
QListIterator<AppLnk> it( children() );
for ( ; it.current(); ++it ) {
const AppLnk *app = it.current();
if ( app->id() == id )
return app;
}
return 0;
}
/*!
Returns the AppLnk with the given \a exec attribute.
*/
const AppLnk *AppLnkSet::findExec( const QString& exec ) const
{
QListIterator<AppLnk> it( children() );
for ( ; it.current(); ++it ) {
const AppLnk *app = it.current();
if ( app->exec() == exec )
return app;
}
return 0;
}
/*!
\class DocLnkSet applnk.h
\brief The DocLnkSet class is a set of DocLnk objects.
*/
/*!
\fn const QList<DocLnk>& DocLnkSet::children() const
Returns the members of the set.
*/
/*!
Constructs an empty DocLnkSet.
\sa appendFrom()
*/
DocLnkSet::DocLnkSet()
{
}
/*!
Constructs a DocLnkSet that contains DocLnk objects representing all
the files in the \a directory (and any subdirectories, recursively).
If \a mimefilter is not null,
only documents with a MIME type matching \a mimefilter are selected.
The value may contain multiple wild-card patterns separated by ";",
such as \c{*o/mpeg;audio/x-wav}.
See also \link applnk.html#files-and-links Files and Links\endlink.
*/
DocLnkSet::DocLnkSet( const QString &directory, const QString& mimefilter ) :
AppLnkSet()
{
QDir dir( directory );
mFile = dir.dirName();
QDict<void> reference(1021);
QStringList subFilter = QStringList::split(";", mimefilter);
QValueList<QRegExp> mimeFilters;
for( QStringList::Iterator it = subFilter.begin(); it != subFilter.end(); ++ it )
mimeFilters.append( QRegExp(*it, FALSE, TRUE) );
findChildren(directory, mimeFilters, reference);
const QList<DocLnk> &list = children();
for ( QListIterator<DocLnk> it( list ); it.current(); ++it ) {
reference.remove( (*it)->file() );
}
for ( QDictIterator<void> dit(reference); dit.current(); ++dit ) {
if ( dit.current() == (void*)2 ) {
// Unreferenced, make an unwritten link
DocLnk* dl = new DocLnk;
QFileInfo fi( dit.currentKey() );
dl->setFile(fi.filePath());
dl->setName(fi.baseName());
// #### default to current path?
// dl->setCategories( ... );
bool match = mimefilter.isNull();
if ( !match )
for( QValueList<QRegExp>::Iterator it = mimeFilters.begin(); it != mimeFilters.end() && !match; ++ it )
if ( (*it).match(dl->type()) >= 0 )
match = TRUE;
if ( match /* && dl->type() != "application/octet-stream" */
&& !!dl->exec() )
add(dl);
else
delete dl;
}
}
}
// other becomes empty
/*!
Transfers all DocLnk objects from \a other to this set. \a other becomes
empty.
*/
void DocLnkSet::appendFrom( DocLnkSet& other )
{
if ( &other == this )
return;
QListIterator<AppLnk> it( other.mApps );
for ( ; it.current(); ) {
mApps.append(*it);
++it;
}
other.mApps.clear();
}
void DocLnkSet::findChildren(const QString &dr, const QValueList<QRegExp> &mimeFilters, QDict<void> &reference, int depth)
{
depth++;
if ( depth > 10 )
return;
QDir dir( dr );
/* Opie got a different approach
* I guess it's geek vs. consumer
* in this case to be discussed
*/
if ( dir.exists( ".Qtopia-ignore" ) )
return;
const QFileInfoList *list = dir.entryInfoList();
if ( list ) {
QFileInfo* fi;
for ( QFileInfoListIterator it(*list); (fi=*it); ++it ) {
QString bn = fi->fileName();
if ( bn[0] != '.' ) {
if ( fi->isDir() ) {
if ( bn != "CVS" && bn != "Qtopia" && bn != "QtPalmtop" )
findChildren(fi->filePath(), mimeFilters, reference, depth);
} else {
if ( fi->extension(FALSE) == "desktop" ) {
DocLnk* dl = new DocLnk( fi->filePath() );
QFileInfo fi2(dl->file());
bool match = FALSE;
if ( !fi2.exists() ) {
dir.remove( dl->file() );
}
if ( mimeFilters.count() == 0 ) {
add( dl );
match = TRUE;
} else {
for( QValueList<QRegExp>::ConstIterator it = mimeFilters.begin(); it != mimeFilters.end(); ++ it ) {
if ( (*it).match(dl->type()) >= 0 ) {
add(dl);
match = TRUE;
}
}
}
if ( !match )
delete dl;
} else {
if ( !reference.find(fi->fileName()) )
reference.insert(fi->filePath(), (void*)2);
}
}
}
}
}
}
/*!
\class DocLnk applnk.h
\brief The DocLnk class represents loaded document references.
*/
/*!
\fn DocLnk::DocLnk( const DocLnk &o )
Copies \a o.
*/
/*!
Constructs a DocLnk from a valid .desktop \a file or a new .desktop
\a file for other files.
*/
DocLnk::DocLnk( const QString &file ) :
AppLnk(file)
{
init(file);
}
/*!
Constructs a DocLnk from a valid .desktop \a file or a new .desktop
\a file for other files. If \a may_be_desktopfile is TRUE, then an
attempt is made to read \a file as a .desktop file; if that fails it
is read as a normal file.
*/
DocLnk::DocLnk( const QString &file, bool may_be_desktopfile ) :
AppLnk(may_be_desktopfile ? file : QString::null)
{
init(file);
}
void DocLnk::init(const QString &file)
{
if ( isValid() ) {
#ifndef FORCED_DIR_STRUCTURE_WAY
if ( mType.isNull() )
// try to infer it
#endif
{
int s0 = file.findRev('/');
if ( s0 > 0 ) {
int s1 = file.findRev('/',s0-1);
if ( s1 > 0 ) {
int s2 = file.findRev('/',s1-1);
if ( s2 > 0 ) {
mType = file.mid(s2+1,s0-s2-1);
}
}
}
}
} else if ( QFile::exists(file) ) {
QString n = file;
n.replace(QRegExp(".*/"),"");
n.replace(QRegExp("\\..*"),"");
setName( n );
setFile( file );
}
MimeType mt(mType);
if( mt.application() )
mExec = mt.application()->exec();
}
/*!
Constructs an invalid DocLnk.
*/
DocLnk::DocLnk()
{
}
/*!
Destroys the DocLnk. Just like AppLnk objects, a run-time error
occurs if the DocLnk is a member of a DocLnkSet (or AppLnkSet).
*/
DocLnk::~DocLnk()
{
}
/*!
\reimp
*/
QString DocLnk::exec() const
{
MimeType mt(type());
const AppLnk* app = mt.application();
if ( app )
return app->exec();
else
return QString::null;
}
/*!
\reimp
*/
void DocLnk::invoke(const QStringList& args) const
{
MimeType mt(type());
const AppLnk* app = mt.application();
if ( app ) {
QStringList a = args;
if ( linkFileKnown() && QFile::exists( linkFile() ) )
a.append(linkFile());
else
a.append(file());
app->execute(a);
}
}
diff --git a/library/tzselect.cpp b/library/tzselect.cpp
index 848dfb7..8dd427f 100644
--- a/library/tzselect.cpp
+++ b/library/tzselect.cpp
@@ -1,302 +1,303 @@
/**********************************************************************
** 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.
**
**********************************************************************/
#define QTOPIA_INTERNAL_TZSELECT_INC_LOCAL
#include "tzselect.h"
#include "resource.h"
#include "config.h"
#include <qtoolbutton.h>
#include <qfile.h>
#include <stdlib.h>
#include <qcopchannel_qws.h>
+#include <qpe/global.h>
#include <qpe/qpeapplication.h>
#include <qmessagebox.h>
/*!
\class TimeZoneSelector
\brief The TimeZoneSelector widget allows users to configure their time zone information.
\ingroup qtopiaemb
*/
class TimeZoneSelectorPrivate
{
public:
TimeZoneSelectorPrivate() : includeLocal(FALSE) {}
bool includeLocal;
};
TZCombo::TZCombo( QWidget *p, const char* n )
: QComboBox( p, n )
{
updateZones();
// check to see if TZ is set, if it is set the current item to that
QString tz = getenv("TZ");
if (parent()->inherits("TimeZoneSelector")) {
if ( ((TimeZoneSelector *)parent())->localIncluded() ) {
// overide to the 'local' type.
tz = "None";
}
}
if ( !tz.isNull() ) {
int n = 0,
index = 0;
for ( QStringList::Iterator it=identifiers.begin();
it!=identifiers.end(); ++it) {
if ( *it == tz )
index = n;
n++;
}
setCurrentItem(index);
} else {
setCurrentItem(0);
}
// listen on QPE/System
#if !defined(QT_NO_COP)
QCopChannel *channel = new QCopChannel( "QPE/System", this );
connect( channel, SIGNAL(received(const QCString&,const QByteArray&)),
this, SLOT(handleSystemChannel(const QCString&,const QByteArray&)) );
#endif
}
TZCombo::~TZCombo()
{
}
void TZCombo::updateZones()
{
QString cur = currentText();
clear();
identifiers.clear();
int curix=0;
QString tz = getenv("TZ");
bool tzFound = FALSE;
Config cfg("CityTime");
cfg.setGroup("TimeZones");
int listIndex = 0;
if (parent()->inherits("TimeZoneSelector")) {
if ( ((TimeZoneSelector *)parent())->localIncluded() ) {
// overide to the 'local' type.
identifiers.append( "None" );
insertItem( tr("None") );
if ( cur == tr("None"))
curix = 0;
listIndex++;
}
}
int cfgIndex = 0;
while (1) {
QString zn = cfg.readEntry("Zone"+QString::number(cfgIndex), QString::null);
if ( zn.isNull() )
break;
if ( zn == tz )
tzFound = TRUE;
QString nm = cfg.readEntry("ZoneName"+QString::number(cfgIndex));
identifiers.append(zn);
insertItem(nm);
if ( nm == cur )
curix = listIndex;
++cfgIndex;
++listIndex;
}
if ( !listIndex ) {
QStringList list = timezoneDefaults();
for ( QStringList::Iterator it = list.begin(); it!=list.end(); ++it ) {
QString zn = *it;
QString nm = *++it;
if ( zn == tz )
tzFound = TRUE;
if ( nm == cur )
curix = listIndex;
identifiers.append(zn);
insertItem(nm);
++listIndex;
}
}
for (QStringList::Iterator it=extras.begin(); it!=extras.end(); ++it) {
insertItem(*it);
identifiers.append(*it);
if ( *it == cur )
curix = listIndex;
++listIndex;
}
if ( !tzFound && !tz.isEmpty()) {
int i = tz.find( '/' );
QString nm = tz.mid( i+1 ).replace(QRegExp("_"), " ");
identifiers.append(tz);
insertItem(nm);
if ( nm == cur )
curix = listIndex;
++listIndex;
}
setCurrentItem(curix);
}
void TZCombo::keyPressEvent( QKeyEvent *e )
{
// ### should popup() in Qt 3.0 (it's virtual there)
// updateZones();
QComboBox::keyPressEvent(e);
}
void TZCombo::mousePressEvent(QMouseEvent*e)
{
// ### should popup() in Qt 3.0 (it's virtual there)
// updateZones();
QComboBox::mousePressEvent(e);
}
QString TZCombo::currZone() const
{
return identifiers[currentItem()];
}
void TZCombo::setCurrZone( const QString& id )
{
for (int i=0; i< count(); i++) {
if ( identifiers[i] == id ) {
setCurrentItem(i);
return;
}
}
insertItem(id);
setCurrentItem( count() - 1);
identifiers.append(id);
extras.append(id);
}
void TZCombo::handleSystemChannel(const QCString&msg, const QByteArray&)
{
if ( msg == "timeZoneListChange()" ) {
updateZones();
}
}
/*!
Creates a new TimeZoneSelector with parent \a p and name \a n. The combobox will be
populated with the available timezones.
*/
TimeZoneSelector::TimeZoneSelector(QWidget* p, const char* n) :
QHBox(p,n)
{
d = new TimeZoneSelectorPrivate();
// build the combobox before we do any updates...
cmbTz = new TZCombo( this, "timezone combo" );
cmdTz = new QToolButton( this, "timezone button" );
cmdTz->setIconSet( Resource::loadIconSet( "citytime_icon" ) );
cmdTz->setMaximumSize( cmdTz->sizeHint() );
// set up a connection to catch a newly selected item and throw our
// signal
QObject::connect( cmbTz, SIGNAL( activated(int) ),
this, SLOT( slotTzActive(int) ) );
QObject::connect( cmdTz, SIGNAL( clicked() ),
this, SLOT( slotExecute() ) );
}
/*!
Destroys a TimeZoneSelector.
*/
TimeZoneSelector::~TimeZoneSelector()
{
}
void TimeZoneSelector::setLocalIncluded(bool b)
{
d->includeLocal = b;
cmbTz->updateZones();
}
bool TimeZoneSelector::localIncluded() const
{
return d->includeLocal;
}
/*!
Returns the currently selected timezone as a string in location format, e.g.
\code Australia/Brisbane \endcode
*/
QString TimeZoneSelector::currentZone() const
{
return cmbTz->currZone();
}
/*!
Sets the current timezone to \a id.
*/
void TimeZoneSelector::setCurrentZone( const QString& id )
{
cmbTz->setCurrZone( id );
}
/*! \fn void TimeZoneSelector::signalNewTz( const QString& id )
This signal is emitted when a timezone has been selected by the user. The id
is a \l QString in location format, eg \code Australia/Brisbane \endcode
*/
void TimeZoneSelector::slotTzActive( int )
{
emit signalNewTz( cmbTz->currZone() );
}
void TimeZoneSelector::slotExecute( void )
{
// execute the world time application...
if (QFile::exists(QPEApplication::qpeDir()+"bin/citytime"))
Global::execute( "citytime" );
else
QMessageBox::warning(this,tr("citytime executable not found"),
tr("In order to choose the time zones,\nplease install citytime."));
}
QStringList timezoneDefaults( void )
{
QStringList tzs;
// load up the list just like the file format (citytime.cpp)
tzs.append( "America/New_York" );
tzs.append( "New York" );
tzs.append( "America/Los_Angeles" );
tzs.append( "Los Angeles" );
tzs.append( "Australia/Brisbane" );
tzs.append( "Brisbane" );
tzs.append( "Europe/Berlin" );
tzs.append( "Berlin" );
tzs.append( "Asia/Tokyo" );
tzs.append( "Tokyo" );
tzs.append( "America/Denver" );
tzs.append( "Denver" );
return tzs;
}