diff options
author | Lauro Neto <lauro.neto@openbossa.org> | 2011-10-11 17:40:07 -0300 |
---|---|---|
committer | Lauro Neto <lauro.neto@openbossa.org> | 2011-10-11 17:40:07 -0300 |
commit | f52941712fc32dfd2881bed0771c86ed76716883 (patch) | |
tree | 753b9aa8807eef4bba7497e57d26fac1f0ad023e /mobility | |
parent | 9616988e1332f9e67cdaab338c3970232cd9d68f (diff) | |
parent | 53bd4b768ea773723f6eba338ecb2cee0facf591 (diff) |
Merge branch 'qml'
Diffstat (limited to 'mobility')
41 files changed, 2993 insertions, 193 deletions
diff --git a/mobility/audiooutput/generator/MainPage.qml b/mobility/audiooutput/generator/MainPage.qml new file mode 100644 index 0000000..aedc384 --- /dev/null +++ b/mobility/audiooutput/generator/MainPage.qml @@ -0,0 +1,58 @@ + + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + id: mainPage + anchors.margins: rootWindow.pageMargin + anchors.fill: parent + + Flow { + anchors.fill: parent + + Flickable { + width: deviceButtons.width + height: screen.displayHeight + contentHeight: deviceButtons.height + ButtonColumn { + id: deviceButtons + Repeater { + model: deviceModel + Button { + text: modelData + onClicked: { + player.deviceChanged(index) + } + } + } + } + } + + Column { + CheckBox { + anchors.left: parent.left + id: play + checked: true + text: "Play when checked" + onClicked: { player.toggleSuspendResume() } + + Connections { + target: player + onPlaybackResumed: { + play.checked = true + } + } + } + + CheckBox { + anchors.left: parent.left + id: pushpull + checked: true + text: "Pull mode when checked" + onClicked: { player.toggleMode() } + } + } + } +} diff --git a/mobility/audiooutput/audiooutput.py b/mobility/audiooutput/generator/audiooutput.py index 523a93d..fa05611 100644 --- a/mobility/audiooutput/audiooutput.py +++ b/mobility/audiooutput/generator/audiooutput.py @@ -10,6 +10,8 @@ import struct from math import sin, pi +from generator import Generator + DURATION_SECONDS = 1 TONE_FREQUENCY_HZ = 600 DATA_FREQUENCY_HZ = 44100 @@ -20,115 +22,6 @@ PULL_MODE_LABEL = 'Enable pull mode' SUSPEND_LABEL = 'Suspend playback' RESUME_LABEL = 'Resume playback' -signed8 = struct.Struct('>b') -unsigned8 = struct.Struct('>B') - -bigSigned16 = struct.Struct('>h') -bigUnsigned16 = struct.Struct('>H') - -littleSigned16 = struct.Struct('<h') -littleUnsigned16 = struct.Struct('<H') - - -class Generator(QIODevice): - - def __init__(self, fmt, durationUs, frequency, parent, filename=None): - QIODevice.__init__(self, parent) - self.pos = 0 - self.buf = [] - - self.generateData(fmt, durationUs, frequency) - if filename: - self.dump(filename, fmt) - - def dump(self, filename, fmt): - - import wave - - handle = wave.open(filename, 'wb') - - handle.setnchannels(fmt.channels()) - handle.setsampwidth(fmt.sampleSize()/8) - handle.setframerate(fmt.sampleRate()) - handle.writeframes(''.join(self.buf)) - - handle.close() - - def start(self): - self.open(QIODevice.ReadOnly) - - def stop(self): - self.pos = 0 - self.close() - - def readData(self, size): - total = 0 - data = [] - - while size - total > 0: - chunk = min(len(self.buf) - self.pos, size - total) - data.extend(self.buf[self.pos:self.pos + chunk]) - self.pos = (self.pos + chunk) % len(self.buf) - total += chunk - - return ''.join(data) - - def writeData(self, data, maxLen): - return 0 - - def bytesAvailable(self): - return len(self.buf) + QIODevice.bytesAvailable(self) - - def generateData(self, fmt, durationUs, frequency): - channelBytes = fmt.sampleSize() / 8 - sampleBytes = fmt.channels() * channelBytes - - seconds = durationUs / 1000000 - length = fmt.frequency() * sampleBytes * seconds - - assert length % sampleBytes == 0 - - self.buf = [''] * length - - sampleIndex = 0 - - for i in range(0, length, channelBytes): - position = float(sampleIndex % fmt.frequency()) / fmt.frequency() - x = sin(2 * pi * frequency * position) - - for channel in range(fmt.channels()): - if fmt.sampleSize() == 8: - value = ((1.0 + x) / 2 * 255) % 255 - - if fmt.sampleType() == QAudioFormat.UnSignedInt: - data = unsigned8.pack(value) - else: #Signed - data = signed8.pack(value - 127) - - self.buf[i + channel * channelBytes] = data - - elif fmt.sampleSize() == 16: - value = ((1.0 + x) / 2 * 65535) % 65535 - - if fmt.sampleType() == QAudioFormat.UnSignedInt: - if fmt.byteOrder() == QAudioFormat.LittleEndian: - data = littleUnsigned16.pack(value) - else: - data = bigUnsigned16.pack(value) - else: - value -= 32767 - - if fmt.byteOrder() == QAudioFormat.LittleEndian: - data = littleSigned16.pack(value) - else: - data = bigSigned16.pack(value) - - self.buf[i + channel * channelBytes] = data[0] - self.buf[i + channel * channelBytes + 1] = data[1] - - sampleIndex += 1 - - class AudioTest(QMainWindow): def __init__(self, filename=None): diff --git a/mobility/audiooutput/generator/generator.py b/mobility/audiooutput/generator/generator.py new file mode 100644 index 0000000..9e2dd5e --- /dev/null +++ b/mobility/audiooutput/generator/generator.py @@ -0,0 +1,117 @@ + +import struct +from math import sin, pi + +from PySide.QtCore import QIODevice, QByteArray, QTimer +from QtMobility.MultimediaKit import QAudioFormat, QAudio, QAudioDeviceInfo + +signed8 = struct.Struct('>b') +unsigned8 = struct.Struct('>B') + +bigSigned16 = struct.Struct('>h') +bigUnsigned16 = struct.Struct('>H') + +littleSigned16 = struct.Struct('<h') +littleUnsigned16 = struct.Struct('<H') + + +class Generator(QIODevice): + + def __init__(self, fmt, durationUs, frequency, parent, filename=None): + QIODevice.__init__(self, parent) + self.pos = 0 + self.buf = [] + + self.generateData(fmt, durationUs, frequency) + if filename: + self.dump(filename, fmt) + + def dump(self, filename, fmt): + + import wave + + handle = wave.open(filename, 'wb') + + handle.setnchannels(fmt.channels()) + handle.setsampwidth(fmt.sampleSize()/8) + handle.setframerate(fmt.sampleRate()) + handle.writeframes(''.join(self.buf)) + + handle.close() + + def start(self): + self.open(QIODevice.ReadOnly) + + def stop(self): + self.pos = 0 + self.close() + + def readData(self, size): + total = 0 + data = [] + + while size - total > 0: + chunk = min(len(self.buf) - self.pos, size - total) + data.extend(self.buf[self.pos:self.pos + chunk]) + self.pos = (self.pos + chunk) % len(self.buf) + total += chunk + + return ''.join(data) + + def writeData(self, data, maxLen): + return 0 + + def bytesAvailable(self): + return len(self.buf) + QIODevice.bytesAvailable(self) + + def generateData(self, fmt, durationUs, frequency): + channelBytes = fmt.sampleSize() / 8 + sampleBytes = fmt.channels() * channelBytes + + seconds = durationUs / 1000000 + length = fmt.frequency() * sampleBytes * seconds + + assert length % sampleBytes == 0 + + self.buf = [''] * length + + sampleIndex = 0 + + for i in range(0, length, channelBytes): + position = float(sampleIndex % fmt.frequency()) / fmt.frequency() + x = sin(2 * pi * frequency * position) + + for channel in range(fmt.channels()): + if fmt.sampleSize() == 8: + value = ((1.0 + x) / 2 * 255) % 255 + + if fmt.sampleType() == QAudioFormat.UnSignedInt: + data = unsigned8.pack(value) + else: #Signed + data = signed8.pack(value - 127) + + self.buf[i + channel * channelBytes] = data + + elif fmt.sampleSize() == 16: + value = ((1.0 + x) / 2 * 65535) % 65535 + + if fmt.sampleType() == QAudioFormat.UnSignedInt: + if fmt.byteOrder() == QAudioFormat.LittleEndian: + data = littleUnsigned16.pack(value) + else: + data = bigUnsigned16.pack(value) + else: + value -= 32767 + + if fmt.byteOrder() == QAudioFormat.LittleEndian: + data = littleSigned16.pack(value) + else: + data = bigSigned16.pack(value) + + self.buf[i + channel * channelBytes] = data[0] + self.buf[i + channel * channelBytes + 1] = data[1] + + sampleIndex += 1 + + + diff --git a/mobility/audiooutput/generator/main.qml b/mobility/audiooutput/generator/main.qml new file mode 100644 index 0000000..dd3484d --- /dev/null +++ b/mobility/audiooutput/generator/main.qml @@ -0,0 +1,11 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + + id: rootWindow + showStatusBar: false + initialPage: MainPage { } + +} diff --git a/mobility/audiooutput/generator/toneplayer.py b/mobility/audiooutput/generator/toneplayer.py new file mode 100644 index 0000000..a142203 --- /dev/null +++ b/mobility/audiooutput/generator/toneplayer.py @@ -0,0 +1,203 @@ +''' + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + + This file is part of the Qt Mobility Components. + + $QT_BEGIN_LICENSE:LGPL$ + No Commercial Usage + This file contains pre-release code and may not be distributed. + You may use this file in accordance with the terms and conditions + contained in the Technology Preview License Agreement accompanying + this package. + + GNU Lesser General Public License Usage + Alternatively, this file may be used under the terms of the GNU Lesser + General Public License version 2.1 as published by the Free Software + Foundation and appearing in the file LICENSE.LGPL included in the + packaging of this file. Please review the following information to + ensure the GNU Lesser General Public License version 2.1 requirements + will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + If you have questions regarding the use of this file, please contact + Nokia at qt-info@nokia.com. +''' + +import os +import sys + +from PySide.QtCore import QObject, QUrl, QTimer, QByteArray, Slot, Property, Signal +from PySide.QtGui import QApplication +from PySide.QtDeclarative import QDeclarativeView +from QtMobility.MultimediaKit import QAudioFormat, QAudioDeviceInfo, QAudioOutput, QAudio + +from generator import Generator + +PUSH_MODE_LABEL = 'Enable push mode' +PULL_MODE_LABEL = 'Enable pull mode' +SUSPEND_LABEL = 'Suspend playback' +RESUME_LABEL = 'Resume playback' + +BUFFER_SIZE = 32768 +DURATION_SECONDS = 1 +TONE_FREQUENCY_HZ = 600 +DATA_FREQUENCY_HZ = 44100 + + +class TonePlayer(QObject): + + changed = Signal() + + def getStateLabel(self): + print "Getting" + return self._label + + def setStateLabel(self, value): + print "Setting", value + self._label = value + self.changed.emit() + + stateLabel = Property(str, getStateLabel, setStateLabel, notify=changed) + + def __init__(self, devices=None, filename=None, parent=None): + QObject.__init__(self, parent) + + self.pullTimer = QTimer(self) + self.buf = QByteArray() + self.devices = devices + self.device = QAudioDeviceInfo.defaultOutputDevice() + self.generator = None + self.audioOutput = None + self.output = None + self.fmt = QAudioFormat() + self.pullMode = False + self.dump = filename + self._label = SUSPEND_LABEL + + self.initializeAudio() + + def initializeAudio(self): + self.pullTimer.timeout.connect(self.pullTimerExpired) + + self.pullMode = True + + self.fmt.setFrequency(DATA_FREQUENCY_HZ) + self.fmt.setChannels(1) + self.fmt.setSampleSize(16) + self.fmt.setCodec('audio/pcm') + self.fmt.setByteOrder(QAudioFormat.LittleEndian) + self.fmt.setSampleType(QAudioFormat.SignedInt) + + info = QAudioDeviceInfo(QAudioDeviceInfo.defaultOutputDevice()) + if not info.isFormatSupported(self.fmt): + print 'Default format not supported - trying to use nearest' + self.fmt = info.nearestFormat(self.fmt) + + self.generator = Generator(self.fmt, DURATION_SECONDS * 1000000, + TONE_FREQUENCY_HZ, self, self.dump) + + self.createAudioOutput() + + def createAudioOutput(self): + self.audioOutput = QAudioOutput(self.device, self.fmt, self) + self.audioOutput.notify.connect(self.notified) + self.audioOutput.stateChanged.connect(self.stateChanged) + self.generator.start() + self.audioOutput.start(self.generator) + + @Slot() + def toggleSuspendResume(self): + if self.audioOutput.state() == QAudio.SuspendedState: + print 'Status: Suspended, resuming' + self.audioOutput.resume() + self.stateLabel = SUSPEND_LABEL + elif self.audioOutput.state() == QAudio.ActiveState: + print 'Status: Active, suspending' + self.audioOutput.suspend() + self.stateLabel = RESUME_LABEL + elif self.audioOutput.state() == QAudio.StoppedState: + print 'Status: Stopped, resuming' + self.audioOutput.resume() + self.stateLabel = SUSPEND_LABEL + elif self.audioOutput.state() == QAudio.IdleState: + print 'Status: Idle' + + playbackResumed = Signal() + + @Slot() + def toggleMode(self): + self.pullTimer.stop() + self.audioOutput.stop() + + if self.pullMode: + print "Enabling push mode" + self.output = self.audioOutput.start() + self.pullMode = False + self.pullTimer.start(5) + else: + print "Enabling pull mode" + self.pullMode = True + self.audioOutput.start(self.generator) + self.playbackResumed.emit() + + @Slot(int) + def deviceChanged(self, index): + print "Device changed: index:", index + print "Selected device name: ", self.devices[index].deviceName() + self.pullTimer.stop() + self.generator.stop() + self.audioOutput.stop() + self.audioOutput.disconnect(self) + self.device = self.devices[index] + self.createAudioOutput() + + def stateChanged(self, state): + print 'State changed: ', state + + def notified(self): + print 'Bytes free %d, elapsed usecs %d, processed usecs %d' % ( + self.audioOutput.bytesFree(), + self.audioOutput.elapsedUSecs(), + self.audioOutput.processedUSecs()) + + def pullTimerExpired(self): + if self.audioOutput.state() != QAudio.StoppedState: + chunks = self.audioOutput.bytesFree() / self.audioOutput.periodSize() + while chunks: + data = self.generator.read(self.audioOutput.periodSize()) + self.output.write(data) + if len(data) != self.audioOutput.periodSize(): + break + chunks -= 1 + + +def main(): + app = QApplication([]) + app.setApplicationName('Audio Output Test') + view = QDeclarativeView() + + devices = [] + for info in QAudioDeviceInfo.availableDevices(QAudio.AudioOutput): + devices.append(info) + + player = TonePlayer(devices, sys.argv[1] if len(sys.argv) > 1 else None) + + context = view.rootContext() + context.setContextProperty("player", player) + context.setContextProperty("deviceModel", [x.deviceName() for x in devices]) + + url = QUrl('main.qml') + view.setSource(url) + + + view.show() + + app.exec_() + +if __name__ == '__main__': + main() diff --git a/mobility/audiooutput/player/MainPage.qml b/mobility/audiooutput/player/MainPage.qml new file mode 100644 index 0000000..57358bc --- /dev/null +++ b/mobility/audiooutput/player/MainPage.qml @@ -0,0 +1,16 @@ + + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: mainPage + anchors.margins: rootWindow.pageMargin + + Button { + id: play + text: "Play!" + anchors.fill: parent + onClicked: player.play() + } +} diff --git a/mobility/audiooutput/player/main.qml b/mobility/audiooutput/player/main.qml new file mode 100644 index 0000000..dd3484d --- /dev/null +++ b/mobility/audiooutput/player/main.qml @@ -0,0 +1,11 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + + id: rootWindow + showStatusBar: false + initialPage: MainPage { } + +} diff --git a/mobility/audiooutput/player/qmlplayer.py b/mobility/audiooutput/player/qmlplayer.py new file mode 100644 index 0000000..51a3c49 --- /dev/null +++ b/mobility/audiooutput/player/qmlplayer.py @@ -0,0 +1,70 @@ +''' + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + + This file is part of the Qt Mobility Components. + + $QT_BEGIN_LICENSE:LGPL$ + No Commercial Usage + This file contains pre-release code and may not be distributed. + You may use this file in accordance with the terms and conditions + contained in the Technology Preview License Agreement accompanying + this package. + + GNU Lesser General Public License Usage + Alternatively, this file may be used under the terms of the GNU Lesser + General Public License version 2.1 as published by the Free Software + Foundation and appearing in the file LICENSE.LGPL included in the + packaging of this file. Please review the following information to + ensure the GNU Lesser General Public License version 2.1 requirements + will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + If you have questions regarding the use of this file, please contact + Nokia at qt-info@nokia.com. +''' + +import os +import sys + +from PySide.QtCore import * +from PySide.QtGui import * +from PySide.QtDeclarative import * +from QtMobility.MultimediaKit import * + +class Player(QObject): + + def __init__(self, filename, parent=None): + QObject.__init__(self, parent) + + self.source = QUrl.fromLocalFile(os.path.abspath(filename)) + self.player = QMediaPlayer() + self.player.setMedia(self.source) + + @Slot() + def play(self): + self.player.play() + +def main(): + app = QApplication([]) + view = QDeclarativeView() + player = Player(sys.argv[1]) + context = view.rootContext() + context.setContextProperty("player", player) + + url = QUrl('main.qml') + view.setSource(url) + view.showFullScreen() + + app.exec_() + + +if __name__ == '__main__': + main() + + + diff --git a/mobility/audiooutput/simpleplayer.py b/mobility/audiooutput/player/simpleplayer.py index f65b0b3..1e4213c 100644 --- a/mobility/audiooutput/simpleplayer.py +++ b/mobility/audiooutput/player/simpleplayer.py @@ -1,4 +1,5 @@ +import os import sys from PySide.QtCore import QUrl @@ -30,7 +31,7 @@ def main(): app = QApplication([]) app.setApplicationName('Simple Audio player') - window = AudioTest(sys.argv[1]) + window = AudioTest(os.path.abspath(sys.argv[1])) window.show() return app.exec_() diff --git a/mobility/feedback/MainPage.qml b/mobility/feedback/MainPage.qml new file mode 100644 index 0000000..4678be9 --- /dev/null +++ b/mobility/feedback/MainPage.qml @@ -0,0 +1,43 @@ + + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: mainPage + anchors.margins: rootWindow.pageMargin + + Flow { + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + anchors.margins: 10 + + spacing: 10 + + Button { + id: rumble + text: "Rumble" + onClicked: effectPlayer.playRumble() + } + + Button { + id: ocean + text: "Ocean" + onClicked: effectPlayer.playOcean() + } + + Button { + id: buttonClick + text: "Button Click" + onClicked: effectPlayer.playButtonClick() + } + + Button { + id: negativeEffect + text: "Negative Effect" + onClicked: effectPlayer.playNegativeEffect() + } + } + +} diff --git a/mobility/feedback/hapticsquare-qtgui.py b/mobility/feedback/hapticsquare-qtgui.py new file mode 100644 index 0000000..0554f4d --- /dev/null +++ b/mobility/feedback/hapticsquare-qtgui.py @@ -0,0 +1,127 @@ +''' + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + + This file is part of the Qt Mobility Components. + + $QT_BEGIN_LICENSE:LGPL$ + No Commercial Usage + This file contains pre-release code and may not be distributed. + You may use this file in accordance with the terms and conditions + contained in the Technology Preview License Agreement accompanying + this package. + + GNU Lesser General Public License Usage + Alternatively, this file may be used under the terms of the GNU Lesser + General Public License version 2.1 as published by the Free Software + Foundation and appearing in the file LICENSE.LGPL included in the + packaging of this file. Please review the following information to + ensure the GNU Lesser General Public License version 2.1 requirements + will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + If you have questions regarding the use of this file, please contact + Nokia at qt-info@nokia.com. +''' + +from PySide.QtCore import * +from PySide.QtGui import * +from QtMobility.Feedback import * + +class HapticButton(QWidget): + clicked = Signal() + toggled = Signal(bool) + + def __init__(self, label): + QWidget.__init__(self, None) + self.m_label = label + self.m_checked = False + self.m_checkable = False + + self.setMinimumSize(100, 100) + + def mousePressEvent(self, qMouseEvent): + self.clicked.emit() + + def paintEvent(self, qPaintEvent): + paint = QPainter(self) + + r = QRect(1, 1, self.width()-2, self.height()-2) + paint.drawRoundedRect(r, 10, 10) + paint.drawText(r, Qt.AlignCenter, self.m_label) + +class Dialog(QDialog): + + def __init__(self): + QDialog.__init__(self) + self.m_rumble = QFeedbackHapticsEffect() + self.m_rumble.setAttackIntensity(0.1) + self.m_rumble.setAttackTime(250) + self.m_rumble.setIntensity(1) + self.m_rumble.setDuration(1000) + self.m_rumble.setFadeTime(250) + self.m_rumble.setFadeIntensity(0.1) + + self.m_ocean = QFeedbackHapticsEffect() + self.m_ocean.setAttackIntensity(0.1) + self.m_ocean.setAttackTime(450) + self.m_ocean.setIntensity(0.8) + self.m_ocean.setDuration(6000) + self.m_ocean.setFadeTime(900) + self.m_ocean.setFadeIntensity(0.05) + self.m_ocean.setPeriod(1500) + + self.m_btnRumble = HapticButton("Rumble!") + self.m_btnOcean = HapticButton("Ocean") + self.m_btnButtonClick = HapticButton("Click") + self.m_btnNegativeEffect = HapticButton("Oops!") + self.topLayout = QGridLayout(self) + self.topLayout.addWidget(self.m_btnRumble, 0, 0) + self.topLayout.addWidget(self.m_btnOcean, 0, 1) + self.topLayout.addWidget(self.m_btnButtonClick, 1, 0) + self.topLayout.addWidget(self.m_btnNegativeEffect, 1, 1) + + self.m_btnRumble.clicked.connect(self.playRumble) + self.m_btnOcean.clicked.connect(self.playOcean) + self.m_btnButtonClick.clicked.connect(self.playButtonClick) + self.m_btnNegativeEffect.clicked.connect(self.playNegativeEffect) + + def __del__(self): + del self.m_btnRumble + del self.m_btnOcean + del self.m_btnButtonClick + del self.m_btnNegativeEffect + + def playRumble(self): + self.m_rumble.start() + print "Play rumble" + + def playOcean(self): + if self.m_ocean.state() == QFeedbackEffect.Stopped: + self.m_ocean.start() + print "Ocean start" + else: + self.m_ocean.stop() + print "Ocean stop" + + def playButtonClick(self): + QFeedbackEffect.playThemeEffect(QFeedbackEffect.ThemeBasicButton) + print "Play button click" + + def playNegativeEffect(self): + QFeedbackEffect.playThemeEffect(QFeedbackEffect.ThemeNegativeTacticon) + print "Play negative button click" + + +def main(): + app = QApplication([]) + w = Dialog() + w.showMaximized() + return app.exec_() + +if __name__ == "__main__": + main() diff --git a/mobility/feedback/hapticsquare.py b/mobility/feedback/hapticsquare.py index 0554f4d..ba5a964 100644 --- a/mobility/feedback/hapticsquare.py +++ b/mobility/feedback/hapticsquare.py @@ -1,5 +1,5 @@ ''' - Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. Contact: Nokia Corporation (qt-info@nokia.com) @@ -30,77 +30,38 @@ from PySide.QtCore import * from PySide.QtGui import * +from PySide.QtDeclarative import * from QtMobility.Feedback import * -class HapticButton(QWidget): - clicked = Signal() - toggled = Signal(bool) - - def __init__(self, label): - QWidget.__init__(self, None) - self.m_label = label - self.m_checked = False - self.m_checkable = False - - self.setMinimumSize(100, 100) - - def mousePressEvent(self, qMouseEvent): - self.clicked.emit() - - def paintEvent(self, qPaintEvent): - paint = QPainter(self) - - r = QRect(1, 1, self.width()-2, self.height()-2) - paint.drawRoundedRect(r, 10, 10) - paint.drawText(r, Qt.AlignCenter, self.m_label) - -class Dialog(QDialog): - - def __init__(self): - QDialog.__init__(self) - self.m_rumble = QFeedbackHapticsEffect() - self.m_rumble.setAttackIntensity(0.1) - self.m_rumble.setAttackTime(250) - self.m_rumble.setIntensity(1) - self.m_rumble.setDuration(1000) - self.m_rumble.setFadeTime(250) - self.m_rumble.setFadeIntensity(0.1) - - self.m_ocean = QFeedbackHapticsEffect() - self.m_ocean.setAttackIntensity(0.1) - self.m_ocean.setAttackTime(450) - self.m_ocean.setIntensity(0.8) - self.m_ocean.setDuration(6000) - self.m_ocean.setFadeTime(900) - self.m_ocean.setFadeIntensity(0.05) - self.m_ocean.setPeriod(1500) - - self.m_btnRumble = HapticButton("Rumble!") - self.m_btnOcean = HapticButton("Ocean") - self.m_btnButtonClick = HapticButton("Click") - self.m_btnNegativeEffect = HapticButton("Oops!") - self.topLayout = QGridLayout(self) - self.topLayout.addWidget(self.m_btnRumble, 0, 0) - self.topLayout.addWidget(self.m_btnOcean, 0, 1) - self.topLayout.addWidget(self.m_btnButtonClick, 1, 0) - self.topLayout.addWidget(self.m_btnNegativeEffect, 1, 1) - - self.m_btnRumble.clicked.connect(self.playRumble) - self.m_btnOcean.clicked.connect(self.playOcean) - self.m_btnButtonClick.clicked.connect(self.playButtonClick) - self.m_btnNegativeEffect.clicked.connect(self.playNegativeEffect) - - def __del__(self): - del self.m_btnRumble - del self.m_btnOcean - del self.m_btnButtonClick - del self.m_btnNegativeEffect - - def playRumble(self): - self.m_rumble.start() - print "Play rumble" - - def playOcean(self): +class EffectPlayer(QObject): + + def __init__(self, parent=None): + QObject.__init__(self, parent) + + self.m_rumble = QFeedbackHapticsEffect() + self.m_rumble.setAttackIntensity(0.1) + self.m_rumble.setAttackTime(250) + self.m_rumble.setIntensity(1) + self.m_rumble.setDuration(1000) + self.m_rumble.setFadeTime(250) + self.m_rumble.setFadeIntensity(0.1) + + self.m_ocean = QFeedbackHapticsEffect() + self.m_ocean.setAttackIntensity(0.1) + self.m_ocean.setAttackTime(450) + self.m_ocean.setIntensity(0.8) + self.m_ocean.setDuration(6000) + self.m_ocean.setFadeTime(900) + self.m_ocean.setFadeIntensity(0.05) + self.m_ocean.setPeriod(1500) + + @Slot() + def playRumble(self): + print "Starting rumble effect" + self.m_rumble.start() + + @Slot() + def playOcean(self): if self.m_ocean.state() == QFeedbackEffect.Stopped: self.m_ocean.start() print "Ocean start" @@ -108,20 +69,33 @@ class Dialog(QDialog): self.m_ocean.stop() print "Ocean stop" - def playButtonClick(self): - QFeedbackEffect.playThemeEffect(QFeedbackEffect.ThemeBasicButton) - print "Play button click" + @Slot() + def playButtonClick(self): + QFeedbackEffect.playThemeEffect(QFeedbackEffect.ThemeBasicButton) + print "Play button click" - def playNegativeEffect(self): - QFeedbackEffect.playThemeEffect(QFeedbackEffect.ThemeNegativeTacticon) - print "Play negative button click" + @Slot() + def playNegativeEffect(self): + QFeedbackEffect.playThemeEffect(QFeedbackEffect.ThemeNegativeTacticon) + print "Play negative button click" def main(): - app = QApplication([]) - w = Dialog() - w.showMaximized() - return app.exec_() + app = QApplication([]) + view = QDeclarativeView() + player = EffectPlayer() + context = view.rootContext() + context.setContextProperty("effectPlayer", player) -if __name__ == "__main__": + url = QUrl('main.qml') + view.setSource(url) + view.showFullScreen() + + app.exec_() + + +if __name__ == '__main__': main() + + + diff --git a/mobility/feedback/main.qml b/mobility/feedback/main.qml new file mode 100644 index 0000000..dd3484d --- /dev/null +++ b/mobility/feedback/main.qml @@ -0,0 +1,11 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + + id: rootWindow + showStatusBar: false + initialPage: MainPage { } + +} diff --git a/mobility/organizer/qml/OverviewPage.qml b/mobility/organizer/qml/OverviewPage.qml new file mode 100644 index 0000000..4f4f4ed --- /dev/null +++ b/mobility/organizer/qml/OverviewPage.qml @@ -0,0 +1,56 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + id: overviewPage + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + Label { + anchors.centerIn: parent + text: "No tasks" + visible: manager.todos.length == 0 + } + + Flickable { + anchors.fill: parent + clip: true + + flickableDirection: Flickable.VerticalFlick + contentHeight: todoButtons.height + contentWidth: todoButtons.width + + ButtonColumn { + id: todoButtons + + // On N9 it seems that displayWidth keeps pointing to the larger + // side of the screen, even in portrait mode... + width: screen.displayHeight - 2 * UiConstants.DefaultMargin + + Repeater { + model: manager.todos + Button { + text: modelData + onClicked: { + manager.editExistingTodo(index) + pageStack.push(Qt.createComponent("TodoEdit.qml")) + } + } + } + } + } + + tools: ToolBarLayout { + id: mainTools + ToolButton { + text: "Add Task" + onClicked: { + manager.editNewTodo() // Prepare new todo info + pageStack.push(Qt.createComponent("TodoEdit.qml")) + } + } + } + +} diff --git a/mobility/organizer/qml/TodoEdit.qml b/mobility/organizer/qml/TodoEdit.qml new file mode 100644 index 0000000..65c60d6 --- /dev/null +++ b/mobility/organizer/qml/TodoEdit.qml @@ -0,0 +1,239 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + id: editPage + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + property int todoId: -1 + + Flickable { + anchors.fill: parent + contentHeight: editCol.height + flickableDirection: Flickable.VerticalFlick + + Column { + id: editCol + + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + spacing: 10 + + Label { + text: "Subject" + } + + TextField { + id: subjectField + text: manager.todoSubject + + Keys.onReturnPressed: { + parent.focus = true; + } + } + + Label { + text: "Start Date" + } + + Column { + spacing: 20 + Button { + id: selectStartDateButton + text: manager.todoStartDateTime[1] + "/" + manager.todoStartDateTime[2] + "/" + manager.todoStartDateTime[0] + + onClicked: { + startDateSelector.day = manager.todoStartDateTime[2]; + startDateSelector.month = manager.todoStartDateTime[1]; + startDateSelector.year = manager.todoStartDateTime[0]; + startDateSelector.open() + } + + DatePickerDialog { + id: startDateSelector + + onAccepted: { + manager.setTodoStartDate(year, month, day) + } + } + } + + Button { + id: selectStartTimeButton + text: manager.todoStartDateTime[3]+ ":" + manager.todoStartDateTime[4] + + onClicked: { + startTimeSelector.hour = manager.todoStartDateTime[3]; + startTimeSelector.minute = manager.todoStartDateTime[4]; + startTimeSelector.open() + } + + TimePickerDialog { + id: startTimeSelector + fields: DateTime.Hours | DateTime.Minutes + acceptButtonText: "Confirm" + rejectButtonText: "Cancel" + + onAccepted: { + manager.setTodoStartTime(hour, minute) + } + + } + } + + } + + Label { + text: "Due Date" + } + + Column { + spacing: 20 + Button { + id: selectDueDateButton + text: manager.todoDueDateTime[1] + "/" + manager.todoDueDateTime[2] + "/" + manager.todoDueDateTime[0] + + onClicked: { + dueDateSelector.day = manager.todoDueDateTime[2]; + dueDateSelector.month = manager.todoDueDateTime[1]; + dueDateSelector.year = manager.todoDueDateTime[0]; + dueDateSelector.open() + } + + DatePickerDialog { + id: dueDateSelector + + onAccepted: { + manager.setTodoDueDate(year, month, day) + } + } + } + + Button { + id: selectDueTimeButton + text: manager.todoDueDateTime[3]+ ":" + manager.todoDueDateTime[4] + + onClicked: { + dueTimeSelector.hour = manager.todoDueDateTime[3]; + dueTimeSelector.minute = manager.todoDueDateTime[4]; + dueTimeSelector.open() + } + + TimePickerDialog { + id: dueTimeSelector + fields: DateTime.Hours | DateTime.Minutes + acceptButtonText: "Confirm" + rejectButtonText: "Cancel" + + onAccepted: { + manager.setTodoDueTime(hour, minute) + } + } + } + + } + + Label { + text: "Status" + } + + Button { + id: statusButton + text: statusSelection.model.get(statusSelection.selectedIndex).name + + onClicked: { + statusSelection.open(); + } + + + SelectionDialog { + id: statusSelection + titleText: "Select status" + selectedIndex: manager.todoStatus + + model: ListModel { + ListElement { name: "Not started" } + ListElement { name: "In progress" } + ListElement { name: "Complete" } + } + + onAccepted: { + manager.todoStatus = statusSelection.selectedIndex; + } + } + } + + Label { + text: "Priority" + } + + Button { + id: priorityButton + text: prioritySelection.model.get(prioritySelection.selectedIndex).name + + onClicked: { + prioritySelection.open(); + } + + + SelectionDialog { + id: prioritySelection + titleText: "Select priority" + selectedIndex: manager.todoPriority + + model: ListModel { + ListElement { name: "Unknown" } + ListElement { name: "Highest" } + ListElement { name: "Extremely high" } + ListElement { name: "Very high" } + ListElement { name: "High" } + ListElement { name: "Medium" } + ListElement { name: "Low" } + ListElement { name: "Very low" } + ListElement { name: "Extremely low" } + ListElement { name: "Lowest" } + } + + onAccepted: { + manager.todoPriority = prioritySelection.selectedIndex; + } + } + } + } + } + + tools: ToolBarLayout { + id: editTools + ToolButton { + text: "Save" + onClicked: { + console.log("Saving new task") + manager.todoSubject = subjectField.text; // Other fields are handled by dialog.accept signal + manager.saveTodo(); + pageStack.pop(); + } + } + ToolButton { + text: "Delete" + enabled: !manager.isNewTodo + onClicked: { + console.log("Deleting todo."); + manager.deleteCurrent(); + pageStack.pop(); + } + } + ToolButton { + text: "Cancel" + onClicked: { + console.log("Cancel task edit"); + console.log("Is new todo?" + manager.isNewTodo); + manager.reload(); + pageStack.pop(); + } + } + } + +} diff --git a/mobility/organizer/qml/main.qml b/mobility/organizer/qml/main.qml new file mode 100644 index 0000000..88c1b95 --- /dev/null +++ b/mobility/organizer/qml/main.qml @@ -0,0 +1,10 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + + id: rootWindow + showStatusBar: false + initialPage: OverviewPage { } +} diff --git a/mobility/organizer/qml/qmltodo.py b/mobility/organizer/qml/qmltodo.py new file mode 100644 index 0000000..a3523f2 --- /dev/null +++ b/mobility/organizer/qml/qmltodo.py @@ -0,0 +1,274 @@ +''' + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + + This file is part of the Qt Mobility Components. + + $QT_BEGIN_LICENSE:LGPL$ + No Commercial Usage + This file contains pre-release code and may not be distributed. + You may use this file in accordance with the terms and conditions + contained in the Technology Preview License Agreement accompanying + this package. + + GNU Lesser General Public License Usage + Alternatively, this file may be used under the terms of the GNU Lesser + General Public License version 2.1 as published by the Free Software + Foundation and appearing in the file LICENSE.LGPL included in the + packaging of this file. Please review the following information to + ensure the GNU Lesser General Public License version 2.1 requirements + will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + If you have questions regarding the use of this file, please contact + Nokia at qt-info@nokia.com. +''' + +import os +import sys + +from PySide.QtCore import QObject, Signal, Slot, Property, QUrl, qWarning +from PySide.QtCore import QAbstractItemModel, QDate, QDateTime, QTime +from PySide.QtGui import QApplication +from PySide.QtDeclarative import QDeclarativeView +from QtMobility.Organizer import QOrganizerManager, QOrganizerItemSortOrder +from QtMobility.Organizer import QOrganizerTodo, QOrganizerTodoTime +from QtMobility.Organizer import QOrganizerItemFilter, QOrganizerItemDetailFilter +from QtMobility.Organizer import QOrganizerItemPriority, QOrganizerTodoProgress +from QtMobility.Organizer import QOrganizerItemType + + +class TodoManager(QObject): + + def __init__(self): + QObject.__init__(self) + + self.manager = QOrganizerManager("memory") + self._todos = [] # FIXME Use a model instead of a string list as model + self._todo = None # Current todo being edited or created + + self.reload() + + @Slot() + def reload(self): + self._todos = [] + + sortOrder = QOrganizerItemSortOrder() + sortOrder.setDetailDefinitionName(QOrganizerTodoTime.DefinitionName, + QOrganizerTodoTime.FieldDueDateTime) + + todoFilter = QOrganizerItemFilter() + + items = self.manager.items(todoFilter, [sortOrder]) + + todos = [] + for item in items: + if item.type() == QOrganizerItemType.TypeTodo: + todo = QOrganizerTodo(item) + + display = todo.startDateTime().toString("yy/MM/dd hh:mm") +\ + "-" + todo.dueDateTime().toString("yy/MM/dd hh:mm") +\ + "\n" + todo.displayLabel() + + todos.append((display, todo)) + + self._todos = todos + self.todosChanged.emit() + + @Slot() + def deleteCurrent(self): + self.manager.removeItem(self._todo.id()) + self.reload() + + currentTodoChanged = Signal() + + @Slot() + def editNewTodo(self): + """Sets the current todo to a newly created todo""" + newTodo = QOrganizerTodo() + newTodo.setPriority(QOrganizerItemPriority.HighPriority) + newTodo.setStatus(QOrganizerTodoProgress.StatusNotStarted) + currentDateTime = QDateTime(QDate.currentDate(), QTime.currentTime()) + newTodo.setStartDateTime(currentDateTime) + newTodo.setDueDateTime(currentDateTime.addSecs(60*60)) + + self._todo = newTodo + self._todo.isNewTodo = True + self.currentTodoChanged.emit() + + @Property(bool, notify=currentTodoChanged) + def isNewTodo(self): + return self._todo.isNewTodo if self._todo else True + + @Slot(int) + def editExistingTodo(self, index): + self._todo = self._todos[index][1] + self._todo.isNewTodo = False + self.currentTodoChanged.emit() + + @Slot() + def saveTodo(self): + self.manager.saveItem(self._todo) + self._todo = None + self.reload() + + todosChanged = Signal() + @Property("QStringList", notify=todosChanged) + def todos(self): + return [x[0] for x in self._todos] + + @todos.setter + def setTodo(self, value): + self._todos = value + self.todosChanged.emit() + + # Subject + currentTodoSubjectChanged = Signal() + + @Property(str, notify=currentTodoSubjectChanged) + def todoSubject(self): + return self._todo.displayLabel() + + @todoSubject.setter + def setTodoSubject(self, value): + self._todo.setDisplayLabel(value) + self.currentTodoSubjectChanged.emit() + + # Dates and times + def datetimeToStrList(self, datetime): + date = datetime.date() + time = datetime.time() + return (("%02d "*5) % (date.year(), date.month(), date.day(), + time.hour(), time.minute())).split() + +# @Slot(result="QStringList") + @Property("QStringList", notify=currentTodoChanged) + def todoStartDateTime(self): + return self.datetimeToStrList(self._todo.startDateTime()) + + @Slot(int, int, int) + def setTodoStartDate(self, year, month, day): + orig_time = self._todo.startDateTime().time() + date = QDate(year, month, day) + datetime = QDateTime(date, orig_time) + + self._todo.setStartDateTime(datetime) + self.currentTodoChanged.emit() + + @Slot(int, int) + def setTodoStartTime(self, hour, minute): + orig_date = self._todo.startDateTime().date() + time = QTime(hour, minute) + datetime = QDateTime(orig_date, time) + + self._todo.setStartDateTime(datetime) + self.currentTodoChanged.emit() + + @Property("QStringList", notify=currentTodoChanged) + def todoDueDateTime(self): + return self.datetimeToStrList(self._todo.dueDateTime()) + + @Slot(int, int, int) + def setTodoDueDate(self, year, month, day): + orig_time = self._todo.dueDateTime().time() + date = QDate(year, month, day) + datetime = QDateTime(date, orig_time) + + self._todo.setDueDateTime(datetime) + + self.currentTodoChanged.emit() + + @Slot(int, int) + def setTodoDueTime(self, hour, minute): + orig_date = self._todo.dueDateTime().date() + time = QTime(hour, minute) + datetime = QDateTime(orig_date, time) + + self._todo.setDueDateTime(datetime) + + self.currentTodoChanged.emit() + + # Status + + Status = [ + QOrganizerTodoProgress.StatusNotStarted, + QOrganizerTodoProgress.StatusInProgress, + QOrganizerTodoProgress.StatusComplete, + ] + + @Property(int, notify=currentTodoChanged) + def todoStatus(self): + status = self._todo.status() + try: + index = self.Status.index(status) + return index + except ValueError: + return 0 + + @todoStatus.setter + def setTodoStatus(self, value): + try: + self._todo.setStatus(self.Status[value]) + self.currentTodoChanged.emit() + except IndexError: + pass # Fail silently... + + # Priority + + Priority = [ + QOrganizerItemPriority.UnknownPriority, + QOrganizerItemPriority.HighestPriority, + QOrganizerItemPriority.ExtremelyHighPriority, + QOrganizerItemPriority.VeryHighPriority, + QOrganizerItemPriority.HighPriority, + QOrganizerItemPriority.MediumPriority, + QOrganizerItemPriority.LowPriority, + QOrganizerItemPriority.VeryLowPriority, + QOrganizerItemPriority.ExtremelyLowPriority, + QOrganizerItemPriority.LowestPriority, + ] + + @Property(int, notify=currentTodoChanged) + def todoPriority(self): + priority = self._todo.priority() + try: + index = self.Priority.index(priority) + return index + except ValueError: + return 0 + + @todoPriority.setter + def setTodoPriority(self, value): + try: + self._todo.setPriority(self.Priority[value]) + self.currentTodoChanged.emit() + except IndexError: + pass # Fail silently... + + +def main(): + app = QApplication([]) + view = QDeclarativeView() + manager = TodoManager() + context = view.rootContext() + context.setContextProperty("manager", manager) + + url = QUrl('main.qml') + view.setSource(url) + + if "-no-fs" not in sys.argv: + view.showFullScreen() + else: + view.show() + + app.exec_() + + +if __name__ == '__main__': + main() + + diff --git a/mobility/samplephonebook/qml/ContactEdit.qml b/mobility/samplephonebook/qml/ContactEdit.qml new file mode 100644 index 0000000..295f32b --- /dev/null +++ b/mobility/samplephonebook/qml/ContactEdit.qml @@ -0,0 +1,116 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: contactEdit + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + + Flickable { + anchors.fill: parent + contentHeight: textFields.height + Column { + id: textFields + anchors.fill: parent + Label { + text: "Name" + } + TextField { + id: fieldName + anchors.left: parent.left + anchors.right: parent.right + text: manager.contactData[0] + } + Label { + text: "Phone" + } + TextField { + id: fieldPhone + text: manager.contactData[1] + anchors.left: parent.left + anchors.right: parent.right + } + Label { + text: "Email" + } + TextField { + id: fieldEmail + text: (manager.emailEnabled ? manager.contactData[2] : "<not supported>") + readOnly: !manager.emailEnabled + anchors.left: parent.left + anchors.right: parent.right + } + Label { + text: "Address" + } + TextField { + id: fieldAddress + text: (manager.addressEnabled ? manager.contactData[3] : "<not supported>") + readOnly: !manager.addressEnabled + anchors.left: parent.left + anchors.right: parent.right + } + + } + } + Dialog { + id: errorDialog + visualParent: contactEdit + title: Item { + id: titleField + height: errorDialog.platformStyle.titleBarHeight + width: parent.width + Label { + id: titleLabel + anchors.verticalCenter: titleField.verticalCenter + font.capitalization: Font.MixedCase + color: "white" + text: "Error" + } + } + content:Item { + id: name + height: childrenRect.height + Text { + id: text + font.pixelSize: 22 + color: "white" + text: manager.errorMessage + } + } + buttons: ButtonRow { + platformStyle: ButtonStyle { } + anchors.horizontalCenter: parent.horizontalCenter + Button {id: b1; text: "Edit fields"; onClicked: errorDialog.accept()} + Button {id: b2; text: "Cancel entry"; onClicked: errorDialog.reject()} + } + } + + tools: ToolBarLayout { + id: mainTools + ToolButton { + text: "Save" + onClicked: { + console.log("Save contact"); + if (!manager.saveContact(fieldName.text, fieldPhone.text, fieldEmail.text, fieldAddress.text)) { + errorDialog.open(); + } else { + manager.selectContact(-1); + pageStack.pop(); + } + } + } + ToolButton { + text: "Cancel" + onClicked: { + console.log("Cancel edit/add") + manager.selectContact(-1) + pageStack.pop() + } + } + } + + +} diff --git a/mobility/samplephonebook/qml/MainPage.qml b/mobility/samplephonebook/qml/MainPage.qml new file mode 100644 index 0000000..bbbef5b --- /dev/null +++ b/mobility/samplephonebook/qml/MainPage.qml @@ -0,0 +1,47 @@ + + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + id: mainPage + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + Flickable { + anchors.fill: parent + + ButtonColumn { + Repeater { + model: manager.contactsNames + Button { + text: modelData + onClicked: { + console.log("Editing existing contact") + manager.selectContact(index) + pageStack.push(Qt.createComponent("ContactEdit.qml")) + } + } + } + } + } + + tools: ToolBarLayout { + id: mainTools + ToolButton { + text: "Add..." + onClicked: { + console.log("Add new contact") + pageStack.push(Qt.createComponent("ContactEdit.qml")) + } + } + ToolButton { + text: "Select backend..." + onClicked: { + pageStack.push(Qt.createComponent("SelectBackend.qml")) + } + } + } + +} diff --git a/mobility/samplephonebook/qml/SelectBackend.qml b/mobility/samplephonebook/qml/SelectBackend.qml new file mode 100644 index 0000000..ec927e8 --- /dev/null +++ b/mobility/samplephonebook/qml/SelectBackend.qml @@ -0,0 +1,41 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: selectBackend + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + + ListView { + anchors.fill: parent + anchors.centerIn: parent + model: manager.availableManagers + delegate: Button { + text: modelData + onClicked: { + manager.selectManager(modelData) + pageStack.pop() + } + } + } + + tools: ToolBarLayout { + id: mainTools + ToolButton { + text: "Select" + onClicked: { + console.log("Selected new backend") + pageStack.pop() + } + } + ToolButton { + text: "Cancel" + onClicked: { + console.log("Cancel edit/add") + pageStack.pop() + } + } + } +} diff --git a/mobility/samplephonebook/qml/main.qml b/mobility/samplephonebook/qml/main.qml new file mode 100644 index 0000000..49eb008 --- /dev/null +++ b/mobility/samplephonebook/qml/main.qml @@ -0,0 +1,10 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + + id: rootWindow + showStatusBar: false + initialPage: MainPage { } +} diff --git a/mobility/samplephonebook/qml/qmlsamplephonebook.py b/mobility/samplephonebook/qml/qmlsamplephonebook.py new file mode 100644 index 0000000..796c15b --- /dev/null +++ b/mobility/samplephonebook/qml/qmlsamplephonebook.py @@ -0,0 +1,274 @@ +''' + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + + This file is part of the Qt Mobility Components. + + $QT_BEGIN_LICENSE:LGPL$ + No Commercial Usage + This file contains pre-release code and may not be distributed. + You may use this file in accordance with the terms and conditions + contained in the Technology Preview License Agreement accompanying + this package. + + GNU Lesser General Public License Usage + Alternatively, this file may be used under the terms of the GNU Lesser + General Public License version 2.1 as published by the Free Software + Foundation and appearing in the file LICENSE.LGPL included in the + packaging of this file. Please review the following information to + ensure the GNU Lesser General Public License version 2.1 requirements + will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + If you have questions regarding the use of this file, please contact + Nokia at qt-info@nokia.com. +''' + +import os +import sys + +from PySide.QtCore import QObject, Signal, Slot, Property, QUrl, qWarning +from PySide.QtGui import QApplication +from PySide.QtDeclarative import QDeclarativeView +from QtMobility.Contacts import QContactManager, QContactPhoneNumber, QContact +from QtMobility.Contacts import QContactAddress, QContactEmailAddress, QContactType +from QtMobility.Contacts import QContactName + + +class MyContactManager(QObject): + + def __init__(self): + QObject.__init__(self) + + self._availableManagers = {} + self._contacts = [] + + self.initialisedManagers = {} + self.manager = None + self.contactId = 0 + + self._errorMessage = "" + self._emailEnabled = False + self._addressEnabled = True + + availableMgrs = QContactManager.availableManagers() + availableMgrs.remove("invalid") + for managerName in availableMgrs: + params = {} + managerUri = QContactManager.buildUri(managerName, params) + self._availableManagers[managerName] = managerUri + + self.selectManager(self.availableManagers[0]) + + # Email Enabled property + onErrorMessageChanged = Signal() + + @Property(str, notify=onErrorMessageChanged) + def errorMessage(self): + return self._errorMessage + + @errorMessage.setter + def setErrorMessage(self, value): + self._errorMessage = value + self.onErrorMessageChanged.emit() + + # Email Enabled property + onEmailEnabledChanged = Signal() + + @Property("bool", notify=onEmailEnabledChanged) + def emailEnabled(self): + return self._emailEnabled + + @emailEnabled.setter + def setEmailEnabled(self, value): + self._emailEnabled = value + self.onEmailEnabledChanged.emit() + + # Address Enabled property + onAddressEnabledChanged = Signal() + + @Property("bool", notify=onAddressEnabledChanged) + def addressEnabled(self): + return self._addressEnabled + + @addressEnabled.setter + def setAddressEnabled(self, value): + self._addressEnabled = value + self.onAddressEnabledChanged.emit() + + @Property("QStringList", constant=True) + def availableManagers(self): + return self._availableManagers.keys() + + # List of contacts changed property + onContactsChanged = Signal() + + @Property("QStringList", notify=onContactsChanged) + def contactsNames(self): + return [x[0] for x in self._contacts] + + onSelectedContactChanged = Signal() + + def emitContactsChanged(self): + self.onContactsChanged.emit() + + @Property("QStringList", notify=onSelectedContactChanged) + def contactData(self): + if not self.contactId: + print "Trying to get data while no contact selected..." + return ["", "", "", ""] + + print "Getting existing contact data" + + contact = self.manager.contact(self.contactId) + + name = self.manager.synthesizedContactDisplayLabel(contact) + phone = contact.detail(QContactPhoneNumber.DefinitionName).value(QContactPhoneNumber.FieldNumber) + + if self.emailEnabled: + emailObj = contact.detail(QContactEmailAddress.DefinitionName) + email = emailObj.value(QContactEmailAddress.FieldEmailAddress) + else: + email = "" + + if self.addressEnabled: + addressObj = contact.detail(QContactAddress.DefinitionName) + address = addressObj.value(QContactAddress.FieldStreet) + else: + address = "" + + return name, phone, email, address + + @Slot(int) + def selectContact(self, idx): + if idx == -1: + self.contactId = 0 + else: + self.contactId = self._contacts[idx][1] + + @Slot(str) + def selectManager(self, name): + managerUri = self._availableManagers[name] + + # first, check to see if they reselected the same backend. + if self.manager and self.manager.managerUri() == managerUri: + return + + # the change is real. update. + if self.initialisedManagers.has_key(managerUri): + self.manager = self.initialisedManagers[managerUri] + else: + self.manager = QContactManager.fromUri(managerUri) + if self.manager.error(): + print "Failed to open store...." + del self.manager + self.manager = None + return + self.initialisedManagers[managerUri] = self.manager + + defs = self.manager.detailDefinitions(QContactType.TypeContact) + + self.emailEnabled = bool(defs["EmailAddress"]) + self.addressEnabled = bool(defs["Address"]) + + self.updateContactList() + + def updateContactList(self): + self._contacts = [] + + for contact in self.manager.contacts(): + name = self.manager.synthesizedContactDisplayLabel(contact) + self._contacts.append((name, contact.localId())) + self.emitContactsChanged() + + saveEmptyName = Signal() + + @Slot(str, str, str, str, result=bool) + def saveContact(self, name, phone, email, address): + if not self.manager: + qWarning("No manager selected, cannot save") + return + + if self.contactId: + print "Updating existing contact" + contact = self.manager.contact(self.contactId) + else: + print "Creating new contact" + contact = QContact() + + if not name: + self.errorMessage = "Name must not be empty!" + return False + + # Name + if name != self.manager.synthesizedContactDisplayLabel(contact): + saveNameField = self.nameField() + if saveNameField: + nm = QContactName(contact.detail(QContactName().DefinitionName)) + nm.setValue(saveNameField, name) + contact.saveDetail(nm) + + # Phone + phoneObj = QContactPhoneNumber(contact.detail(QContactPhoneNumber.DefinitionName)) + phoneObj.setNumber(phone) + contact.saveDetail(phoneObj) + + # Email + if self.emailEnabled: + emailObj = QContactEmailAddress(contact.detail(QContactEmailAddress.DefinitionName)) + emailObj.setEmailAddress(email) + contact.saveDetail(emailObj) + + # Address + if self.addressEnabled: + addressObj = QContactAddress(contact.detail(QContactAddress.DefinitionName)) + addressObj.setStreet(address) + contact.saveDetail(addressObj) + + contact = self.manager.compatibleContact(contact) + success = self.manager.saveContact(contact) + if not success: + qWarning("Failed to save contact") + + self.updateContactList() + + return True + + + def nameField(self): + # return the field which the name data should be saved in. + if not self.manager: + return "" + + defs = self.manager.detailDefinitions(QContactType.TypeContact) + nameDef = defs[QContactName.DefinitionName] + if QContactName.FieldCustomLabel in nameDef.fields(): + return QContactName.FieldCustomLabel + elif QContactName.FieldFirstName in nameDef.fields(): + return QContactName.FieldFirstName + else: + return "" + +def main(): + app = QApplication([]) + view = QDeclarativeView() + manager = MyContactManager() + context = view.rootContext() + context.setContextProperty("manager", manager) + + url = QUrl('main.qml') + view.setSource(url) + view.showFullScreen() + + app.exec_() + + +if __name__ == '__main__': + main() + + + diff --git a/mobility/servicebrowser/qml/HoldButton.qml b/mobility/servicebrowser/qml/HoldButton.qml new file mode 100644 index 0000000..32ce02e --- /dev/null +++ b/mobility/servicebrowser/qml/HoldButton.qml @@ -0,0 +1,45 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Button { + text: "" + + property int holdTime: 800 // Hold time in msecs + + signal held + signal clickedWithoutHold // Replace the original clicked signal, which keeps being emitted. + + onPressedChanged: { + if (pressed) { + // Start counting + holdTimer.wasTriggered = false; + holdTimer.start(); + } else { + // Just stop the timer + holdTimer.restart(); + holdTimer.stop(); + } + + if (!pressed && !holdTimer.wasTriggered) { + // Replaces the clicked signal + clickedWithoutHold(); + holdTimer.restart(); + holdTimer.stop(); + } + } + + Timer { + property bool wasTriggered: false + id: holdTimer + interval: holdTime + running: false + repeat: false + onTriggered: { + wasTriggered = true + held(); + restart(); + stop(); + } + } +} diff --git a/mobility/servicebrowser/qml/ImplementationDetails.qml b/mobility/servicebrowser/qml/ImplementationDetails.qml new file mode 100644 index 0000000..bfbf139 --- /dev/null +++ b/mobility/servicebrowser/qml/ImplementationDetails.qml @@ -0,0 +1,60 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + + property string implementationSpec: "" + property int implementationIndex: -1 + property string serviceName: "" + property int serviceIndex: -1 + + id: implementationDetails + anchors.margins: UiConstants.DefaultMargin + //orientationLock: PageOrientation.LockPortrait + + Label { + id: titleLabel + anchors.top: parent.top + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + text: "Implementation: " + implementationSpec + } + + Flickable { + anchors.top: titleLabel.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + contentHeight: servicesButtons.height + + ButtonColumn { + id: servicesButtons + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + Repeater { + model: manager.implementationDetails(implementationSpec, implementationIndex, + serviceName, serviceIndex); + Button { + width: parent.width + text: modelData + onClicked: { + console.log("Selecting service") + //manager.selectService(index) + } + } + } + } + } + + tools: ToolBarLayout { + id: implementationPageTools + ToolButton { + text: "Back" + onClicked: { + pageStack.pop(); + } + } + } + +} diff --git a/mobility/servicebrowser/qml/ServiceImplementations.qml b/mobility/servicebrowser/qml/ServiceImplementations.qml new file mode 100644 index 0000000..28791cc --- /dev/null +++ b/mobility/servicebrowser/qml/ServiceImplementations.qml @@ -0,0 +1,93 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + + property string serviceName: "" + property int serviceIndex: -1 + + id: serviceImplementations + anchors.margins: UiConstants.DefaultMargin + //orientationLock: PageOrientation.LockPortrait + + Label { + id: titleLabel + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + text: "Service: " + serviceName + } + + Flickable { + anchors.top: titleLabel.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + contentHeight: servicesButtons.height + + ButtonColumn { + id: servicesButtons + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + Repeater { + id: buttonRepeater + model: manager.serviceImplementations(serviceName, serviceIndex) + + HoldButton { + text: modelData + // TODO Getting some "Unable to assing undefined value" at this line when + // setting model to a different list (line 73), but the example is working + // so far. + width: parent.width + + onHeld: { + setDefaultDialog.titleText = "Change default implementation"; + setDefaultDialog.message = "Set " + modelData + " as default?"; + setDefaultDialog.index = index; + setDefaultDialog.open(); + } + + onClickedWithoutHold: { + pageStack.push(Qt.createComponent("ImplementationDetails.qml"), + { implementationSpec: modelData, + implementationIndex: index, + serviceName: serviceName, + serviceIndex: serviceIndex + }); + + } + } + } + } + } + + QueryDialog { + property int index: -1 + + id: setDefaultDialog + acceptButtonText: "Yes" + rejectButtonText: "No" + + onAccepted: { + console.log("Accepted"); + manager.setDefault(index); + buttonRepeater.model = manager.serviceImplementations(serviceName, serviceIndex) + } + + onRejected: { + console.log("Rejected"); + } + + } + + tools: ToolBarLayout { + id: implementationPageTools + ToolButton { + text: "Back" + onClicked: { + pageStack.pop(); + } + } + } + +} diff --git a/mobility/servicebrowser/qml/ServicesPage.qml b/mobility/servicebrowser/qml/ServicesPage.qml new file mode 100644 index 0000000..4bcf85c --- /dev/null +++ b/mobility/servicebrowser/qml/ServicesPage.qml @@ -0,0 +1,61 @@ + + +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Page { + id: servicePage + anchors.margins: UiConstants.DefaultMargin + //orientationLock: PageOrientation.LockPortrait + + Label { + id: titleLabel + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + text: "Services available" + } + + Flickable { + anchors.top: titleLabel.bottom + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + contentHeight: servicesButtons.height + + ButtonColumn { + id: servicesButtons + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + Repeater { + model: manager.servicesNames + Button { + text: modelData + onClicked: { + console.log("Selecting service") + pageStack.push(Qt.createComponent("ServiceImplementations.qml"), + { serviceName: modelData, + serviceIndex: index }) + } + } + } + } + } + + /*tools: ToolBarLayout { + id: mainTools + ToolButton { + text: "Add..." + onClicked: { + console.log("Add new contact") + pageStack.push(Qt.createComponent("ContactEdit.qml")) + } + } + ToolButton { + text: "Select backend..." + onClicked: { + pageStack.push(Qt.createComponent("SelectBackend.qml")) + } + } + }*/ + +} diff --git a/mobility/servicebrowser/qml/main.qml b/mobility/servicebrowser/qml/main.qml new file mode 100644 index 0000000..ee8dfe8 --- /dev/null +++ b/mobility/servicebrowser/qml/main.qml @@ -0,0 +1,10 @@ + +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + + id: rootWindow + showStatusBar: false + initialPage: ServicesPage { } +} diff --git a/mobility/servicebrowser/qml/qmlbrowser.py b/mobility/servicebrowser/qml/qmlbrowser.py new file mode 100644 index 0000000..4ac9b51 --- /dev/null +++ b/mobility/servicebrowser/qml/qmlbrowser.py @@ -0,0 +1,134 @@ +''' + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + + This file is part of the Qt Mobility Components. + + $QT_BEGIN_LICENSE:LGPL$ + No Commercial Usage + This file contains pre-release code and may not be distributed. + You may use this file in accordance with the terms and conditions + contained in the Technology Preview License Agreement accompanying + this package. + + GNU Lesser General Public License Usage + Alternatively, this file may be used under the terms of the GNU Lesser + General Public License version 2.1 as published by the Free Software + Foundation and appearing in the file LICENSE.LGPL included in the + packaging of this file. Please review the following information to + ensure the GNU Lesser General Public License version 2.1 requirements + will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + If you have questions regarding the use of this file, please contact + Nokia at qt-info@nokia.com. +''' + +import os +import sys + +from PySide.QtCore import QObject, Signal, Slot, Property, QUrl, qWarning +from PySide.QtGui import QApplication +from PySide.QtDeclarative import QDeclarativeView +from QtMobility.ServiceFramework import QServiceManager + + +class ServiceManager(QObject): + + def __init__(self): + QObject.__init__(self) + + self._services = [] + self._errorMessage = "" + self._emailEnabled = False + self._addressEnabled = True + + self.manager = QServiceManager(self) + + self.reloadServicesList() + + def reloadServicesList(self): + self._services = [] + for service in self.manager.findServices(): + self._services.append(service) + self.onServicesChanged.emit() + + onServicesChanged = Signal() + + @Property("QStringList", notify=onServicesChanged) + def servicesNames(self): + return self._services + + @Slot(str, int, result="QStringList") + def serviceImplementations(self, serviceName, serviceIndex): + print "Interfaces implemented by ", serviceName + + self._implementations = [] + for descriptor in self.manager.findInterfaces(serviceName): + impSpec = "%s %d.%d" % (descriptor.interfaceName(), + descriptor.majorVersion(), + descriptor.minorVersion()) + + if not serviceName: + impSpec += " (" + descriptor.serviceName() + ")" + + default = self.manager.interfaceDefault(descriptor.interfaceName()) + if descriptor == default: + impSpec += " (default)" + + self._implementations.append((impSpec, descriptor)) + return [x[0] for x in self._implementations] + + @Slot(str, int, str, int, result="QStringList") + def implementationDetails(self, implementationSpec, implementationIndex, + serviceName, serviceIndex): + + selectedImplementation = self._implementations[implementationIndex][1] + implementationRef = self.manager.loadInterface(selectedImplementation) + attributes = [] + + if not implementationRef: + return ["(Error loading service plugin)"] + + metaObject = implementationRef.metaObject() + + for i in range(metaObject.methodCount()): + method = metaObject.method(i) + attributes.append("[METHOD] " + method.signature()) + + for i in range(metaObject.propertyCount()): + p = metaObject.property(i) + attributes.append("[PROPERTY] " + p.name()) + + return attributes if attributes else ["(no attributes found)"] + + @Slot(int) + def setDefault(self, index): + descriptor = self._implementations[index][1] + + if descriptor.isValid(): + if self.manager.setInterfaceDefault(descriptor): + pass + +def main(): + app = QApplication([]) + view = QDeclarativeView() + manager = ServiceManager() + context = view.rootContext() + context.setContextProperty("manager", manager) + + url = QUrl('main.qml') + view.setSource(url) + view.showFullScreen() + + app.exec_() + + +if __name__ == '__main__': + main() + + diff --git a/mobility/servicebrowser/servicebrowser.py b/mobility/servicebrowser/servicebrowser.py index c6ed671..c034018 100644 --- a/mobility/servicebrowser/servicebrowser.py +++ b/mobility/servicebrowser/servicebrowser.py @@ -89,7 +89,7 @@ class ServiceBrowser(QWidget): for desc in descriptors: text = "%s %d.%d" % (desc.interfaceName(), desc.majorVersion(), desc.minorVersion()) - if len(serviceName) == 0: + if not serviceName: text += " (" + desc.serviceName() + ")" defaultInterfaceImpl = self.serviceManager.interfaceDefault(desc.interfaceName()) diff --git a/mobility/sysinfo/dialog.py b/mobility/sysinfo/dialog.py index bd5fba0..b1dfb33 100644 --- a/mobility/sysinfo/dialog.py +++ b/mobility/sysinfo/dialog.py @@ -206,7 +206,7 @@ class Dialog(QWidget, Ui_Dialog): def netStatusComboActivated(self, index): status = "" - reIndex = index + reIndex = QSystemNetworkInfo.NetworkMode(index) self.displayNetworkStatus(self.ni.networkStatus(reIndex)) self.macAddressLabel.setText(self.ni.macAddress(reIndex)) strength = self.ni.networkSignalStrength(reIndex) diff --git a/mobility/sysinfo/qml/AvailableLanguages.qml b/mobility/sysinfo/qml/AvailableLanguages.qml new file mode 100644 index 0000000..9d20ca6 --- /dev/null +++ b/mobility/sysinfo/qml/AvailableLanguages.qml @@ -0,0 +1,21 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: availableLanguages + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockPortrait + + ListView { + anchors.fill: parent + anchors.centerIn: parent + model: sysinfo.availableManagers + delegate: Button { + text: modelData + onClicked: { + languageButton.text = text + pageStack.pop() + } + } + } +} diff --git a/mobility/sysinfo/qml/DevicePage.qml b/mobility/sysinfo/qml/DevicePage.qml new file mode 100644 index 0000000..ab60424 --- /dev/null +++ b/mobility/sysinfo/qml/DevicePage.qml @@ -0,0 +1,73 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: devicePage + orientationLock: PageOrientation.LockLandscape + Flickable { + id: flickableDevice + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + contentHeight: columnDevice.height + toolBarLayout.height + contentWidth: flickableDevice.width + Column { + id: columnDevice + anchors.top: parent.top + anchors.topMargin: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + spacing: 25 + ProgressBar { + id: progressBar + minimumValue: 0 + maximumValue: 100 + value: 10 + width: parent.width + } + Label { text: "Power state" } + ButtonColumn { + RadioButton { text: "Unknown power" } + RadioButton { text: "Battery power" } + RadioButton { text: "Wall power" } + RadioButton { text: "Wall Power charging Battery" } + spacing: 10 + } + Row { + Label { text: "IMEI: " } + Label { id: labelIMEI; text: sysinfo.imei } + } + Row { + Label { text: "IMSI: " } + Label { id: labelIMSI; text: sysinfo.imsi } + } + Row { + Label { text: "Manufacturer: " } + Label { id: labelManufacturer; text: sysinfo.manufacturer } + } + Row { + Label { text: "Model: " } + Label { id: labelModel; text: sysinfo.model } + } + Row { + Label { text: "Product: " } + Label { id: labelProduct; text: sysinfo.product } + } + Row { + Button { id: buttonLock; iconSource: "../general_unlock.png"; checked: sysinfo.deviceLock } + Label { text: "Device lock"; anchors.verticalCenter: parent.verticalCenter } + } + Row { + Label { text: "Current profile: " } + Label { id: labelProfile; text: sysinfo.profile } + } + Row { + Label { text: "Input method " } + Label { id: labelInputMethod; text: sysinfo.inputMethod } + } + RadioButton { text: "Bluetooth on"; checked: sysinfo.bluetoothState } + } + } + ScrollDecorator { + flickableItem: flickableDevice + } +} diff --git a/mobility/sysinfo/qml/DisplayPage.qml b/mobility/sysinfo/qml/DisplayPage.qml new file mode 100644 index 0000000..205fafc --- /dev/null +++ b/mobility/sysinfo/qml/DisplayPage.qml @@ -0,0 +1,58 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: displayPage + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockLandscape + Flickable { + id: flickableDisplay + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + contentHeight: columnDisplay.height + toolBarLayout.height + contentWidth: flickableDisplay.width + Column { + id: columnDisplay + anchors.top: parent.top + anchors.topMargin: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + spacing: 25 + Row { + Label { text: "Brightness: " } + Label { id: labelBrightness; text: sysinfo.displayBrightness } + } + Row { + Label { text: "Color depth: " } + Label { id: labelColorDepth; text: sysinfo.colorDepth } + } +/* Row { + Label { text: "Orientation: " } + Label { id: labelOrientation; text: "" } + } + Row { + Label { text: "Contrast: " } + Label { id: labelContrast; text: "" } + } + Row { + Label { text: "DPI Width: " } + Label { id: labelDPIWidth; text: "" } + } + Row { + Label { text: "DPI Height: " } + Label { id: labelDPIHeight; text: "" } + } + Row { + Label { text: "Physical Width: " } + Label { id: labelPhysicalWidth; text: "" } + } + Row { + Label { text: "Physical Height: " } + Label { id: labelPhysicalHeight; text: "" } + }*/ + } + } + ScrollDecorator { + flickableItem: flickableDisplay + } +} diff --git a/mobility/sysinfo/qml/GeneralPage.qml b/mobility/sysinfo/qml/GeneralPage.qml new file mode 100644 index 0000000..48dafbb --- /dev/null +++ b/mobility/sysinfo/qml/GeneralPage.qml @@ -0,0 +1,60 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: generalPage + orientationLock: PageOrientation.LockLandscape + anchors.margins: UiConstants.DefaultMargin + + Column { + anchors.fill: parent + spacing: 25 + Row { + spacing: 20 + Label { text: "Current language:" } + Label { id: currentLanguage; text: sysinfo.currentLanguage } + } + Row { + spacing: 20 + Label { text: "Current country:" } + Label { id: currentCountry; text: "currentCountry" } + } + Row { + spacing: 20 + Label { text: "Available languages:"; anchors.verticalCenter: parent.verticalCenter } + Button { + id: languageButton + text: "Select a language" + onClicked: { + pageStack.push(Qt.createComponent("AvailableLanguages.qml")) + } + } + } + Row { + spacing: 20 + Label { text: "Version"; anchors.verticalCenter: parent.verticalCenter } + Button { + id: versionButton + text: "Select version" + onClicked: pageStack.push(Qt.createComponent("AvailableVersions.qml")) + + } + TextField { + text: "" + } + } + + Row { + spacing: 20 + Label { text: "Feature supported"; anchors.verticalCenter: parent.verticalCenter } + Button { + id: featureButton + text: "Select feature" + onClicked: pageStack.push(Qt.createComponent("AvailableFeatures.qml")) + } + TextField { + text: "" + } + } + } +} diff --git a/mobility/sysinfo/qml/NetworkDetails.qml b/mobility/sysinfo/qml/NetworkDetails.qml new file mode 100644 index 0000000..9ad2527 --- /dev/null +++ b/mobility/sysinfo/qml/NetworkDetails.qml @@ -0,0 +1,67 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 +import com.nokia.extras 1.1 + +Sheet { + + id: sheet + + property string networkMode: "" + + acceptButtonText: "Close" + rejectButtonText: "" + + title: Label { + text: "Details for network mode " + sheet.networkMode + } + + content: Flickable { + anchors.fill: parent + anchors.margins: UiConstants.DefaultMargin + contentWidth: col.width + contentHeight: col.height + flickableDirection: Flickable.VerticalFlick + + Column { + id: col + + anchors.top: parent.top +// anchors.left: parent.left +// anchors.right: parent.right + spacing: 10 + + Label { + text: "Network status: " + sysinfo.networkStatus(networkMode) + } + + Label { + text: "Network name: " + sysinfo.networkName(networkMode) + } + + Label { + text: "Interface name: " + sysinfo.networkInterfaceName(networkMode) + } + + Label { + text: "MAC Address: " + sysinfo.networkMacAddress(networkMode) + } + + Row { + anchors.left: col.left + anchors.right: col.right + + spacing: 10 + Label { + text: "Signal strength:" + } + + ProgressBar { + width: 600 + minimumValue: -1 + maximumValue: 100 + value: sysinfo.networkSignalStrength(networkMode) + } + } + } + } +} diff --git a/mobility/sysinfo/qml/NetworkPage.qml b/mobility/sysinfo/qml/NetworkPage.qml new file mode 100644 index 0000000..bb44e6e --- /dev/null +++ b/mobility/sysinfo/qml/NetworkPage.qml @@ -0,0 +1,76 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + + id: page + orientationLock: PageOrientation.LockLandscape + anchors.margins: UiConstants.DefaultMargin + + Flickable { + id: flickNetwork + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + contentHeight: colNetwork.height + toolBarLayout.height + contentWidth: flickNetwork.width + + Column { + id: colNetwork + spacing: 20 + + ButtonColumn { + id: columnNetworks + //anchors.top: parent.top + //width: parent.width + + Repeater { + model: sysinfo.networksNames + Button { + text: modelData + onClicked: { + console.log("Getting info for" + modelData); + var component = Qt.createComponent("NetworkDetails.qml"); + if (component.status == Component.Ready) { + var networkSheet = component.createObject(page, + { + "networkMode": modelData + }); + networkSheet.open(); + } else { + console.log("Component not ready"); + } + } + } + } + } + + // Cell ID stuff + Label { + text: "Cell ID: " + sysinfo.cellId() + } + + Label { + text: "Location Area Code: " + sysinfo.locationAreaCode() + } + + Label { + text: "Current Mobile Country Code: " + sysinfo.currentMCC() + } + + Label { + text: "Current Mobile Network Code: " + sysinfo.currentMNC() + } + + Label { + text: "Home Mobile Country Code: " + sysinfo.homeMCC() + } + + Label { + text: "Home Mobile Network Code: " + sysinfo.homeMNC() + } + + } + + } + +} diff --git a/mobility/sysinfo/qml/ScreenSaverPage.qml b/mobility/sysinfo/qml/ScreenSaverPage.qml new file mode 100644 index 0000000..d25e760 --- /dev/null +++ b/mobility/sysinfo/qml/ScreenSaverPage.qml @@ -0,0 +1,10 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: screenSaverTab + orientationLock: PageOrientation.LockLandscape + anchors.margins: UiConstants.DefaultMargin + + RadioButton { text: "Screen saver inhibited"; checked: sysinfo.screenSaverInhibited } +} diff --git a/mobility/sysinfo/qml/StoragePage.qml b/mobility/sysinfo/qml/StoragePage.qml new file mode 100644 index 0000000..6c5ad2a --- /dev/null +++ b/mobility/sysinfo/qml/StoragePage.qml @@ -0,0 +1,55 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: storageTab + orientationLock: PageOrientation.LockLandscape + anchors.margins: UiConstants.DefaultMargin + + Flickable { + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + contentHeight: columnStorage.height + toolBarLayout.height + contentWidth: width + Column { + id: columnStorage + anchors.top: parent.top + width: parent.width + + spacing: 25 + + Repeater { + + model: sysinfo.volumeNames + + Column { + + width: parent.width + + Label { + width: parent.width + text: "Volume: " + modelData + platformStyle: LabelStyle { + fontPixelSize: 32 + } + } + + Row { + spacing: 30 + Label { + text: "Type: " + sysinfo.storageType(modelData) + } + + Label { + text: "Total size: " + sysinfo.totalStorageSize(modelData) + } + + Label { + text: "Available: " + sysinfo.availableStorageSize(modelData) + } + } + } + } + } + } +} diff --git a/mobility/sysinfo/qml/TabBarPage.qml b/mobility/sysinfo/qml/TabBarPage.qml new file mode 100644 index 0000000..8cc24de --- /dev/null +++ b/mobility/sysinfo/qml/TabBarPage.qml @@ -0,0 +1,31 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +Page { + id: tabBarPage + anchors.margins: UiConstants.DefaultMargin + orientationLock: PageOrientation.LockLandscape + + tools: ToolBarLayout { + id: toolBarLayout + ButtonRow { + platformStyle: TabButtonStyle { } + TabButton { text: "General"; tab: generalTab } + TabButton { text: "Device"; tab: deviceTab } + TabButton { text: "Display"; tab: displayTab } + TabButton { text: "Storage"; tab: storageTab } + TabButton { text: "Network"; tab: networkTab } + TabButton { text: "Screen saver"; tab: screenSaverTab } + } + } + TabGroup { + anchors.fill: parent + currentTab: generalTab + GeneralPage { id: generalTab } + DevicePage { id: deviceTab } + DisplayPage { id: displayTab } + StoragePage { id: storageTab } + NetworkPage { id: networkTab } + ScreenSaverPage { id: screenSaverTab } + } +} diff --git a/mobility/sysinfo/qml/main.py b/mobility/sysinfo/qml/main.py new file mode 100644 index 0000000..a4e0d89 --- /dev/null +++ b/mobility/sysinfo/qml/main.py @@ -0,0 +1,334 @@ +#!/usr/bin/python + +import sys +import os + +from PySide import QtCore +from PySide import QtGui +from PySide import QtDeclarative +from PySide import QtOpenGL +from QtMobility.SystemInfo import QSystemInfo, QSystemDeviceInfo, QSystemDisplayInfo, QSystemStorageInfo, QSystemNetworkInfo, QSystemScreenSaver + + +class SystemInfoModel(QtCore.QObject): + changed = QtCore.Signal() + + def __init__(self): + super(SystemInfoModel, self).__init__() + self.systemInfo = QSystemInfo(self) + self.setupGeneral() + self.setupDevice() + self.setupDisplay() + self.setupStorage() + self.setupNetwork() + self.setupScreenSaver() + + @QtCore.Property(str, notify=changed) + def currentLanguage(self): + return self._currentLanguage + + @QtCore.Property("QStringList", notify=changed) + def availableLanguages(self): + return self._availableLanguages + + @QtCore.Property(int, notify=changed) + def displayBrightness(self): + return self._displayBrightness + + @QtCore.Property(int, notify=changed) + def colorDepth(self): + return self._colorDepth + + @QtCore.Property(str, notify=changed) + def imei(self): + return self._imei + + @QtCore.Property(str, notify=changed) + def imsi(self): + return self._imsi + + @QtCore.Property(str, notify=changed) + def manufacturer(self): + return self._manufacturer + + @QtCore.Property(str, notify=changed) + def product(self): + return self._product + + @QtCore.Property(str, notify=changed) + def model(self): + return self._model + + @QtCore.Property(str, notify=changed) + def profile(self): + return self._profile + + @QtCore.Property(str, notify=changed) + def inputMethod(self): + return self._inputMethod + + @QtCore.Property(bool, notify=changed) + def deviceLock(self): + return self._deviceLock + + @QtCore.Property(str, notify=changed) + def simStatus(self): + return self._simStatus + + @QtCore.Property(bool, notify=changed) + def bluetoothState(self): + return self._bluetoothState + + @QtCore.Property("QStringList", notify=changed) + def volumeNames(self): + return self._volumeNames + + @QtCore.Property("QStringList", notify=changed) + def networksNames(self): + return ["Wlan", "Ethernet", "Gsm", "Cdma", "Wcdma"] + + @QtCore.Property(bool, notify=changed) + def screenSaverInhibited(self): + return self._screenSaverInhibited + + def setupGeneral(self): + self._currentLanguage = self.systemInfo.currentLanguage() + self._availableLanguages = self.systemInfo.availableLanguages() + + def setupDevice(self): + self.deviceInfo = QSystemDeviceInfo(self) + self._batteryLevel = self.deviceInfo.batteryLevel() + self.deviceInfo.batteryLevelChanged.connect(self.updateBatteryStatus) + self.deviceInfo.batteryStatusChanged.connect(self.displayBatteryStatus) + self.deviceInfo.powerStateChanged.connect(self.updatePowerState) + self._imei = self.deviceInfo.imei() + self._imsi = self.deviceInfo.imsi() + self._manufacturer = self.deviceInfo.manufacturer() + self._model = self.deviceInfo.model() + self._product = self.deviceInfo.productName() + self._deviceLock = self.deviceInfo.isDeviceLocked() + + methods = self.deviceInfo.inputMethodType() + inputs = [] + if methods & QSystemDeviceInfo.Keys: + inputs.append("Keys") + if methods & QSystemDeviceInfo.Keypad: + inputs.append("Keypad") + if methods & QSystemDeviceInfo.Keyboard: + inputs.append("Keyboard") + if methods & QSystemDeviceInfo.SingleTouch: + inputs.append("Touch Screen") + if methods & QSystemDeviceInfo.MultiTouch: + inputs.append("Multi touch") + if methods & QSystemDeviceInfo.Mouse: + inputs.append("Mouse") + + self._inputMethod = " ".join(inputs) + self.updateSimStatus() + self.updateProfile() + + self._bluetoothState = self.deviceInfo.currentBluetoothPowerState() + self.deviceInfo.bluetoothStateChanged.connect(self.updateBluetoothState) + + def setupDisplay(self): + self.displayInfo = QSystemDisplayInfo() + self._displayBrightness = self.displayInfo.displayBrightness(0) + self._colorDepth = self.displayInfo.colorDepth(0) + + def setupStorage(self): + self.storageInfo = QSystemStorageInfo() + self._volumeNames = self.storageInfo.logicalDrives() + + @QtCore.Slot(str, result=str) + def storageType(self, volumeName): + names = { + QSystemStorageInfo.InternalDrive: "Internal", + QSystemStorageInfo.RemovableDrive: "Removable", + QSystemStorageInfo.CdromDrive: "CD-Rom", + QSystemStorageInfo.RemoteDrive: "Network", + } + + volType = self.storageInfo.typeForDrive(volumeName) + + return names.get(volType, "Unknown") + + @QtCore.Slot(str, result=str) + def totalStorageSize(self, volumeName): + return self.convert_bytes(self.storageInfo.totalDiskSpace(volumeName)) + + @QtCore.Slot(str, result=str) + def availableStorageSize(self, volumeName): + return self.convert_bytes(self.storageInfo.availableDiskSpace(volumeName)) + + def convert_bytes(self, bytes): + # From http://www.5dollarwhitebox.org/drupal/node/84 + bytes = float(bytes) + if bytes >= 1099511627776: + terabytes = bytes / 1099511627776 + size = '%.2fT' % terabytes + elif bytes >= 1073741824: + gigabytes = bytes / 1073741824 + size = '%.2fG' % gigabytes + elif bytes >= 1048576: + megabytes = bytes / 1048576 + size = '%.2fM' % megabytes + elif bytes >= 1024: + kilobytes = bytes / 1024 + size = '%.2fK' % kilobytes + else: + size = '%.2fb' % bytes + return size + + def setupNetwork(self): + self.networkInfo = QSystemNetworkInfo() + + def modeEnumForName(self, name): + try: + mode = getattr(QSystemNetworkInfo, name.capitalize() + "Mode") + except AttributeError as e: + print e + return None + + return mode + + @QtCore.Slot(str, result=str) + def networkStatus(self, modeName): + mode = self.modeEnumForName(modeName) + status = self.networkInfo.networkStatus(mode) + statusName = str(status).split('.')[-1] + # Split the CamelCase enum name + import re + return re.sub(r'([a-z])([A-Z])', r'\1 \2', statusName) + + @QtCore.Slot(str, result=str) + def networkName(self, modeName): + mode = self.modeEnumForName(modeName) + name = self.networkInfo.networkName(mode) + return name if name else "<Unknown>" + + @QtCore.Slot(str, result=str) + def networkInterfaceName(self, modeName): + mode = self.modeEnumForName(modeName) + name = self.networkInfo.interfaceForMode(mode).humanReadableName() + return name if name else "<Unknown>" + + @QtCore.Slot(str, result=str) + def networkMacAddress(self, modeName): + mode = self.modeEnumForName(modeName) + mac = self.networkInfo.macAddress(mode) + return mac if mac else "<Unknown>" + + @QtCore.Slot(str, result=int) + def networkSignalStrength(self, modeName): + mode = self.modeEnumForName(modeName) + return self.networkInfo.networkSignalStrength(mode) + + @QtCore.Slot(result=str) + def cellId(self): + cell = self.networkInfo.cellId() + return str(cell) if cell != -1 else "<Unavailable>" + + @QtCore.Slot(result=str) + def locationAreaCode(self): + code = self.networkInfo.locationAreaCode() + return str(code) if code != -1 else "<Unavailable>" + + @QtCore.Slot(result=str) + def currentMCC(self): + code = self.networkInfo.currentMobileCountryCode() + return code if code else "<Unavailable>" + + @QtCore.Slot(result=str) + def currentMNC(self): + code = self.networkInfo.currentMobileNetworkCode() + return code if code else "<Unavailable>" + + @QtCore.Slot(result=str) + def homeMCC(self): + code = self.networkInfo.homeMobileCountryCode() + return code if code else "<Unavailable>" + + @QtCore.Slot(result=str) + def homeMNC(self): + code = self.networkInfo.homeMobileNetworkCode() + return code if code else "<Unavailable>" + + def setupScreenSaver(self): + self.saverInfo = QSystemScreenSaver(self) + self._screenSaverInhibited = self.saverInfo.screenSaverInhibited() + + def updateBluetoothState(self, on): + self._bluetoothState = on + self.changed.emit() + + def updateBatteryStatus(self, status): + self._batteryLevel = status + self.emit(QtCore.SIGNAL('changed()')) + + def displayBatteryStatus(self, status): + pass + + def updatePowerState(self, newState): + pass + + def updateSimStatus(self): + if self.deviceInfo: + status = self.deviceInfo.simStatus() + if status == QSystemDeviceInfo.SimLocked: + simstring = "Sim Locked"; + elif status == QSystemDeviceInfo.SimNotAvailable: + simstring = "Sim not available"; + elif status == QSystemDeviceInfo.SingleSimAvailable: + simstring = "Single Sim Available"; + elif status == QSystemDeviceInfo.DualSimAvailable: + simstring = "Dual Sim available"; + else: + simstring = "" + + self._simStatus = simstring + + + def updateProfile(self): + if self.deviceInfo: + current = self.deviceInfo.currentProfile() + if current == QSystemDeviceInfo.UnknownProfile: + profilestring = "Unknown" + elif current == QSystemDeviceInfo.SilentProfile: + profilestring = "Silent" + elif current == QSystemDeviceInfo.NormalProfile: + profilestring = "Normal" + elif current == QSystemDeviceInfo.LoudProfile: + profilestring = "Loud" + elif current == QSystemDeviceInfo.VibProfile: + profilestring = "Vibrate" + elif current == QSystemDeviceInfo.OfflineProfile: + profilestring = "Offline"; + elif current == QSystemDeviceInfo.PowersaveProfile: + profilestring = "Powersave"; + elif current == QSystemDeviceInfo.CustomProfile: + profilestring = "custom"; + + self._profile = profilestring + +class SystemInfoUI(QtCore.QObject): + def __init__(self): + super(SystemInfoUI, self).__init__() + self.view = QtDeclarative.QDeclarativeView() + self.rc = self.view.rootContext() + + self.model = SystemInfoModel() + self.rc.setContextProperty('sysinfo', self.model) + + self.view.setSource('main.qml') + + if "-no-fs" in sys.argv: + self.view.show() + else: + self.view.showFullScreen() + + self.systemInfo = QSystemInfo(self) + +if __name__ == "__main__": + app = QtGui.QApplication([]) + ui = SystemInfoUI() + app.exec_() diff --git a/mobility/sysinfo/qml/main.qml b/mobility/sysinfo/qml/main.qml new file mode 100644 index 0000000..57bdc31 --- /dev/null +++ b/mobility/sysinfo/qml/main.qml @@ -0,0 +1,10 @@ +import QtQuick 1.1 +import com.nokia.meego 1.0 + +PageStackWindow { + id: appWindow + + initialPage: tabBarPage + + TabBarPage { id: tabBarPage } +} |