silvansky programming stuff

6Apr/110

assert

Наткнулся в коде (/src/gui/dialogs/qinputdialog.cpp):

void QInputDialog::setInputMode(InputMode mode)
{
    Q_D(QInputDialog);
 
    QWidget *widget;
 
    /*
        Warning: Some functions in QInputDialog rely on implementation details
        of the code below. Look for the comments that accompany the calls to
        setInputMode() throughout this file before you change the code below.
    */
 
    switch (mode) {
    case IntInput:
        d->ensureIntSpinBox();
        widget = d->intSpinBox;
        break;
    case DoubleInput:
        d->ensureDoubleSpinBox();
        widget = d->doubleSpinBox;
        break;
    default:
        Q_ASSERT(mode == TextInput);
        d->chooseRightTextInputWidget();
        return;
    }
 
    d->setInputWidget(widget);
}

switch просто поразил своим ассертом в default'е! )

Tagged as: , , , No Comments
5Apr/110

nine part pixmap

Код для отрисовки картинки из 9 частей (типа border-image). Принимает QImage, но может быть модифицирован для работы напрямую с QPixmap.

void drawNinePartImage(const QImage &image, QRectF paintRect, qreal borderLeft, qreal borderRight, qreal borderTop, qreal borderBottom, QPainter * painter)
{
	QPixmap bg = QPixmap::fromImage(image);
	// source size
	qreal w = bg.width();
	qreal h = bg.height();
	// target size
	qreal tw = paintRect.width();
	qreal th = paintRect.height();
/*
 
+-------+-------------------+-------+
|       |                   |       |
|   0   |         1         |   2   |
|       |                   |       |
+-------+-------------------+-------+
|       |                   |       |
|   3   |         4         |   5   |
|       |                   |       |
+-------+-------------------+-------+
|       |                   |       |
|   6   |         7         |   8   |
|       |                   |       |
+-------+-------------------+-------+
 
*/
	QPainter::PixmapFragment fragments[9]; // we'll draw 9-part pixmap
	qreal hborders = borderLeft + borderRight;
	qreal vborders = borderTop + borderBottom;
	qreal sx = (tw - hborders) / (w - hborders), sy = (th - vborders) / (h - vborders);
	qreal hbLeft = borderLeft / 2.0;
	qreal hbRight = borderRight / 2.0;
	qreal hbTop = borderTop / 2.0;
	qreal hbBottom = borderBottom / 2.0;
	fragments[0] = QPainter::PixmapFragment::create(QPointF(hbLeft, hbTop),
							QRectF(0, 0, borderLeft, borderTop));
	fragments[1] = QPainter::PixmapFragment::create(QPointF(borderLeft + (tw - hborders) / 2.0, hbTop),
							QRectF(borderLeft, 0, w - hborders, borderTop),
							sx);
	fragments[2] = QPainter::PixmapFragment::create(QPointF(tw - hbRight, hbTop),
							QRectF(w - borderRight, 0, borderRight, borderTop));
	fragments[3] = QPainter::PixmapFragment::create(QPointF(hbLeft, borderTop + (th - hborders) / 2.0),
							QRectF(0, borderTop, borderLeft, h - hborders),
							1.0,
							sy);
	fragments[4] = QPainter::PixmapFragment::create(QPointF(borderLeft + (tw - hborders) / 2.0, borderTop + (th - vborders) / 2.0),
							QRectF(borderLeft, borderTop, w - hborders, h - vborders),
							sx,
							sy);
	fragments[5] = QPainter::PixmapFragment::create(QPointF(tw - hbRight, borderTop + (th - vborders) / 2.0),
							QRectF(w - borderRight, borderTop, borderRight, h - vborders),
							1,
							sy);
	fragments[6] = QPainter::PixmapFragment::create(QPointF(hbLeft, th - hbBottom),
							QRectF(0, h - borderBottom, borderLeft, borderBottom));
	fragments[7] = QPainter::PixmapFragment::create(QPointF(borderLeft + (tw - hborders) / 2.0, th - hbBottom),
							QRectF(borderLeft, h - borderBottom, w - hborders, borderBottom),
							sx);
	fragments[8] = QPainter::PixmapFragment::create(QPointF(tw - hbRight, th - hbBottom),
							QRectF(w - borderRight, h - borderBottom, borderRight, borderBottom));
 
	painter->drawPixmapFragments(fragments, 9, bg);
}
 
Tagged as: , , , No Comments
25Mar/110

my damaged brain…

Долго мучился, пока не почитал мануалы. В нужном месте.
Оказывается, что если хочешь для прямого наследника QWidget'а установить background-image через setStyleSheet(), то надо ему переопределить paintEvent():

class MyCustomWidget : public QWidget
{
  Q_OBJECT
  // ...
}

void MyCustomWidget::paintEvent(QPaintEvent *)
{
  QStyleOption opt;
  opt.init(this);
  QPainter p(this);
  style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

* This source code was highlighted with Source Code Highlighter.

http://doc.qt.nokia.com/4.7/stylesheet-reference.html#list-of-stylable-widgets - там в самом конце.

23Dec/100

Qt + windows registry

Хороший не документированный способ работы с реестром винды из Qt.

Пример: прочитать системную переменную Path:

QSettings reg("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", QSettings::NativeFormat);
QStringList paths(reg.value("Path").toString().split(";"));
23Nov/100

QML WhealArea

источник: https://github.com/explicitcall/QMLbox
что: QML-элемент WheelArea, дополнение к стандартному MouseArea. реагирует на mouse wheel.
чтобы юзать, регистрируем и импортируем стандартным образом.

#ifndef WHEELAREA_H
#define WHEELAREA_H

#include <QDeclarativeItem>
#include <QGraphicsSceneWheelEvent>

class WheelArea : public QDeclarativeItem
{
    Q_OBJECT

public:
    explicit WheelArea(QDeclarativeItem *parent = 0) : QDeclarativeItem(parent) {}

protected:
    void wheelEvent(QGraphicsSceneWheelEvent *event) {
        switch(event->orientation())
        {
            case Qt::Horizontal:
                emit horizontalWheel(event->delta());
                break;
            case Qt::Vertical:
                emit verticalWheel(event->delta());
                break;
            default:
                event->ignore();
                break;
        }
    }

signals:
    void verticalWheel(int delta);
    void horizontalWheel(int delta);
};

#endif // WHEELAREA_H
Tagged as: , , , No Comments
16Nov/100

qml & multiline elide

иногда нужно обрезать длинную строку и поставить в конце многоточие... для этого в QML у текста есть свойство elide. чтобы его задействовать нужно задать ширину текста.

а что если мы хотим вывести текст в 2 строки? и при этом естественно обрезать лишнее и поставить многоточие?...
тогда elide бессилен.

немного результатов моих мучений с данным вопросом: рабочая функция многострочного илайда!

сразу перейдём к коду.

Text {
    id: tempText
    visible: false
    width: parent.width
    wrapMode: Text.WordWrap
    function elideMultiline(text, font, linesCount) {
        tempText.font = font
        var l = text.length
        var s = "";
        for (var i = 0; i < linesCount; i++) {
            s += "W";
            if (i < linesCount - 1)
                s += "\n"
        }
        tempText.text = s
        var maxHeight = tempText.paintedHeight
        tempText.text = text
        while (tempText.paintedHeight > maxHeight) {
            tempText.text = text.substring(0, --l) + "..."
        }
        return tempText.text
    }
}
Text {
    id: longText
    width: parent.width
    wrapMode: Text.WordWrap
    font.pointSize: 16
    Component.onCompleted: {
        text = tempText.elideMultiline("my very-very-very-very and very long text with a lot of words in it and which i want to be correctly elided", font, 2)
    }
}

как видно из кода, создаётся дополнительный элемент Text и делается невидимым. он используется для определения размеров текста на экране. для этого элемента определяем функцию elideMultiline, в неё передаём текст, шрифт и нужное нам количество строк текста.

далее всё просто, простой линейный перебор (сокращаем строку на 1 символ, дописываем "...", проверяем, опять сокращаем.......)

в принципе всё работает, но когда нужно вызвать эту функцию много раз, получаются тормоза. как дойдут руки, переделаю из линейного поиска в метод золотого сечения.

Замечание. Почему-то не хочет работать text: elideMultiline(), поэтому используется событие готовности компонента и в нём делается присвоение. Если сделать всё же первый вариант, то всё будет тормозить и выдавать кучу предупреждений "QML Text: Binding loop detected for property "text""

Tagged as: , , , , No Comments
16Nov/100

<замазано>


тестирую тег span в HTML... не нашёл лучшего места, чем данный жж.
кстати, интересно наверное будут выглядеть посты в таком стиле. неудобочитаемые.

а если серьёзно, то нашёл интересный класс в QtDeclarative, называется QDeclarativeImageProvider. его надо наследовать, реализовать функции requestImage/requestPixmap, зарегистрировать наш провайдер в энджине (QDeclarativeEngine::addImageProvider()) и юзать из QML вот так:

Image {
    source: "image://providerName/imageName.png"
}

теперь можно динамически вставлять картинки в qml, передавая туда лишь строку с "image://...".

Tagged as: , , , No Comments
15Nov/100

qml + qt model/view

итак, теперь серьёзно о QML. загрузить в QML список элементов и отобразить их там - это конечно хорошо, но мало. предположим, у нас есть уже модель данных, сделанная на наследнике QAbstractItemModel и мы хотим отобразить элементы этой модели. причём перед отображением неплохо бы отфильтровать и отсортировать нашу модель.

C++-way: делаем наследника QAbstractItemView, делаем наследника QAbstractItemDelegate (для кастомной отрисовки), делаем наследника QSortFilterProxyModel (для фильтрации и сортировки).

QML-way: делаем наследника QSortFilterProxyModel (для фильтрации и сортировки), делаем в QML ListView (для моделей типа список), регистрируем наш фильтр в QML, назначаем list.model.

всё по прежнему остаётся просто! в принципе, надо лишь правильно создать и заполнить свою модель и прокси-модель.

Tagged as: , , , , No Comments
11Nov/100

qt + qml

итак, я немного разобрался с использованием QML. в кратце состав моего тестового проекта:

А. просто в QML:

1. создать скроллабл лист из итемов с кастомным делегатом отрисовки и списком итемов для отображения
2. реализовать выделение итемов по лику мыши и активацию их по повторному клику или нажатию на enter

Б. C++/QML

1. встроить объект из кода C++ в контекст QML
2. вызвать нужный метод этого объекта из QML
3. использовать сигналы этого объекта в QML
4. использовать в списке итемы, сгенерированные кодом на C++
5. встроить QDeclarativeView в окно программы (т.е., в существующий пользовательский интерфейс) и реализовать их взаимодействие

итак, код.

main.qml - реализация на QML

import Qt 4.7
import silvansky 1.0

Rectangle {
    width: 360
    height: 600
    gradient: Gradient {
        GradientStop {
            position: 0
            color: "#ffffff"
        }

        GradientStop {
            position: 0.48
            color: "#ffffff"
        }

        GradientStop {
            position: 1
            color: "#88e9ec"
        }
    }
    Component {
        id: contactDelegate
        Item {
            function activated(ci) {
                console.log("item #" + list1.currentIndex + " activated! (" + cl1.contacts[ci].name + " the " + cl1.contacts[ci].type + ")")
            }

            MouseArea {
                id: ma1
                width: 360
                height: 60
                onClicked: {
                    var ci = list1.indexAt(parent.x + mouse.x, parent.y + mouse.y)
                    if (list1.currentIndex == ci) {
                        activated(ci)
                    }
                    else {
                        list1.currentIndex = ci
                    }
                }
            }
            Keys.onSelectPressed: {
                activated(list1.currentIndex)
            }
            Keys.onEnterPressed: {
                activated(list1.currentIndex)
            }
            Keys.onReturnPressed: {
                activated(list1.currentIndex)
            }
            Keys.onEscapePressed: {
                console.log("ESCAPE!!!!!! AAAA!!!")
                interactor.escapePressed()
            }
            width: parent.width
            height: 60
            Column {
                Text {
                    height: 60
                    text: name + " (" + type + ")"
                    color: (type == "admin") ? "red" : ((type == "boss") ? "green" : "blue")
                    font.pointSize: 12
                    verticalAlignment: Text.AlignVCenter
                }
            }
        }
    }
    ListView {
        id: list1
        anchors.fill: parent
        //model: ContactsModel {}
        model: cl1.contacts
        delegate: contactDelegate
        highlight: Rectangle { color: "#00DDDD"; radius: 5 }
        highlightMoveDuration: 400
        highlightMoveSpeed: -1
        focus: true
    }
    Connections {
        target: interactor
        onMoveUp: {
            list1.currentIndex--
        }
        onMoveDown: {
            list1.currentIndex++
        }
    }
}

немного пояснений. сначала мы импортируем модуль Qt, затем мой модуль.

основа всего - главный объект (root object), который в данном случае просто прямоугольник размерами 360х600 (размер я выбирал такой чтоб на мобильнике можно было тестить) и с заливкой в виде градиента.

у нашего прямоуголльника есть дочерние объекты. первый из них - делегат для отрисовки итема в списке. в нём есть функция, которая вызывается при активировании итема, MouseArea для обработки нажатий мышью и обработчики нажатий на Enter/Return/Select/Escape. высота итема фиксирована (60px), ширина берётся как у родителя. далее мы просто выводим текст (предполагается, что у элемента списка есть два свойства: name и type), выделяя некоторые итемы цветом.

второй дочерний объект - собственно список (ListView). у него выставляем id, говорим, что будем заполнять родителя собой, устанавливаем модель и делегат, устанавливаем параметры подсветки элементов.

тут заметим, что модель мы берём из объекта cl1, который не объявлен. если раскомментить предыдущую строку, то будем брать модель из файла ContactsModel.qml, который содержит примерно следующее:

import Qt 4.7

ListModel {
    id: lm1
    ListElement {
        name: "Good Guy"
        type: "admin"
    }
    ListElement {
        name: "Vlad Pukin"
        type: "ex-boss"
    }
    ListElement {
        name: "Ramonitos"
        type: "boss"
    }
    ListElement {
        name: "J. Doolitle"
        type: "ex-boss"
    }
    ListElement {
        name: "Borak Ohama"
        type: "boss"
    }
    ListElement {
        name: "Vasya Pupkin"
        type: "lamer"
    }
    ListElement {
        name: "Utilkin"
        type: "user"
    }
    // and so on...
}

но мы не будем его использовать.

итак, следующий объект - Connections, в данном случае он используется для подключения сигналов из объектов C++ к функциям в QML. здесь interactor - объект, который будет объявлен в коде на C++.

итак, с QML разобрались. фух... теперь пойдёт интересное. создаём программу на C++/Qt, создаём там классы Contact, ContactList и QmlInteractor, создаём форму TestQmlView (наследуем от виджета, например). в форму запихиваем QDeclarativeView и тулбар, на который ставим две кнопки - Up и Down, которые будут перемещать выделение в списке.

вот примерно что должно получиться:

testqmlview.h

#ifndef TESTQMLVIEW_H
#define TESTQMLVIEW_H

#include <QWidget>
#include <QDeclarativeView>
#include <QToolBar>

namespace Ui
{
    class TestQmlView;
}

class TestQmlView : public QWidget
{
    Q_OBJECT

public:
    explicit TestQmlView(QWidget *parent = 0);
    ~TestQmlView();
    void setQml(const QUrl & url);
    QDeclarativeView * declarativeView() const
    {
        return dview;
    }

protected:
    void changeEvent(QEvent *e);
signals:
    void goUp();
    void goDown();

private:
    Ui::TestQmlView *ui;
    QDeclarativeView * dview;
    QToolBar * toolbar;
    QAction * up;
    QAction * down;
};

#endif // TESTQMLVIEW_H

contact.h

#ifndef CONTACT_H
#define CONTACT_H

#include <QObject>

class Contact : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged)
public:
    Contact();

    // props

    // name
    QString name() const
    {
        return _name;
    }
    void setName(const QString newName)
    {
        _name = newName;
    }
    // type
    QString type() const
    {
        return _type;
    }
    void setType(const QString newType)
    {
        _type = newType;
    }
signals:
    void nameChanged(const QString newName);
    void typeChanged(const QString newType);

public slots:
private:
    QString _name;
    QString _type;
};

#endif // CONTACT_H

contactlist.h

#ifndef CONTACTLIST_H
#define CONTACTLIST_H

#include <QObject>
#include "contact.h"
#include <QList>
#include <QDeclarativeListProperty>

class ContactList : public QObject
{
    Q_OBJECT
public:
    ContactList();

    Q_PROPERTY(QDeclarativeListProperty<Contact> contacts READ contacts CONSTANT)
    QDeclarativeListProperty<Contact> contacts()
    {
        return QDeclarativeListProperty<Contact>(this, _contacts);
    }
signals:

public slots:
private:
    QList<Contact*> _contacts;
};

#endif // CONTACTLIST_H

qmlinteractor.h

#ifndef QMLINTERACTOR_H
#define QMLINTERACTOR_H

#include <QObject>

class QmlInteractor : public QObject
{
    Q_OBJECT
public:
    QmlInteractor();
    Q_INVOKABLE void escapePressed();

signals:
    void moveUp();
    void moveDown();

public slots:

};

#endif // QMLINTERACTOR_H

в принципе тут ничего сложного. просто объекты со свойствами, объявленными через Q_PROPERTY. для свойств типа QList нужно использовать шаблон-враппер QDeclarativeListProperty<>, использование показано в коде.

осталось в конструкторе ContactList'а заполнить как-либо список _contacts. у меня это сделано так:

#include "contactlist.h"
#include <QDebug>
#include <time.h>

ContactList::ContactList() :
    QObject(0)
{
    qDebug() << "ContactList created!";
    QList<QString> names;
    QList<QString> types;
    names << "Name1" << "Vasya" << "petya" << "good guy" << "bad guy" << "youmil" << "rutta" << "hooker";
    types << "admin" << "user" << "boss" << "ex-boss" << "lamer";
    qsrand(time(NULL));
    for (int i = 0; i < 50; i++)
    {
        Contact * c = new Contact;
        c->setName(names.at(qrand() % names.count()));
        c->setType(types.at(qrand() % types.count()));
        _contacts.append(c);
    }
}

далее пошло самое интересное. итак, встречайте! файл main.cpp!

#include <QtGui/QApplication>
#include <QtDeclarative>
#include <QDebug>
#include "testqmlview.h"
#include "qmlinteractor.h"
#include "contact.h"
#include "contactlist.h"

void registerQmlTypes()
{
    static const char * uri = "silvansky";
    qmlRegisterType<QmlInteractor>(uri, 1, 0, "QmlInteractor");
    qmlRegisterType<Contact>(uri, 1, 0, "Contact");
    qmlRegisterType<ContactList>(uri, 1, 0, "ContactList");
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    TestQmlView view;
    registerQmlTypes();
    ContactList * cl = new ContactList;
    QmlInteractor * interactor = new QmlInteractor;
    view.declarativeView()->rootContext()->setContextProperty("cl1", cl);
    view.declarativeView()->rootContext()->setContextProperty("interactor", interactor);
    QObject::connect(&view, SIGNAL(goUp()), interactor, SIGNAL(moveUp()));
    QObject::connect(&view, SIGNAL(goDown()), interactor, SIGNAL(moveDown()));
    view.setQml(QUrl("qml/qtquicktest/main.qml"));
#if defined(Q_OS_SYMBIAN) || defined(Q_OS_SIMULATOR)
    view.showFullScreen();
#else
    view.show();
    view.adjustSize();
#endif
    return app.exec();
}

разбираем по порядку.

первая функция регистрирует три типа для использования в QML - Contact, ContactList и QmlInteractor

теперь читаем внимательно, ибо порядок строк важен ;)
создаём view (у него в конструкторе создаётся QDeclarativeView), затем создаём контактлист и интерактор.
а теперь фокус-покус! у QDeclarativeView берём rootContext и у ему делаем setContextProperty()! этот финт ушами я долго пытался найти. что это даёт? да то, что теперь наши объекты cl и interactor доступны в QML под id cl1 и interactor и наш QML-код из main.qml перестаёт быть бессмысленным.

после коннектов (не буду их пояснять) мы в наш QDeclarativeView загружаем наш файл main.qml и показываем наше окошко.

всё, компилим, запускаем, наслаждаемся!
главное не забыть в .pro файле написать следующие строчки:

QT += declarative
symbian: {
    qmlfiles.sources = qml/qtquicktest/*.qml
    qmlfiles.path = ./qml/qtquicktest
    DEPLOYMENT += qmlfiles
}

послесловие или "зачем это надо?"

вообще, перенести часть мобильного проекта на QML мне захотелось после попытки сделать кинетик скролл для QListView. разумеется, я не стал писать его с нуля, а воспользовался готовым классом FlickCharm из Anomaly demo, немного его подточив. но при этом всё стало плохо - тормоза, глюки, трудно нажать на элемент, ну и т.д.... особенно сильные тормоза были при натягивании дизайна через QSS.

а вот в QML элемент ListView сам по себе умеет кинетик скроллинг делать. быстро, красиво и удобно. и много разных других фишек (например, плавное перемещение фокуса). потестив немного это всё я пришёл к выводу, что на QML всё должно работать быстрее. пока что остановился только на переводе списков на QML, потом подумаю над тем чтобы весь UI на него перевести.

Tagged as: , , , No Comments
7Oct/100

сигнал о входящем/исходящем телефонном вызове в Qt под Symbian

в связи с тем, что из QtMobility 1.1 исключили модуль Telephony (анонсированный в 1.1-tp) я немного покопался в инете и нашёл таки способ как поймать начало и конец входящего и исходящего звонков. Осталось поймать смс-ки ;)

итак, средствами Qt этого не сделать. смиритесь. придётся написать немного кода на родном API симбиана.

итак, класс мы назовём CallWatcher. наследовать его мы будем от QObject (чтобы слать сигналы) и от CActive (это уже симбиан, технология Active Object).

  1. class CallWatcher : public QObject, public CActive
  2. {
  3.   Q_OBJECT
  4. public:
  5.   CallWatcher();
  6.   ~CallWatcher();
  7.   void RequestNotification();
  8. private:
  9.   void RunL();
  10.   void DoCancel();
  11. signals:
  12.   void callStarted();
  13.   void callEnded();
  14. private:
  15.   CTelephony* iTelephony;
  16.   CTelephony::TCallStatusV1 iLineStatus;
  17.   CTelephony::TCallStatusV1Pckg iLineStatusPckg;
  18.   bool started;
  19. };

* This source code was highlighted with Source Code Highlighter.

собственно, суть в том, что мы будем ждать сообщения (события, нотификатора, кому как нравится) от объекта класса CTelephony, входящего в библиотеку etel3dparty.

не забываем про инклюды!

#include <e32base.h>
#include <Etel3rdParty.h>
#include <QObject>

* This source code was highlighted with Source Code Highlighter.

первый - для CActive и иже с ним, второй для CTelephony.

теперь пишем сам код:

  1. CallWatcher::CallWatcher(): CActive(EPriorityStandard), QObject(NULL), iLineStatusPckg(iLineStatus)
  2. {
  3.   CActiveScheduler::Add(this);
  4.   iLineStatus.iStatus = CTelephony::EStatusUnknown;
  5.   iTelephony = CTelephony::NewL();
  6.   RequestNotification();
  7.   started = false;
  8. }
  9.  
  10. CallWatcher::~CallWatcher()
  11. {
  12.   delete iTelephony;
  13. }
  14.  
  15. void CallWatcher::RequestNotification()
  16. {
  17.   _LIT(KCallWatcherPanic, "CallWatcher");
  18.   __ASSERT_ALWAYS(!IsActive(), User::Panic(KCallWatcherPanic, 1));
  19.  
  20.   iTelephony->NotifyChange(iStatus, CTelephony::EVoiceLineStatusChange, iLineStatusPckg);
  21.   SetActive();
  22. }
  23.  
  24. void CallWatcher::RunL()
  25. {
  26.   if(iStatus == KErrNone)
  27.   {
  28.     if (!started && (iLineStatus.iStatus != CTelephony::EStatusIdle))
  29.     {
  30.       started = true;
  31.       emit callStarted();
  32.     }
  33.     else if (iLineStatus.iStatus == CTelephony::EStatusIdle)
  34.     {
  35.       started = false;
  36.       emit callEnded();
  37.     }
  38.     RequestNotification();
  39.   }
  40. }
  41.  
  42. void CallWatcher::DoCancel()
  43. {
  44.   iTelephony->CancelAsync(CTelephony::EVoiceLineStatusChangeCancel);
  45. }
  46.  

* This source code was highlighted with Source Code Highlighter.

в конструкторе нашего класса мы сначала добавляем наш объект (CActive*) к шедулеру, т.е., запускаем его на прослушку сообщений.
Затем выставляем статус линии в "неизвестный", создаём объект CTelephony (неудобоваримо на первый взгляд, но так принято в симбиане - двухэтапные конструкторы и прочее), запрашиваем события и помечаем, что разговор не начат ещё.

в функции RequestNotification() мы делаем проверку на валидность (точнее, на активность себя же), а затем запрашиваем у нашего iTelephony нотификатор изменения статуса линии, а затем активизируем себя.

функция RunL() будет вызвана когда придёт нужное нам сообщение. в ней мы проверяем статус на ошибки, и если таковых нет, делаем всё совсем стандартно (не охота подробно комментировать), главное - статус линии хранится в iLineStatus.iStatus. а затем просто запрашиваем следующее событие. так уж сделано там - событие пришло, значит больше не нужно. немного нелогично на мой взгляд, но видимо у разработчиков были свои причины на это.

ну, и для финала делаем функцию отмены DoCancel(), в которой просто отменяем запрос.

всё, теперь можно компилить (не забываем про LIBS += -letel3rdparty в .pro файле) и тестить. в нужный нам момент (входящий или исходящий вызов начат или завершён) мы получим соответствующие сигналы.

стоит отметить, что для использования CTelephony нужны особые капабилитиз - TARGET.CAPABILITY += NetworkServices. но это не помешает тестировать прогу с самоподписанным сертификатом.

Tagged as: , , , , No Comments