Sie sind auf Seite 1von 23

Project Report

by

Gino Cappelli
Prof: Vittorio

Ghini

University of Bologna A.Y. 2010/2011


1

Table of contents 1. Introduction 2. Set-up of the environment 3. Added features 4. Modularity and Portability 5. Future development 3 5 7 20 22

1. Introduction
In the following report are explained some important points of the project on which I have worked during the third year of my Degree at University of Bologna. The main project objective has been to add some features to an existing application called Jangiu [1]. The application is a crossplatform VoIP Client for smart-phones with a friendly user interface [2]. This application has been mainly developed for the Symbian O.S. [3] (in C++) using the Qt libraries [4] for the design of the GUI. My scope of interests regarded the user-interface (graphic) side, moving the important part of my project to the Qt modules of the application (and not to the low-level modules containing the implementation of the SIP protocol [5]). In facts, I developed two main features: A search functionality (of the contacts), based on a prefix inserted in a search bar The division of the contacts using groups In the next chapter are described many troubles that I have had during the set-up of the Carbide C++ environment [6]. In the chapters 3 and 4 it is explained how the above features have been added and the repercussion of these modules on the application portability. Finally, the chapter 5 suggests some possible future development plans for this application.
3

Figure 1: An image of the Jangiu application running on the Symbian emulator [7]

2. Set-up

of the environment

The Jangiu application has been developed using the Carbide C++ IDE (v 2.7) that provides many useful features for the Symbian developers. In [1] is explained how to correctly perform all the steps necessary to set-up the IDE with the application and all its libraries (Qt, PjSIP (Open Source SIP Stack) [8] ). Once obtained the source code of the Jangiu application (see [1]), and correctly imported the project in the IDE ([1]), it will be possible to carry out the following steps to solve many problems concerning the correct behavior of the application:

Comment the line 995 in the sock_common.c file (under pjproject [see 1], pjlib/src/pj/sock_common.c)
len = sizeof(a); status = pj_sock_getsockname(fd, &a, &len); if (status != PJ_SUCCESS) { pj_sock_close(fd); return status; } // COMMENT THE FOLLOWING LINE // pj_sock_close(fd);

Comment the line 403 in the ioqueue_symbian.cpp file (under pjproject, pjlib/src/pj/ioqueue_symbian.cpp)
// Call callback. if (cb_.on_accept_complete) { cb_.on_accept_complete( key_, op_key, (pj_sock_t)pjNewSock, PJ_SUCCESS); } } // COMMENT THE FOLLOWING LINE //ioqueue_->eventCount++;

In the files symbian_ua.mmp (under pjproject) and jangiu_exe.mmp (under the jangiu project) set the variables EPOCSTACKSIZE and EPOCHEAPSIZE to { 0x50000 } and { 0x50000 0x1000000 } respectively.
EPOCSTACKSIZE EPOCHEAPSIZE 0x50000 0x50000 0x1000000

Figure 2: The Carbide C/C++ IDE

3. Added

features

The two changes made to the Jangiu application affect the userinterface, as shows the image below.

Figure 3: The two changes apported to the user-inteface: 1. The search bar 2. The groups

Both the features affect the user-interface, mainly the contactsdialog.cpp file under the jangiu/src folder. Consequently, in this chapter, it will be explained how this file has been changed and how the added code works.

3.1 The search bar


To implement this functionality the following tasks have been made: Added the input line in the ui_contactsdialog.h file Implemented two functions: search() and keyReleaseEvent() The input line is a Qt filed and it is not interesting, while the two functions capture the events on this input line to implement the search mechanism. Particularly, the keyReleaseEvent() function waits for a keyboard event (letters, numbers, ) on the input-line and passes the new content to the search() function, that in turn selects the contacts to display on the top window.
Insert f

ab ab

input-line

abf abf

new input-line

search(abf)

Figure 4: How the keyboard events are handled 8

The following code, taken from the keyReleaseEvent() function, implements the keyboard event handling:
void ContactsDialog::keyReleaseEvent(QKeyEvent *event) { /** * STEP 1: * Handling the keyboard */ switch (event->nativeVirtualKey()){ // // Discard all the common non-alphanumeric // keyboard events. // case EKeyYes: { event->ignore(); break; } case EKeyNo: { event->ignore(); break; }

OTHER NON-ALPHANUMERIC EVENTS


// // Handling the alphanumeric events default: { if(event->text()>="0" && event->text()<="9") { // QString to Int conversion flag bool success; // // IMPORTANT CONVENTION: // ui->lineEdit_2 is the 'search input-field' // switch(event->text().toInt(&success,10/*base*/)) { case 0: // Do nothing // because button 0 does not contain letters break; case 1: // Do nothing // because button 1 does not contain letters break;

case 2: // Case 2 = charachter 'a' if(success) { // If the search input-field is not focused if(!(ui->lineEdit_2->hasFocus())) { // Append the charachter in the field ui->lineEdit_2-> insert(QString("a")); // and set the focus on it ui->lineEdit_2->setFocus(); } } break; case 3: // Case 3 = charachter 'd' if(success) { // If the search input-field is not focused if(!(ui->lineEdit_2->hasFocus())) { // Append the charachter in the field ui->lineEdit_2-> insert(QString("d")); // and set the focus on it ui->lineEdit_2->setFocus(); } } break;

OTHER CHARACHERS (4 to 9)
default: // Do nothing break; } else { };

10

// If the the charachter is not a number // then it is a letter // // Native support for the QWERTY keyboards: // therefore insert automatically the // letter in the search input-field // if(!(ui->lineEdit_2->hasFocus())) { if(event->text()!="#" && event->text()!="-" && event->text()!="*" && event->text()!="," && event->text()!=" " && event->text()!="." && event->text()!="&" && event->text()!="/" && event->text()!="+" && event->text()!=";" && event->text()!="=" && event->text()!="?") { // Append the charachter in the field ui->lineEdit_2->insert(event->text()); // and set the focus on it ui->lineEdit_2->setFocus(); } }

/** * STEP 2: * Call the search() function given the prefix */ // // Once the charachter is been inserted in the // search input-field (lineEdit_2), we can call the // search() function that updates the // contact book, removing all the contacts // that do not begin with the given prefix. // this->search(ui->lineEdit_2->text()); } }; #endif } break;

As can be seen from the code, the keyReleaseEvent() function captures the keyboard events and, once populated the input-line with the inserted character, calls the search() function.

11

The following code, taken from the search() function, implements the actual search mechanism (implementation with groups):
/** * The search() function updates the contacts list, * removing all the contacts that do not begin with * the prefix (QString prefix) given in input. */ void ContactsDialog::search(QString prefix) { QListWidgetItem c; QListWidgetItem *item; // Restore the initial environment, since previus calls to // search() may have changed the list of contacts. // // Therefore re-insert all removed contacts, if any if(!(this->removedContacts.isEmpty())) { foreach(c, removedContacts) { QListWidgetItem *item = new QListWidgetItem(QIcon(":icons/unknown.png"), c.text()); ui->listWidget->addItem(item); } } this->removedContacts.clear(); QList<QListWidgetItem *> contacts=ui->listWidget-> findItems(QString(":"),Qt::MatchContains); // Remove all groups for(int i=0;i<ui->listWidget->count();i++) if(!ui->listWidget->item(i)->text().contains(":")) ui->listWidget->takeItem(i); if(!(contacts.isEmpty()) && prefix!=QString("")) { // Entablish the "search" group, composed by all contact // that begins with the given prefix item = new QListWidgetItem(QIcon(":icons/group.png"), QString("Search \""+prefix+"\"")); item->setFlags(item->flags() & ~Qt::ItemIsSelectable); ui->listWidget->insertItem(0,item); for(int i=0;i<contacts.count();i++) { QString contactName=contacts.at(i)->text().split(":").first(); // For each contact: if it does not begin with the // given prefix, remove it (and keep it in the // removedContacts list for future use). if(!contactName.startsWith(prefix)) { this->removedContacts.append(*(contacts.at(i)));

12

} }

for(int j=0;j<ui->listWidget->count();j++) if(ui->listWidget->item(j)-> text().split(":").first()==contactName) ui->listWidget->takeItem(j);

} else if(prefix==QString("")) // If there is no prefix, then reload the initial contact list reloadContacts(); // Update the contacts list ui->listWidget->repaint();

The following images show how the search bar works:

Figure 5: The search bar WITHOUT groups

13

Figure 6: The search bar WITH groups

14

3.2 The groups


The following functions have been added in order to implement the groups: getGroups() : returns the list of groups (as (Q)List of (Q)Strings) removeGroup() : given a contact remove the contact itself from its group, if it exists

assignGroup() : shows a dialog in which the user can assign a specific group to a contact performAssignement() : saves the just-assigned group of the contact in a specific file on the device file-system reloadContacts() : updates the contacts list, displaying all the contacts with their groups In addition, the loadContacts() function has been changed.

The groups are saved in a specific file called jangiuGroups.txt, as shows the following code taken from performAssignement(), that populates that file:
void ContactsDialog::performAssignment() { if(groupField->text().compare("")) { QFile file("jangiuGroups.txt"); file.open(QIODevice::Append | QIODevice::Text); QTextStream out(&file); out out out out << << << << ui->listWidget->currentItem()->text().split(":").first(); ":"; groupField->text(); "\r\n";

15

} else }

file.close(); reloadContacts(); errorMessageBox("You haven't inserted any character");

The following code, from the reloadContacts() function, updates the window that contains the contacts with their groups:
void ContactsDialog::reloadContacts() { QListWidgetItem *item; QContact currContact; ui->listWidget->clear(); contactManager = new QContactManager("symbian"); QtMobility::QContactSortOrder order; order.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldCustomLabel); QList<QContact> contacts = contactManager->contacts(); // // LOAD FIRST CONTACTS IN GROUPS // QList<QString> groups=getGroups(); QList<QString> addedContacts; for(int i=0;i<groups.size();i++) { item = new QListWidgetItem(QIcon(":icons/group.png"), groups[i]); item->setFlags(item->flags() & ~Qt::ItemIsSelectable); ui->listWidget->addItem(item); QFile file("jangiuGroups.txt"); file.open(QIODevice::ReadOnly | QIODevice::Text); QTextStream in(&file); QString currLine; while((currLine=in.readLine(0))!=NULL) if(currLine.split(":")[1]==groups[i]) { for(int j=0; j<contacts.size(); j++) { currContact = contacts.at(j); if(currContact.displayLabel()==currLine. split(":")[0]) { QContactOnlineAccount sipUrl = currContact.

16

detail(QContactOnlineAccount::DefinitionName); QString nameAndNumber= currContact. DisplayLabel() + ": "+sipUrl.accountUri(); item = new QlistWidgetItem( Qicon(":icons/unknown.png"), nameAndNumber); ui->listWidget->addItem(item); addedContacts.insert(0,currLine. split(":")[0]); break; } } } file.close(); }

item = new QListWidgetItem(QIcon(":icons/group.png"), QString("No group")); item->setFlags(item->flags() & ~Qt::ItemIsSelectable); ui->listWidget->addItem(item); // appends it to list widget to display on screen for(int i=0; i<contacts.size(); i++) { currContact = contacts.at(i); if(!addedContacts.contains(currContact.displayLabel())) { QContactOnlineAccount sipUrl = currContact. detail(QContactOnlineAccount::DefinitionName); QString nameAndNumber = currContact. displayLabel()+": "+sipUrl.accountUri(); QListWidgetItem *item = new QlistWidgetItem (QIcon(":icons/unknown.png"), nameAndNumber); ui->listWidget->addItem(item); } } }

17

The following images show how the groups are implemented:

(a)

(b)

Figure 7: (a) Some contacts with their groups (b) How the user can assign a group to a contact

18

(a)

(b)

Figure 8: (a) How assignGroup() works (b) When the search bar is active a new search group is created

19

4. Modularity

and Portability

Another interesting issue to be clarified regards the portability of each added module. Depending to the changes made to the initial project, can be defined essentially two modules: A first module with all its function that implements the search function And a second module that implements the groups The first module relies on the keyReleaseEvent() function that is strictly dependent from the Symbian environment, because it is linked with the keyboards. By contrast, the second module depends only by the Qt libraries, that are not correlate with a specific device. The following image can clarify the concept:

Qt Symbian Module 1
(search bar) (search bar)

Module 2
(groups) (groups)

Figure 9: Portability of each module added to the Jangiu application

20

Note that it will be possible to adapt the first module to each device (and O.S.) simply changing the keyReleaseEvent() function, that handles the device keyboard. One solution could be to remove the #ifdef C statement [9] within the function.
/ // Search-contacts implementation begins here // void ContactsDialog::keyReleaseEvent(QKeyEvent *event) { // // Native support for both 0-9 keyboard // and QWERTY keyboard // #ifdef Q_OS_SYMBIAN /** * STEP 1: * Handling the keyboard */

21

5. Future

development

In terms of user interface (and beyond) the Jangiu application can be extended with the following utilities: Possibility to switch among various different conversations, for example using tabs Extend interoperability, for example making calls with other clients Backup of all the previous conversations Conversations with unconnected users, for example relying on a database Possibility to associate various different SIP addresses to one contact Shared rooms (send and receive messages among various contacts) Encrypt the outgoing data Adding a shared (other contacts can see it) string to the contact fields that describes its state, like facebook [10] Adding emoticon icons [11] to messages

22

References
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
Giulio Massaccesi, Un'applicazione VoIP per Symbian: Architettura. Tesi di Laurea (Thesis) [AY 2009-2010], University of Bologna.
http://en.wikipedia.org/wiki/Graphical_user_interface http://en.wikipedia.org/wiki/Symbian http://qt.nokia.com/products/ http://en.wikipedia.org/wiki/Session_Initiation_Protocol http://en.wikipedia.org/wiki/Carbide.c%2B%2B
http://www.developer.nokia.com/Resources/Tools_and_downloads/Other/Symbian_SDKs/

http://www.pjsip.org/ http://en.wikipedia.org/wiki/C_preprocessor http://en.wikipedia.org/wiki/Facebook http://en.wikipedia.org/wiki/Emoticon

23

Das könnte Ihnen auch gefallen