| Home · All Classes · Main Classes · Deprecated |
MTheme abstracts the theming and styling of DirectUI applications and widgets. More...


Public Types | |
| enum | ThemeService { AnyTheme = 0, RemoteTheme, LocalTheme } |
| enum | InsertMode { Overwrite, Append } |
| typedef QString | ViewType |
Signals | |
| void | pixmapRequestsFinished () |
| void | themeIsChanging () |
| void | themeChangeCompleted () |
Public Member Functions | |
| MTheme (const QString &applicationName, const QString &imglistFilename=QString(), ThemeService themeService=AnyTheme) | |
| virtual | ~MTheme () |
Static Public Member Functions | |
| static const MStyle * | style (const char *styleClassName, const QString &objectName, const QString &mode, const QString &type, M::Orientation orientation, const MWidgetController *parent=NULL) |
| static const MStyle * | style (const char *styleClassName, const QString &objectName, const QString &mode, const QString &type, M::Orientation orientation, const QList< QStringList > &parentClassHierarchies, const QString &parentStyleName) |
| static const MStyle * | style (const char *styleClassName, const QString &objectName="") |
| static void | releaseStyle (const MStyle *style) |
| static bool | addPixmapDirectory (const QString &directoryName, M::RecursionMode mode=M::NonRecursive) |
| static void | clearPixmapDirectories () |
| static MTheme * | instance () |
| static const QPixmap * | pixmap (const QString &id, const QSize &size=QSize(0, 0)) |
| static const QPixmap * | asyncPixmap (const QString &id, const QSize &size=QSize(0, 0)) |
| static QPixmap * | pixmapCopy (const QString &id, const QSize &size=QSize(0, 0)) |
| static const MScalableImage * | scalableImage (const QString &id, int left, int right, int top, int bottom) |
| static void | releaseScalableImage (const MScalableImage *image) |
| static void | releasePixmap (const QPixmap *pixmap) |
| static QAbstractAnimation * | animation (const QString &animationTypeName) |
| static QGraphicsEffect * | effect (const QString &effectTypeName) |
| static MWidgetView * | view (const MWidgetController *controller) |
| static const MPalette & | palette () |
| static const MDefaultFonts & | fonts () |
| static bool | loadCSS (const QString &filename, InsertMode mode=Append) |
| static QString | currentTheme () |
| static bool | hasPendingRequests () |
| static void | cleanupGarbage () |
Protected Member Functions | |
| void | rebuildViewsForWidgets () |
MTheme abstracts the theming and styling of DirectUI applications and widgets.
MTheme is a singleton class providing runtime access to the MeeGo Touch theming parameters, as well as factory methods for instantiating various theming resources such as shared graphical assets in the form of QPixmaps and MScalableImages, as well as style and view instances for the widgets.
MTheme communicates with a theme server whenever a graphical asset is requested. The theme server is responsible for loading the graphics (either from static image files, by rasterizing SVG or through procedural generation) and sharing them. The sharing of graphics assets is platform specific, MeeGo Touch ships with a reference theme server called mthemedaemon that shares assets using the X11 system. In case a theme server is not available, no sharing occurs and each graphical asset is duplicated for each application.
Definition at line 62 of file corelib/theme/mtheme.h.
| typedef QString MTheme::ViewType |
ViewTypes are standardized widget variant names, as defined by the widgets themselves. For example, MButton::checkboxType can be expected to be implemented by each theme, while a random non-standard type is unlikely to be. There is a mapping of view types to view implementation class names in the theme configurations.
Definition at line 74 of file corelib/theme/mtheme.h.
| enum MTheme::InsertMode |
Defines the how resources that are registered with the theme at runtime are handled.
Definition at line 84 of file corelib/theme/mtheme.h.
{
Overwrite,
Append
};
| enum MTheme::ThemeService |
Defines the type of theme service the process will use.
| AnyTheme |
Default theme service will be used. |
| RemoteTheme |
Remote theme service will be used. |
| LocalTheme |
Local theme service will be used. |
Definition at line 77 of file corelib/theme/mtheme.h.
{
AnyTheme = 0,
RemoteTheme,
LocalTheme
};
| MTheme::MTheme | ( | const QString & | applicationName, | |
| const QString & | imglistFilename = QString(), |
|||
| ThemeService | themeService = AnyTheme | |||
| ) |
Constructs the MTheme instance.
By default the theme system firsrt attempts to connect to a remote theme service, if this fails a local theme service is created unless overriden by the themeService parameter. Note that on some platforms failing to connect to a remote theme service at startup may be a fatal error. If the themeService is RemoteTheme, the constructor will not return until a remote theme service becomes available. This option should be used when the application may potentially start before the theme service during system bootup. The RemoteTheme option can also be toggled by the -remote-theme command line parameter as passed to MApplication. The RemoteTheme option cannot be used if imglistFilename is also set.
applicationName is used as the first part of the search path for resources, ensuring that application specific theme resources are prioritized. imglistFilename is not in use anymore.
Definition at line 131 of file mtheme.cpp.
:
d_ptr(new MThemePrivate(applicationName, themeService))
{
if (gTheme || (MComponentData::instance() && MComponentData::instance()->d_ptr->theme))
qFatal("There cannot be multiple instances of MTheme, use MTheme::instance() instead of constructing a new one");
Q_D(MTheme);
d->q_ptr = this;
connect(d->themeDaemon, SIGNAL(themeChanged(QStringList, QStringList)),
SLOT(themeChangedSlot(QStringList, QStringList)));
connect(d->themeDaemon, SIGNAL(pixmapCreatedOrChanged(QString, QSize, MPixmapHandle)),
SLOT(pixmapCreatedOrChangedSlot(QString, QSize, MPixmapHandle)));
connect(d->themeDaemon, SIGNAL(themeChangeCompleted()), SIGNAL(themeChangeCompleted()));
#ifdef HAVE_GCONF
connect(&d->locale, SIGNAL(valueChanged()), SLOT(localeChangedSlot()));
#endif
gTheme = this;
}

| MTheme::~MTheme | ( | ) | [virtual] |
Destroys the theme instance.
Definition at line 156 of file mtheme.cpp.
{
MStyleSheet::cleanup(false);
QHash<QString, CachedScalableImage>::iterator i2 = d_ptr->scalableImageIdentifiers.begin();
QHash<QString, CachedScalableImage>::iterator end2 = d_ptr->scalableImageIdentifiers.end();
for (; i2 != end2; ++i2) {
qWarning() << "MTheme - MScalableImage" << i2.key() << "not released!" << "refcount:" << i2.value().refcount;
releasePixmap(i2.value().image->pixmap());
delete i2.value().image;
}
d_ptr->cleanupGarbage();
// print identifiers from all pixmaps which were not released
QHash<QString, CachedPixmap>::iterator i = d_ptr->pixmapIdentifiers.begin();
QHash<QString, CachedPixmap>::iterator end = d_ptr->pixmapIdentifiers.end();
for (; i != end; ++i) {
qWarning() << "MTheme - pixmap" << i.key() << "not released!" << "refcount:" << i.value().refcount;
}
// unload all theme libraries
d_ptr->reloadThemeLibraries(QStringList());
gTheme = NULL;
delete d_ptr;
}

| bool MTheme::addPixmapDirectory | ( | const QString & | directoryName, | |
| M::RecursionMode | mode = M::NonRecursive | |||
| ) | [static] |
Adds a directory to the theme service search path for this application.
The theme service will look for PNG and SVG files in the location specified by directoryName, which can be either an relative or absolute path. If mode is defined as Recursive, subdirectories of the specified directory are searched as well. The default is not to search subdirectories.
Definition at line 185 of file mtheme.cpp.
{
QDir dir(directoryName);
if (!dir.exists())
return false;
instance()->d_ptr->themeDaemon->addDirectoryToPixmapSearchList(dir.absolutePath(), recursive);
return true;
}

| QAbstractAnimation * MTheme::animation | ( | const QString & | animationTypeName | ) | [static] |
Returns an animation instance with the given type.
| animationTypeName | Name of the animation type. |
The returned animation is theme specific.
Definition at line 563 of file mtheme.cpp.
{
QAbstractAnimation *a = MClassFactory::instance()->createAnimation(animationTypeName);
if (!a) {
qWarning() << "Failed to create implementation for: " << animationTypeName;
return NULL;
}
return a;
}

| const QPixmap * MTheme::asyncPixmap | ( | const QString & | id, | |
| const QSize & | size = QSize(0, 0) | |||
| ) | [static] |
Returns a QPixmap that contains the graphical asset specified by the logical ID.
Loads the pixmap specified by id of size size.
The requested pixmap is loaded asynchronously. The returned pixmap can be one of the following:
In the first two cases, the pixmap data can be changed at any time by the theme. This may happen when the theme changes, as pixmaps are updated, pixmaps finish loading or for any other reason.
The returned pixmap is owned by the theme and should be freed with releasePixmap() when no longer needed.
Definition at line 221 of file mtheme.cpp.

| void MTheme::cleanupGarbage | ( | ) | [static] |
Definition at line 674 of file mtheme.cpp.
{
instance()->d_ptr->cleanupGarbage();
}

| void MTheme::clearPixmapDirectories | ( | ) | [static] |
Clear all pixmap directories from the theme service search path for this application.
Definition at line 195 of file mtheme.cpp.
{
instance()->d_ptr->themeDaemon->clearPixmapSearchList();
}

| QString MTheme::currentTheme | ( | ) | [static] |
Returns the name of the current theme in use.
Definition at line 663 of file mtheme.cpp.
{
MThemePrivate *d = MTheme::instance()->d_func();
return d->themeDaemon->currentTheme();
}

| QGraphicsEffect * MTheme::effect | ( | const QString & | effectTypeName | ) | [static] |
Returns an effect instance with the given type.
| effectTypeName | Name of the effect type. |
The returned effect is theme specific.
Definition at line 574 of file mtheme.cpp.
{
QGraphicsEffect *a = MClassFactory::instance()->createEffect(effectTypeName);
if (!a) {
qWarning() << "Failed to create implementation for: " << effectTypeName;
return NULL;
}
return a;
}

| const MDefaultFonts & MTheme::fonts | ( | ) | [static] |
Returns the theme's logical font information.
The font information can be used to programmatically query the common fonts defined in the theme.
Definition at line 609 of file mtheme.cpp.

| bool MTheme::hasPendingRequests | ( | ) | [static] |
Returns true if there are pending asynchronous pixmap requests in the system.
Definition at line 669 of file mtheme.cpp.
{
return instance()->d_ptr->themeDaemon->hasPendingRequests();
}

| MTheme * MTheme::instance | ( | ) | [static] |
Returns the singleton MTheme instance.
Definition at line 200 of file mtheme.cpp.
{
if (MComponentData::instance())
return MComponentData::instance()->d_ptr->theme;
if (!gTheme) {
// This allows MTheme to be independent from MApplication.
// Uses this process' name as the theme identifier by default
QFileInfo fileInfo(QCoreApplication::instance()->applicationName());
QString applicationName = fileInfo.fileName();
gTheme = new MTheme(applicationName);
}
return gTheme;
}

| bool MTheme::loadCSS | ( | const QString & | filename, | |
| InsertMode | mode = Append | |||
| ) | [static] |
Loads the requested CSS file to the current active theme.
Either appends to or replaces the existing theme CSS using the style sheet located by filename, depending on the mode. The method returns true if the CSS file was successfully loaded.
Note that CSS files should be loaded before constructing the style objects.
Definition at line 614 of file mtheme.cpp.
{
if (instance()->d_ptr->loadCSS(filename, mode)) {
// Re-populate all the styles, custom stylesheet may have overridden something
for (MThemePrivate::RegisteredStyleContainers::iterator iterator = MThemePrivate::styleContainers.begin(); iterator != MThemePrivate::styleContainers.end(); ++iterator) {
iterator.value()->reloadStyles();
}
// notify all widgets that style needs to be applied
QSet<MWidgetController *>::iterator end = MWidgetControllerPrivate::allSystemWidgets.end();
for (QSet<MWidgetController *>::iterator i = MWidgetControllerPrivate::allSystemWidgets.begin();
i != end; ++i) {
// get view ask it to apply the new style
const MWidgetView *view = (*i)->view();
if (view) {
const_cast<MWidgetView *>(view)->applyStyle();
}
}
return true;
}
return false;
}

| const MPalette & MTheme::palette | ( | ) | [static] |
Returns the theme's logical color palette.
The palette can be used to programmatically query the common colors defined in the theme.
Definition at line 604 of file mtheme.cpp.

Returns a QPixmap that contains the graphical asset specified by the logical ID.
Note: While loading the graphics the application UI thread is blocked. In case the graphics is large or you do not need to immediately know the final size of the requested graphics, consider using the asyncPixmap() method instead to keep the UI responsive.
The id is a logical identifier for a single graphical theme asset. The source format of the graphics is abstracted and determined by the theme service. The default graphics loading policy is as follows:
The size parameter determines the size of the returned pixmap. The default size of QSize(0,0) marks that the original source graphics size should be used.
The returned pixmap is owned by the theme and should be freed with releasePixmap() when no longer needed.
Definition at line 216 of file mtheme.cpp.

Returns a copy of the graphical asset with the given logical ID.
Loads the pixmap specified by id of size size synchronously and returns a copy to the caller. This method can be very slow, use the pixmap() or asyncPixmap() methods instead if possible.
The ownership of the returned pixmap is transferred to caller, and the pixmap may be modified.
Definition at line 226 of file mtheme.cpp.
{
//force daemon to load the pixmap synchronously, then make copy of the
//pixmap and release it immediately
const QPixmap *p = instance()->d_ptr->pixmap(id, false, size);
QPixmap* copy = new QPixmap(p->copy());
releasePixmap(p);
return copy;
}

| void MTheme::pixmapRequestsFinished | ( | ) | [signal] |
This signal is emitted when all pixmap requests have finished.
The signal is emitted regardless of if the request was successfull or not.
Note that for regular applications, listening for this signal is not necessary, since any change automatically triggers an update of the interface.
Widget implementations must not connect to this signal. All widgets are repainted after the outstanding requests have finished.
| void MTheme::rebuildViewsForWidgets | ( | ) | [protected] |
Causes all widgets to update their views when the theme is changed.
Definition at line 930 of file mtheme.cpp.
{
Q_D(MTheme);
// Re-populate all the styles
// TODO: This could be probably optimized somehow
for (MThemePrivate::RegisteredStyleContainers::iterator iterator = d->styleContainers.begin(); iterator != d->styleContainers.end(); ++iterator) {
iterator.value()->reloadStyles();
}
// go trough all widgets, replace views
QSet<MWidgetController *>::iterator end = MWidgetControllerPrivate::allSystemWidgets.end();
for (QSet<MWidgetController *>::iterator i = MWidgetControllerPrivate::allSystemWidgets.begin();
i != end; ++i) {
MWidgetController *controller = (*i);
// figure out the view class name
QString className = d->determineViewClassForController(controller);
const MWidgetView *view = controller->view();
if (view) {
// check if it's completely new view class for this widget?
if (className != view->metaObject()->className()) {
controller->d_func()->deprecateView();
} else {
const_cast<MWidgetView *>(view)->applyStyle();
}
}
}
}

| void MTheme::releasePixmap | ( | const QPixmap * | pixmap | ) | [static] |
Releases a shared QPixmap acquired through MTheme.
releasePixmap performs cleanup and frees the pixmap if there are no other clients using it.
Definition at line 323 of file mtheme.cpp.
{
// NULL pixmap, do nothing
if (!pixmap)
return;
// invalidPixmap, no need to release it
if (pixmap == instance()->d_ptr->invalidPixmap) {
return;
}
if (instance()->d_ptr->releasePixmap(pixmap))
return;
// check if we didn't find the pixmap from our cache
Q_ASSERT_X(false, "MTheme::releasePixmap", "Pixmap not found from the cache!");
}

| void MTheme::releaseScalableImage | ( | const MScalableImage * | image | ) | [static] |
Releases a shared MScalableImage acquired through MTheme.
releaseScalableImage performs cleanup and frees the image if there are no other clients using it.
Definition at line 304 of file mtheme.cpp.
{
// find the image from cache and decrease refcount + release if refcount = 0
// TODO: this could be optimized
QHash<QString, CachedScalableImage>::iterator i = instance()->d_ptr->scalableImageIdentifiers.begin();
QHash<QString, CachedScalableImage>::iterator end = instance()->d_ptr->scalableImageIdentifiers.end();
for (; i != end; ++i) {
// is this the image which we should release?
if (i.value().image == image) {
if (!i.value().refcount.deref()) {
releasePixmap(i.value().image->pixmap());
delete i.value().image;
instance()->d_ptr->scalableImageIdentifiers.erase(i);
}
break;
}
}
}

| void MTheme::releaseStyle | ( | const MStyle * | style | ) | [static] |
This method should be called on style objects when they are no longer needed.
releaseStyle performs cleanup and frees the style if there are no other clients using it.
Definition at line 555 of file mtheme.cpp.
{
if (!style)
return;
MStyleSheet::releaseStyle(style);
}
| const MScalableImage * MTheme::scalableImage | ( | const QString & | id, | |
| int | left, | |||
| int | right, | |||
| int | top, | |||
| int | bottom | |||
| ) | [static] |
Returns a MScalableImage that contains the graphical asset specified by the logical ID.
The logic for acquiring a scalable image is the same as that for a regular pixmap. The left, right, top and bottom parameters specify the non-scaled border values of the image.
The returned image is owned by the theme and should be freed with releaseScalableImage() when no longer needed.
Definition at line 274 of file mtheme.cpp.
{
// check if we already have this scalable image in the cache
QString scalableidentifier = scalableImageCacheId(id, left, top, right, bottom);
QHash<QString, CachedScalableImage>::iterator i = instance()->d_ptr->scalableImageIdentifiers.find(scalableidentifier);
if (i != instance()->d_ptr->scalableImageIdentifiers.end()) {
//image found, increase refcount and return it
i.value().refcount.ref();
return i.value().image;
}
//first try to fetch the used pixmap from the cache
QString pixmapidentifier = defaultPixmapCacheId(id, 0, 0);
const QPixmap *p = instance()->d_ptr->fetchPixmapFromCache(pixmapidentifier);
if (!p) {
QPixmap *result = new QPixmap();
instance()->d_ptr->pixmapIdentifiers.insert(pixmapidentifier, CachedPixmap(result, id, QSize(0, 0)));
instance()->d_ptr->themeDaemon->pixmapHandleSync(id, QSize(0, 0));
p = result;
}
//create the actual scalable image and cache it
MScalableImage *image = new MScalableImage(p, left, right, top, bottom, id);
instance()->d_ptr->scalableImageIdentifiers.insert(scalableidentifier, CachedScalableImage(image));
return image;
}

| const MStyle * MTheme::style | ( | const char * | styleClassName, | |
| const QString & | objectName, | |||
| const QString & | mode, | |||
| const QString & | type, | |||
| M::Orientation | orientation, | |||
| const QList< QStringList > & | parentClassHierarchies, | |||
| const QString & | parentStyleName | |||
| ) | [static] |
This is an overloaded function.
Returns the style object matching the given parameters. Instead of taking the controller of the widget to get the contextual information for the style, this function gets a list of QStringLists, describing the metaclass hierarchy of each parent, starting from the most direct.
This overload is not for using in regular MeeGo Touch applications. It is intended to be used by other libraries that need the styling information but do not have widget controllers or views instantiated.
Definition at line 511 of file mtheme.cpp.
{
// The style type should never be "default" - that would probably be a view type
// that's mistakenly being used as a style type.
// The caller probably means "" instead.
Q_ASSERT(type != "default");
MThemePrivate *d = MTheme::instance()->d_func();
// list containing all stylesheets from all assemblies from which this style is/inherits + app css
QList<const MStyleSheet *> sheets;
QList<QByteArray> styleMetaObjectHierarchy;
d->extractDataForStyleClass(styleClassName, sheets, styleMetaObjectHierarchy);
// Get parent data based on the parentClassHierarchies parameter...
QVector<MStyleSheetPrivate::ParentData> parentsData(parentClassHierarchies.size());
for (int i = 0; i < parentClassHierarchies.size(); i++) {
MStyleSheetPrivate::ParentData &pd = parentsData[i];
QList<QByteArray> parentClassHierarchiesConverted;
foreach (const QString &str, parentClassHierarchies[i]) {
parentClassHierarchiesConverted << str.toAscii();
}
pd.hierarchy = parentClassHierarchiesConverted;
pd.sheets = d->extractSheetsForClassHierarchy(sheets, pd.hierarchy);
}
// add application css
if (d->application->stylesheet())
sheets.append(d->application->stylesheet());
// add custom stylesheet
if (d->customStylesheet)
sheets.append(d->customStylesheet);
return MStyleSheetPrivate::style(sheets, parentsData, parentStyleName.toAscii(), styleMetaObjectHierarchy, styleClassName, objectName.toAscii(), mode.toAscii(), type.toAscii(), orientation);
}

| const MStyle * MTheme::style | ( | const char * | styleClassName, | |
| const QString & | objectName, | |||
| const QString & | mode, | |||
| const QString & | type, | |||
| M::Orientation | orientation, | |||
| const MWidgetController * | parent = NULL | |||
| ) | [static] |
Returns the style object matching the given parameters.
A style object is a collection of data properties, from which widget views (or any other type of class) access their run time parameters. The data is in the form of standard Qt properties and the style object is automatically filled through Qt property introspection based on values defined in CSS sylesheets.
Ownership of the returned object remains with MTheme, the caller must not delete it as it may be shared by multiple users. Once the caller no longer needs the object, it should be passed to the releaseStyle method of MTheme.
The parameters are:
Definition at line 463 of file mtheme.cpp.
{
// The style type should never be "default" - that would probably be a view type
// that's mistakenly being used as a style type.
// The caller probably means "" instead.
Q_ASSERT(type != "default");
MThemePrivate *d = MTheme::instance()->d_func();
// list containing all stylesheets from all assemblies from which this style is/inherits + app css
QList<const MStyleSheet *> sheets;
QList<QByteArray> styleMetaObjectHierarchy;
d->extractDataForStyleClass(styleClassName, sheets, styleMetaObjectHierarchy);
// Get parent data by traversing the MWidgetController pointer we have
QVector<MStyleSheetPrivate::ParentData> parentsData = MStyleSheetPrivate::extractParentsData(parent);
for (int i = 0; i < parentsData.size(); i++) {
MStyleSheetPrivate::ParentData &pd = parentsData[i];
pd.sheets = d->extractSheetsForClassHierarchy(sheets, pd.hierarchy);
}
// add application css
if (d->application->stylesheet())
sheets.append(d->application->stylesheet());
// add custom stylesheet
if (d->customStylesheet)
sheets.append(d->customStylesheet);
QString parentStyleName;
if (parent) {
if (!parent->styleName().isNull())
parentStyleName = parent->styleName();
else
parentStyleName = parent->objectName();
}
return MStyleSheetPrivate::style(sheets, parentsData, parentStyleName.toAscii(),
styleMetaObjectHierarchy, styleClassName, objectName.toAscii(),
mode.toAscii(), type.toAscii(), orientation);
}

| const MStyle * MTheme::style | ( | const char * | styleClassName, | |
| const QString & | objectName = "" | |||
| ) | [static] |
This is an overloaded function.
Returns the style object with the given styleClassName and objectName
Definition at line 457 of file mtheme.cpp.
{
return MTheme::style(styleClassName, objectName, 0, 0, M::Landscape, NULL);
}

| void MTheme::themeChangeCompleted | ( | ) | [signal] |
This signal is emitted when the theme service and all applications have changed the theme.
Note that for regular applications, listening for this signal is not necessary, since when this signal is emitted the applications are already running with the new theme.
| void MTheme::themeIsChanging | ( | ) | [signal] |
This signal is emitted when the current theme was changed but before the old resources are deleted. This allows for applications to stop using the old pixmaps before they become invalid.
Note that for regular application, listening to this signal is not necessary. This is mostly useful for custom applications that only use selected parts of MeegoTouch Framework.
| MWidgetView * MTheme::view | ( | const MWidgetController * | controller | ) | [static] |
Returns a view instance for the given controller.
The returned view is theme specific and can be changed in the theme configuration.
Definition at line 585 of file mtheme.cpp.
{
// Best matching view class name
QString viewClassName = instance()->d_ptr->determineViewClassForController(controller);
if (viewClassName.isEmpty()) {
qWarning() << "Could not find view class for:" << controller->metaObject()->className() << "/" << controller->viewType();
return NULL;
}
MWidgetView *v = MClassFactory::instance()->createView(viewClassName.toStdString().c_str(), controller);
if (!v) {
qWarning() << "Failed to create view for:" << controller->metaObject()->className() << "/" << controller->viewType() << ". Class name found was: " << viewClassName;
return NULL;
}
return v;
}

| Copyright © 2010 Nokia Corporation | Generated on Thu Nov 4 2010 18:14:27 (PDT) Doxygen 1.7.1 |
MeeGo Touch |