Canonical Voices

ssweeny

Ubuntu 14.10

I’m at a sprint in Washington, DC with my fellow Canonicalers gearing up for the commercial release of our phone OS (more on that later) but that doesn’t mean we’ve forgotten about the desktop and cloud.

Yesterday was another Ubuntu release day! We released Ubuntu 14.10, codenamed the Utopic Unicorn. Look for lots of subtle improvements to the desktop as we prepare some big things to come soon.

As usual, you can take a tour or go straight to the download page.

And while we’re at it, here’s to another 10 years of Ubuntu!

Read more
Nicholas Skaggs

Sprinting in DC: Thursday

This week, my team and I are sprinting with many of the core app developers and other folks inside of Ubuntu Engineering. Each day I'm attempting to give you a glimpse of what's happening.

Today started with some UOS planning which is happening in a couple short weeks. If you haven't yet put it on your calendar, please do so! And plan to not only attend, but consider submitting a session as well. The users track might be just the place for your session. Session topics can be about anything ubuntu related you might want to share or discuss with others.

As the week has progressed I've enjoyed getting to know the core apps developers better. Today we met with all of them to hear feedback on how the projects have been going. Lots of good discussion was had discussing how things like meetings and reviews work, individual project needs and actions that could be taken to improve all of the projects. It's wonderful to have everyone in the same place and able to talk.


After lunch the QA team discussed manual testing and proposed utilizing moztrap for some of the manual testing they are undertaking as part of the CI process for ubuntu touch images. While it is too early to say what implications this will have on manual testing from a community perspective, I'm happy to see the conversation has begun around the current issues facing manual tests. I'm also happy someone else is willing to be a guinea pig for changes like this! For image testing, the qatracker has served us well and will continue to do so, but I hope in the future we can improve the experience. In fact, we have done work in this area recently, and would love to hear from anyone who wants to help improve the qatracker experience. So, whether or not a migration to moztrap occurs at some point, the future looks bright.

The core app developers also got a chance to both get and receive feedback from the SDK and design teams. The deep dives into applications like calendar were very much appreciated and I expect those suggestions will filter into the applications in the near future. As usual the core apps developers came prepared with suggestions and grievances for the SDK team, as well as praises for things done well.

Finally to end the day, we discussed developer mode on the device. Rather than talk about the history of how it was implemented, let me share with you the future. Rather than locking adb access via a password, we'll utilize certificates. The password based solution already will ensure your locked device isn't vulnerable to nefarious humans who might want to connect and steal your data or reflash your phone. However, things like passwordless sudo will be possible with using certificates. In addition if security is the bane of your existence, you will be able to enable developer mode without setting a password at all.

Whew, today was very full!

Read more
Jane Silber

Today marks 10 years of Ubuntu and the release of the 21st version. That is an incredible milestone and one which is worthy of reflection and celebration. I am fortunate enough to be spending the day at our devices sprint with 200+ of the folks that have helped make this possible. There are of course hundreds of others in Canonical and thousands in the community who have helped as well. The atmosphere here includes a lot of reminiscing about the early days and re-telling of the funny stories, and there is a palpable excitement in the air about the future. That same excitement was present at a Canonical Cloud Summit in Brussels last week.

The team here is closing in on shipping our first phone, marking a new era in Ubuntu’s history. There has been excellent work recently to close bugs and improve quality, and our partner BQ is as pleased with the results as we are. We are on the home stretch to this milestone, and are still on track to have Ubuntu phones in the market this year. Further, there is an impressive array of further announcements and phones lined up for 2015.

But of course that’s not all we do – the Ubuntu team and community continue to put out rock solid, high quality Ubuntu desktop releases like clockwork – the 21st of which will be released today. And with the same precision, our PC OEM team continues to make that great work available on a pre-installed basis on millions of PCs across hundreds of machine configurations. That’s an unparalleled achievement, and we really have changed the landscape of Linux and open source over the last decade. The impact of Ubuntu can be seen in countless ways – from the individuals, schools, and enterprises who now use Ubuntu; to proliferation of Codes of Conduct in open source communities; to the acceptance of faster (and near continuous) release cycles for operating systems; to the unique company/community collaboration that makes Ubuntu possible; to the vast number of developers who have now grown up with Ubuntu and in an open source world; to the many, many, many technical innovations to come out of Ubuntu, from single-CD installation in years past to the more recent work on image-based updates.

Ubuntu Server also sprang from our early desktop roots, and has now grown into the leading solution for scale out computing. Ubuntu and our suite of cloud products and services is the premier choice for any customer or partner looking to operate at scale, and it is indeed a “scale-out” world. From easy to consume Ubuntu images on public clouds; to managed cloud infrastructure via BootStack; to standard on-premise, self-managed clouds via Ubuntu OpenStack; to instant solutions delivered on any substrate via Juju, we are the leaders in a highly competitive, dynamic space. The agility, reliability and superior execution that have brought us to today’s milestone remains a critical competency for our cloud team. And as we release Ubuntu 14.10 today, which includes the latest OpenStack, new versions of our tooling such as MaaS and Juju, and initial versions of scale-out solutions for big data and Cloud Foundry, we build on a ten year history of “firsts”.

All Ubuntu releases seem to have their own personality, and Utopic is a fitting way to commemorate the realisation of a decade of vision, hard work and collaboration. We are poised on the edge of a very different decade in Canonical’s history, one in which we’ll carry forward the applicable successes and patterns, but will also forge a new path in the twin worlds of converged devices and scale-out computing. Thanks to everyone who has contributed to the journey thus far. Now, on to Vivid and the next ten years!

Read more
UbuntuTouch

URL dispatcher 是在Ubuntu OS上的一个服务。它可以让我们的应用(confined,i.e, click package应用)来启动其它的应用。这些应用通常是一个特别的URL来 识别的。可能最常见的例子就是向网页浏览器发送http:// URL来启动网页浏览器,但是像music或其它的应用也可以支持。对于大多数的应用来说,这是一个最有用的方式来退出现有的应用来启动另外一个应用。


对于Qt应用来说,它访问URL dispatcher的方法是通过Qt的desktop plugin。C++应用可以通过使用QDesktopServices.openURL()方法。QML应用可以使
用 Qt.openUrlExternally(string)方法。对于其它的应用来说,它们可以利用根据自己的需求使用Platform API或直接使用liburl-dispatcher。

URL dispatcher项目可以在Launchpad的链接找到。

支持的URL格式

基本URL格式


在URL dispatcher中有几种被支持的格式:



application:///$(app_id).desktop
The application URL can be used to start an application with a known Application ID. For applications that install their desktop file in /usr/share/applications the application ID should just be the name of the desktop file.
appid://$(pkg)/$(app)/$(version) Allows for launching an application using an application ID. Also provides for wild cards. The $(app) can be first-listedlast-listed-app or only-listed-app to select the appropriate applicaiton using the click manifest. Also the $(version) can be current-user-version to select the version in the manifest

这里的第二种方法是推荐的方法。比如对于Clock应用来说,我们可以看到如下的应用URL:


appid://com.ubuntu.clock/clock/current-user-version

我们可以通过如下的方法得到在手机中应用click package的信息:


     


应用URL

对于一些应用来说,我们可以在启动应用的时候同时传人一些参数来启动该应用。我们可以通过在应用的Click manifest文件中加入URL的定义来注册该应用可以被一个或多个URL来启动。为了达到这个目的,我们可以在该文件中的“hooks”部分加入一个和“desktop”并列的小的json文件的申明。一个简单的manifest就像下面定义的。


{
        "name": "My App",
        "version": "1.2.3",
        "hooks": {
                "foo": {
                        "desktop": "foo.desktop",
                        "urls": "foo.url-dispatcher"
                }
        }
}

这里它指向另外一个在click包中的JSON文件。它定义了什么URL将被接受。一个简单的文件就像如下的格式:

[
        {
                "protocol": "foo",
                "domain-suffix": "bar.com"
        }
]

通过上面的定义,每当有任何一个像“foo://*.bar.com”格式URL请求,由foo.desktop代表的应用将被自动被调用。在这里,如果“domain-suffix”项被省去的话,该应用将接受所有以“foo”代表的protocol格式的请求。URL dispatcher的定义是一个数组,这样有很多的这样的格式可以在应用中被定义。

一个例程显示如何调用Music及Clock可以在如下的地址找到:

bzr branch lp:~liu-xiao-guo/debiantrial/launchapps

作者:UbuntuTouch 发表于2014-10-23 23:06:03 原文链接
阅读:90 评论:0 查看评论

Read more
Nicholas Skaggs

Sprinting in DC: Wednesday

This week, my team and I are sprinting with many of the core app developers and other folks inside of Ubuntu Engineering. Each day I'm attempting to give you a glimpse of what's happening.

To kick off the day, I led a session on something that has been wreaking havoc for application test writers within the core apps -- environment setup. In theory, setting up the environment to run your test should be easy. In practice, I've found it increasingly difficult. The music, calendar, clock, reminders, file manager and other teams have all been quite affected by this and the canonical QA team and myself have all pitched in to help, but struggled as well. In short, a test should be easy to launch, be well behaved and not delete any user data, and be easy to setup and feed test data into for the test process. I'm happy to report that the idea of a permanent solution has been reached. Now we must implement it of course, but the result should be drastically easier and more reliable test setup for you the test author.

I also had the chance to list some grievances for application developers with the QA team. We spoke about wanting to expand the documentation on testing and specifically targeted the need to create better templates in the ubuntu sdk for new projects. When you start a new project you should have well functioning tests, and we should teach you about how to run them too!



Just before lunch the community core app developers were able to discuss post-RTM plans and features. A review of the apps was undertaken and some desire for new designs or features were discussed. Terminal is being rebuilt to be more aligned with upstream. Music is currently undergoing a re-design which is coming along great. Calculator is anxious to get some design love. Reminders potential for offline notetaking as well as potential name changes were all discussed. Overall, an amazing accomplishment by all the developers!

After lunch, I spent time confirming the fix for a longstanding bug within autopilot. The merge proposal for fixing this bug has been simmering all summer and it's time to get it fixed. The current test suites for calendar and clock have been impacted by this and have already had regressions occur that could have been caught had tests been able to be written for this area. Having myself, the autopilot team, and the calendar developers in one place made fixing this possible.

To end the day, I spent some time attending sessions for changes to CI and learning more about the coming changes to CI within ubuntu. In summary the news is wonderful. CI will test using autopkgtest, and all of ubuntu will come under this umbrella -- phone, desktop, everything. If it's a package and it has tests, we will do all of the autopkgtest goodness currently being done for the distro.

The evening closed with a bit of fun provided by a game making hackathon using bacon2d and the hilariously horrible "Turkish Star Wars". We could always use more games in the ubuntu app store, and I hear there might even still be a pioneers t-shirt or two left if you get it in early!

Read more
facundo


¿Qué es un satélite? Hay varias definiciones... para el propósito de este artículo, podemos decir que es un objeto que orbita alrededor de otro. Nuestro planeta tiene un satélite natural (la Luna) y muchos, muchísimos satélites artificiales.

Crear un nuevo satélite artificial, es decir poner un aparato creado por los humanos a girar alrededor de la tierra es bastante fácil. Es cuestión de subir el aparato lo suficientemente alto, es decir, ponerlo en órbita. Claro, crear un satélite artificial útil tampoco es moco de pavo, hay que ponerlo en una órbita más o menos controlada, y poder comunicarse con el aparato.

Hay un detalle importante en la frase anterior. Estoy hablando de órbitas... una órbita terrestre es el camino que recorre el satélite cuando está girando por alredor de la Tierra. Y claro, hay muchas, ¡infinidades! Agarren una pelota, por ejemplo, y van a ver que pueden trazar con una lapicera muchísimos recorridos distintos alrededor de ella, y a eso hay que sumarle que las órbitas pueden estar a distintas alturas (la altura del satélite afecta la velocidad a la que se desplaza, cuanto más abajo está más rápido tiene que ir para no "caerse", mientras que cuanto más alto está más lento tiene que ir para no "salir disparado" de la órbita terrestre).

Órbitas hay un montón, pero no todas son útiles. Un ejemplo de una órbita útil es la llamada "órbita sincrónica al sol", que se logra combinando altitud e inclinación para lograr que el satélite pase sobre una determinada latitud terrestre a la misma hora del día. Esto es piola para aquellos satélites que tienen que sacar imágenes del suelo terrestre, porque quizás es suficiente con que pasen un par de veces al día por arriba del lugar que tienen que fotografiar. Es el caso de los nanosatélites que estuvimos mandando estos años.

Hay, sin embargo, una órbita que es muy especial. Si al satélite lo ponemos justo sobre la linea del ecuador, y lo hacemos girar a una velocidad específica, en lugar de verlo pasar cada tanto, lo vamos a estar viendo siempre en el mismo punto en el cielo.

Esta órbita se llama geostacionaria. Para ponerlo en términos precisos, la órbita geoestacionaria es una órbita geosíncrona en el plano ecuatorial terrestre, con una excentricidad nula (órbita circular) y un movimiento de oeste a este.

Órbita síncrona

Arthur C. Clarke popularizó la idea de utilizar la órbita geoestacionaria para poner allí satélites de comunicaciones (lo hizo en un paper en 1945, "Extra-Terrestrial Relays", por el cual ganó el premio Marconi en 1982).

Un satélite en órbita geoestacionaria es muy importante para las comunicaciones, porque como siempre se lo ve en el mismo lugar, se puede apuntar una antena y dejarla fija en esa dirección, y tener un enlace permanente con el satélite. O sea que dos puntos en la tierra, apuntando al mismo satélite, pueden estar comunicados todo el tiempo. Este concepto es la base de las comunicaciones modernas en nuestra sociedad, afectando profundamente la forma en que vivimos.

Las órbitas geoestacionarias sólo se pueden conseguir muy cerca de un anillo de 35.786 km sobre el ecuador. En la práctica, esto significa que todos los satélites geoestacionarios deben estar en este anillo, y sólo en ese anillo, por lo cual la cantidad de satélites que se puede poner ahí es limitada.

Estarán de acuerdo conmigo que las comunicaciones son un factor clave en nuestra sociedad: es por eso muy importante quien tiene el poder sobre los satélites en esa órbita, quien los controla. La organización que está coordinando la asignación de estos espacios es la Unión Internacional de Telecomunicaciones.

Con el ARSAT-1 (lanzado el pasado 16 de Octubre) Argentina vuelve a ocupar una posición orbital que tenía asignada (que estuvo ocupada hasta el 2010 por el Nahuel 1A), y que corría el riesgo de perder luego de cuatro años de no utilizarla.

ARSAT 1

Es por eso que este satélite era tan importante. No sólo porque fue desarrollado, financiado y ensamblado acá (Argentina es ahora una de las pocas naciones que hacen sus propios satélites) sino porque es un factor clave en la soberanía del país, ya que permite tener control propio sobre un elemento clave para las comunicaciones.

Read more
Nicholas Skaggs

Sprinting in DC: Tuesday

This week, my team and I are sprinting with many of the core app developers and other folks inside of Ubuntu Engineering. Each day I'm attempting to give you a glimpse of what's happening.

On Tuesday I was finally able to sit down with the team and plan our week. In addition I was able to plan some of the work I had in mind with the community folks working on the core apps. Being obsessed with testing, my primary goals this week are centered around quality. Namely I want to make it easier for developers to write tests. Asking them to write tests is much easier when it's easy to do so. Fortunately, I think (hope?) all of the community core apps developers recognize the benefits to tests and thus are motivated to drive maturity into the testing story.

I'm also keen to work on the manual testing story. The community is imperative in helping test images for not only ubuntu, but also all of it's flavors. Seriously, you should say thank you to those folks helping make sure your install of ubuntu works well. They are busy this week helping make sure utopic is as good as it can be. Rock on image testers! But the tools and process used weigh on my mind, and I'm keen to chat later in the week with the canonical QA team and get there feedback.

During the day I attended sessions regarding changes and tweaks to the CI process. For core apps developers, errors in jenkins should be easier to replicate after these changes. CI will be moving to utilizing adt-run (autopkgtest) for there test execution (and you should too!). They will also provide the exact commands used to run the test. That means you can easily duplicate the results on the dashboard locally and fix the issues found. No more works on my box excuses!

I also met the team responsible for the application store and gave them feedback on the application submission process. Submitting apps is already so simple, but even more cool things are happening on this front.

The end of the evening found us shuffling into cab's for a team dinner. We had a long table of folks eating Italian food and getting to know each other better.


After dinner, I pressured a few folks into having some dessert and ordered a sorbet for myself. After receiving no less than 4 fruit sorbets due to a misunderstanding, I began carving the fruits and sending plates of sorbet down the table. My testcase failed however when the plates all came back :-(



Read more
Nicholas Skaggs

Sprinting in DC: Monday

This week, my team and I are sprinting in Washington DC with many of the core app developers and other folks inside of Ubuntu Engineering. Sprints are always busy, but the work tends to be a mix of social and technical. I get to assign names (IRC nicknames mostly) to faces as well as get to know my co-workers and other community members better.

I thought it might be useful to give writeups each day of what's going on, at least from my perspective during the sprint. I won't yammer on too much about quality and instead bring you pictures of what you really want. And some of this too. Whoops, here's one.

Pictures of people taking pictures . . .
Monday was the first day of the sprint, and also the day of my arrival! Personally I'm busy at home during this week, so it's tough to get away. That said, I can't imagine being anywhere else for the week. The sprints are a wonderful source of respite for everyone.

Monday itself consisted of making sure everything is ready for the week, planning events, and icebreakers. In typical fashion, an opening plenary set the bar for the week with notes about the progress being made on the phone as well as the future of the desktop. Lots of meetings and a few blurry jet lagged hours later, everyone was ready to sit for a bit and have some non-technical conversation!

Fortunately for us there was an event planned to meet both our social and hunger needs. After being split randomly into teams of bugs (love the play on quality), we played a bit of trivia. After each round teams were scored not only on the correct response, but also how quickly they responded. The questions varied from the obscure to fun bits about ubuntu. The final round centered around Canonical itself which was fun trip down memory lane to remember.

As I crawled into bed I still had the wonderfully cheesy announcer playing trivia questions in my head.


Read more
pitti

I’m on my way home from Düsseldorf where I attended the LinuxCon Europe and Linux Plumber conferences. I was quite surprised how huge LinuxCon was, there were about 1.500 people there! Certainly much more than last year in New Orleans.

Containers (in both LXC and docker flavors) are the Big Thing everybody talks about and works with these days; there was hardly a presentation where these weren’t mentioned at all, and (what felt like) half of the presentations were either how to improve these, or how to use these technologies to solve problems. For example, some people/companies really take LXC to the max and try to do everything in them including tasks which in the past you had only considered full VMs for, like untrusted third-party tenants. For example there was an interesting talk how to secure networking for containers, and pretty much everyone uses docker or LXC now to deploy workloads, run CI tests. There are projects like “fleet” which manage systemd jobs across an entire cluster of containers (distributed task scheduler) or like project-builder.org which auto-build packages from each commit of projects.

Another common topic is the trend towards building/shipping complete (r/o) system images, atomic updates and all that goodness. The central thing here was certainly “Stateless systems, factory reset, and golden images” which analyzed the common requirements and proposed how to implement this with various package systems and scenarios. In my opinion this is certainly the way to go, as our current solution on Ubuntu Touch (i. e. Ubuntu’s system-image) is far too limited and static yet, it doesn’t extend to desktops/servers/cloud workloads at all. It’s also a lot of work to implement this properly, so it’s certainly understandable that we took that shortcut for prototyping and the relatively limited Touch phone environment.

On Plumbers my main occupations were mostly the highly interesting LXC track to see what’s coming in the container world, and the systemd hackfest. On the latter I was again mostly listening (after all, I’m still learning most of the internals there..) and was able to work on some cleanups and improvements like getting rid of some of Debian’s patches and properly run the test suite. It was also great to sync up again with David Zeuthen about the future of udisks and some particular proposed new features. Looks like I’m the de-facto maintainer now, so I’ll need to spend some time soon to review/include/clean up some much requested little features and some fixes.

All in all a great week to meet some fellows of the FOSS world a gain, getting to know a lot of new interesting people and projects, and re-learning to drink beer in the evening (I hardly drink any at home :-P).

If you are interested you can also see my raw notes, but beware that there are mostly just scribbling.

Now, off to next week’s Canonical meeting in Washington, DC!

Read more
UbuntuTouch

对很多的开发者来说,你们可能使用的不是Ubuntu操作系统。在这种情况下,开发者需要在自己的操作系统中(OS X及Windows)安装virtualbox,并在VirtualBox中安装Ubuntu及Ubuntu SDK。为了方便大家的安装,我们已经制定好了一个Image。这个Image中包含Ubuntu Utopic (14.10)及Ubuntu SDK。大家可以一次性地下载并安装SDK。下面介绍其安装步骤。

1)从https://www.virtualbox.org/wiki/Downloads下载最新的VirtualBox

Download VirtualBox


注意:当我们下载VirtualBox是,一定要根据自己的系统选择合适的版本。


2)双击刚下载的VirtualBox文件,并安装它

3)下载Ubuntu virtual machine (最小的Ubuntu 14.10 desktop版本及已经在里面安装好的Ubuntu SDK)

4)等下完后,双击已经下载的文件“ubuntu+sdk.ova”来导入到VirtualBox中,并运行它


注意:在整个安装过程中,需要用到的用户名及密码是“ubuntu/ubuntu”

在安装完整个SDK后,我们可以参照文章“怎么在Virtualbox下安装Ubuntu OS”来设置自己的中文输入法及文件分享。可以参照文章“Ubuntu SDK 安装”来进一步安装自己的“armhf”及“i386” chroot。整个安装chroot的过程可能需要一定的时间。需要耐心等待。等整个安装过程完成了,我们就可以进行下一步的开发了。

作者:UbuntuTouch 发表于2014-10-17 9:50:48 原文链接
阅读:213 评论:0 查看评论

Read more
Nicholas Skaggs

The final images of what will become utopic are here! Yes, in just one short week utopic unicorn will be released into the world. Celebrate this exciting release and be among the first to run utopic by helping us test!

We need your help and test results, both positive and negative. Please head over to the milestone on the isotracker, select your favorite flavor, and perform the needed tests against the images.

If you've never submitted test results for the iso tracker, check out the handy links on top of the isotracker page detailing how to perform an image test, as well as a little about how the qatracker itself works. If you still aren't sure or get stuck, feel free to contact the qa community or myself for help.

Thank you for helping to make ubuntu better! Happy Testing!

Read more
Robbie Williamson

The following is an update on Ubuntu’s response to the latest Internet emergency security issue, POODLE (CVE-2014-3566), in combination with an
SSLv3 downgrade vulnerability.

Vulnerability Summary

“SSL 3.0 is an obsolete and insecure protocol. While for most practical purposes it has been replaced by its successors TLS 1.0, TLS 1.1, and TLS 1.2, many TLS implementations remain backwards­ compatible with SSL 3.0 to interoperate with legacy systems in the interest of a smooth user experience. The protocol handshake provides for authenticated version negotiation, so normally the latest protocol version common to the client and the server will be used.” -https://www.openssl.org/~bodo/ssl-poodle.pdf

A vulnerability was discovered that affects the protocol negotiation between browsers and HTTP servers, where a man-in-the-middle (MITM) attacker is able trigger a protocol downgrade (ie, force downgrade to SSLv3, CVE to be assigned).  Additionally, a new attack was discovered against the CBC block cipher used in SSLv3 (POODLE, CVE-2014-3566).  Because of this new weakness in the CBC block cipher and the known weaknesses in the RC4 stream cipher (both used with SSLv3), attackers who successfully downgrade the victim’s connection to SSLv3 can now exploit the weaknesses of these ciphers to ascertain the plaintext of portions of the connection through brute force attacks.  For example, an attacker who is able to manipulate the encrypted connection is able to steal HTTP cookies.  Note, the protocol downgrade vulnerability exists in web browsers and is not implemented in the ssl libraries.  Therefore, the downgrade attack is currently known to exist only for HTTP.

OpenSSL will be updated to guard against illegal protocol negotiation downgrades (TLS_FALLBACK_SCSV).  When the server and client are updated to use TLS_FALLBACK_SCSV, the protocol cannot be downgraded to below the highest protocol that is supported between the two (so if the client and the server both support TLS 1.2, SSLv3 cannot be used even if the server offers SSLv3).

The recommended course of action is ultimately for sites to disable SSLv3 on their servers, and for browsers to disable SSLv3 by default since the SSLv3 protocol is known to be broken.  However, it will take time for sites to disable SSLv3, and some sites will choose not to, in order to support legacy browsers (eg, IE6).  As a result, immediately disabling SSLv3 in Ubuntu in the openssl libraries, in servers or in browsers, will break sites that still rely on SSLv3.

Ubuntu’s Response:

Unfortunately, this issue cannot be addressed in a single USN because this is a vulnerability in a protocol, and the Internet must respond accordingly (ie SSLv3 must be disabled everywhere).  Ubuntu’s response provides a path forward to transition users towards safe defaults:

  • Add TLS_FALLBACK_SCSV to openssl in a USN:  In progress, upstream openssl is bundling this patch with other fixes that we will incorporate
  • Follow Google’s lead regarding chromium and chromium content api (as used in oxide):
    • Add TLS_FALLBACK_SCSV support to chromium and oxide:  Done – Added by Google months ago.
    • Disable fallback to SSLv3 in next major version:  In Progress
    • Disable SSLv3 in future version:  In Progress
  • Follow Mozilla’s lead regarding Mozilla products:
    • Disable SSLv3 by default in Firefox 34:  In Progress – due Nov 25
    • Add TLS_FALLBACK_SCSV support in Firefox 35:  In Progress

Ubuntu currently will not:

  • Disable SSLv3 in the OpenSSL libraries at this time, so as not to break compatibility where it is needed
  • Disable SSLv3 in Apache, nginx, etc, so as not to break compatibility where it is needed
  • Preempt Google’s and Mozilla’s plans.  The timing of their response is critical to giving sites an opportunity to migrate away from SSLv3 to minimize regressions

For more information on Ubuntu security notices that affect the current supported releases of Ubuntu, or to report a security vulnerability in an Ubuntu package, please visit http://www.ubuntu.com/usn/.

 

Read more
UbuntuTouch

我在以前的文章中,讲述了如何使用U1dbSQLite offline storage API来存储应用的一些状态。在这篇文章中,我将介绍如何使用Qt.labs.settings来存储应用的状态。更加详细的介绍,请参阅链接


首先,我们创建一个最简单的“App with Simple UI”模版应用,并修改文件“main.qml”如下:

import QtQuick 2.0
import Ubuntu.Components 1.1
import Qt.labs.settings 1.0

/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "com.ubuntu.developer.liu-xiao-guo.settings"

    /*
     This property enables the application to change orientation
     when the device is rotated. The default is false.
    */
    //automaticOrientation: true

    // Removes the old toolbar and enables new features of the new header.
    useDeprecatedToolbar: false

    width: units.gu(50)
    height: units.gu(75)

    Page {
        title: i18n.tr("Simple")

        Column {
            anchors.fill: parent
            anchors.centerIn: parent
            anchors.horizontalCenter: parent.center


            Label {
                text: "Please input a string below:"
                fontSize: "large"
            }

            TextField {
                id: myTextField
                text: settings.input
                placeholderText: "please input a string"

                onTextChanged: {
                    settings.input = text
                }
            }

            Button {
                text: "Get category"
                onClicked: {
                    console.log("settings category:" + settings.category);
                }
            }
        }

        Settings {
            id: settings
            property string input: "unknown"
        }

        Component.onDestruction: {
            settings.input = myTextField.text
        }
    }
}

记得这里我们一定要加入Qt.labs.settings。我们首先绑定myTextField的值为settings中的input。在程序退出的时候,我们通过如下的方式进行存储:


        Component.onDestruction: {
            settings.input = myTextField.text
        }

在我们的应用中,我们使用如下的方法。每当myTextField变化时,我们就存一下。这依赖于我们最终程序的需求是什么样的。

            TextField {
                id: myTextField
                text: settings.input
                placeholderText: "please input a string"

                onTextChanged: {
                    settings.input = text
                }
            }

运行我们的应用,我们会发现,当我们修改myTextField中的值,并退出后。下次启动时,可以看到,上次输入的值被读取,并存放于myTextField中。



整个测试的源码在 bzr branch lp:~liu-xiao-guo/debiantrial/settingsqml

作者:UbuntuTouch 发表于2014-10-16 15:18:13 原文链接
阅读:187 评论:0 查看评论

Read more
UbuntuTouch

QML入门必备基础知识之——UI布局管理


概述

使用 Qt 做过 UI 后一定对 QHBoxLayout, QVBoxLayout, 和 QGridLayout 这三个最重要也最常使用的 layout managers 非常熟悉。那么在 QML 中又是如何控制和管理 UI 布局的呢?那么我们这篇文章就为大家介绍这些基础知识。

首先,QML 同样允许大家使用硬编码的方式将位置数值直接写到代码中,但是这样做首先难以适应 UI 的调整,其次代码维护起来也很困难。因此我们推荐大家不要直接写数值,而是使用下列三种布局管理器:Row,、Column、Grid,以及使用 Anchor 进行布局。

Row

QML 中的 Row 元素会将其子控件都排列在同一行,相互不重叠。我们还可以使用它的 spacing 属性来定义子控件之间的距离。比如下列代码就会产生如图所示的效果:

Row { 
spacing: 2
Rectangle { color: "red"; width: 50; height: 50 }
Rectangle { color: "green"; width: 20; height: 50 }
Rectangle { color: "blue"; width: 50; height: 20 }
}

Row.png




Column

QML 中的 Column 元素会将其子控件都排列在同一行,相互不重叠。我们可以使用它的 spacing 属性来定义子控件之间的距离。比如下列代码就会产生如图所示的效果:

Column { 
spacing: 2
Rectangle { color: "red"; width: 50; height: 50 }
Rectangle { color: "green"; width: 20; height: 50 }
Rectangle { color: "blue"; width: 50; height: 20 }
}

Column.png





Grid

QML 中的 Grid 元素会将其子控件都均匀地排列在一个网格内,相互不重叠,每一个子控件都被放置在一个网格单元的(0,0)位置,也就是左上角。Grid的 rows 和 columns 属性定义网格的行数和列数,列数默认是4。我们还可以使用 Grid 的spacing 属性来定义网格单元之间的距离,这里注意水平和垂直方向的 spacing 都是一样的。比如下列代码就会产生如图所示的效果:

Grid { 
columns: 3
spacing: 2
Rectangle { color: "red"; width: 50; height: 50 }
Rectangle { color: "green"; width: 20; height: 50 }
Rectangle { color: "blue"; width: 50; height: 20 }
Rectangle { color: "cyan"; width: 50; height: 50 }
Rectangle { color: "magenta"; width: 10; height: 10 }
}

Grid.png




混合应用

我们还可以将 Grid、Row 和 Column 进行混合应用。比如下面的代码会产生如图所示的效果:

Column {
spacing: 2
Rectangle { color: "red"; width: 50; height: 50 }
Row {
spacing: 2
Rectangle { color: "yellow"; width: 50; height: 50 }
Rectangle { color: "black"; width: 20; height: 50 }
Rectangle { color: "blue"; width:50; height: 20 }
}
Rectangle { color: "green"; width: 20; height: 50 }
}

Combine.png






Anchor

每一个 item 都可以被认为具有 7 条隐藏的“anchor lines":left、 horizontalCenter、 right、 top、 verticalCenter、baseline、以及 bottom,如下图所示: Anchor1.png

其中 baseline 是指的文本所在的线,在上图中并未标出,如果 item 没有文字的话 baselinw 就和 top 的位置是相同的。 除此之外,Anchor 系统还提供了margins 和 offsets。margins 是指一个 item 和外界之间所留有的空间,而 offsets 则可以通过使用 center anchor lines 来进行布局。如下图所示:

Anchor2.png





使用 QML anchoring 系统,我们可以定义不同 items 之间的 anchor lines 之间的关系。例如:

Rectangle { id: rect1; ... }
Rectangle { id: rect2; anchors.left: rect1.right; anchors.leftMargin: 5; ... }

执行效果:Anchor3.png




我们还可以使用多个 anchors:

Rectangle { id: rect1; ... }
Rectangle { id: rect2; anchors.left: rect1.right; anchors.top: rect1.bottom; ... }

执行效果:Anchor4.png





通过定义多个水平或垂直的 anchors,我们还可以控制 item 的大小,例如:

Rectangle { id: rect1; x: 0; ... }
Rectangle { id: rect2; anchors.left: rect1.right; anchors.right: rect3.left; ... }
Rectangle { id: rect3; x: 150; ... }

执行效果:Anchor5.png


注意:出于效率方面的考虑,我们只允许对一个 item 的邻居和直接父亲使用 anchor 定义。比如下面的定义是不合法的:

 Item {
id: group1
Rectangle { id: rect1; ... }
}
Item {
id: group2
Rectangle { id: rect2; anchors.left: rect1.right; ... } // invalid anchor!
}
本文原文出“QML入门必备基础知识之——UI布局管理
作者:UbuntuTouch 发表于2014-10-16 9:41:16 原文链接
阅读:94 评论:0 查看评论

Read more
David Callé

Scopes come with a very flexible customization system. From picking the text color to rearranging how results are laid out, a scope can easily look like a generic RSS reader, a music library or even a store front.

In this new article, you will learn how to make your scope shine by customizing its results, changing its colors, adding a logo and adapting its layout to present your data in the best possible way. Read…

screenshot20145615_125616591

Read more
Michael Hall

Will CookeThis is a guest post from Will Cooke, the new Desktop Team manager at Canonical. It’s being posted here while we work to get a blog setup on unity.ubuntu.com, which is where you can find out more about Unity 8 and how to get involved with it.

Intro

Understandably, most of the Ubuntu news recently has focused around phones. There is a lot of excitement and anticipation building around the imminent release of the first devices.  However, the Ubuntu Desktop has not been dormant during this time.  A lot of thought and planning has been given to what the desktop will become in the future; who will use it and what will they use it for.  All the work which is going in to the phone will be directly applicable to the desktop as well, since they will use the same code.  All the apps, the UI tweaks, everything which makes applications secure and stable will all directly apply to the desktop as well.  The plan is to have the single converged operating system ready for use on the desktop by 16.04.

The plan

We learned some lessons during the early development of Unity 7. Here’s what happened:

  • 11.04: New Unity as default
  • 11.10: New Unity version
  • 12.04: Unity in First LTS

What we’ve decided to do this time is to keep the same, stable Unity 7 desktop as the default while we offer users who want to opt-in to Unity8 an option to use that desktop. As development continues the Unity 8 desktop will get better and better.  It will benefit from a lot of the advances which have come about through the development of the phone OS and will benefit from continual improvements as the releases happen.

  • 14.04 LTS: Unity 7 default / Unity 8 option for the first time
  • 14.10: Unity 7 default / Unity 8 new rev as an option
  • 15.04: Unity 7 default / Unity 8 new rev as an option
  • 15.10: Potentially Unity 8 default / Unity 7 as an option
  • 16.04 LTS: Unity 8 default / Unity 7 as an option

As you can see, this gives us a full 2 cycles (in addition to the one we’ve already done) to really nail Unity 8 with the level of quality that people expect. So what do we have?

How will we deliver Unity 8 with better quality than 7?

Continuous Integration is the best way for us to achieve and maintain the highest quality possible.  We have put a lot of effort in to automating as much of the testing as we can, the best testing is that which is performed easily.  Before every commit the changes get reviewed and approved – this is the first line of defense against bugs.  Every merge request triggers a run of the tests, the second line of defense against bugs and regressions – if a change broke something we find out about it before it gets in to the build.

The CI process builds everything in a “silo”, a self contained & controlled environment where we find out if everything works together before finally landing in the image.

And finally, we have a large number of tests which run against those images. This really is a “belt and braces” approach to software quality and it all happens automatically.  You can see, we are taking the quality of our software very seriously.

What about Unity 7?

Unity 7 and Compiz have a team dedicated to maintenance and bug fixes and so the quality of it continues to improve with every release.  For example; windows switching workspaces when a monitor gets unplugged is fixed, if you have a mouse with 6 buttons it works, support for the new version of Metacity (incase you want to use the Gnome2 desktop) – added (and incidentally, a lot of that work was done by a community contributor – thanks Alberts!)

Unity 7 is the desktop environment for a lot of software developers, devops gurus, cloud platform managers and millions of users who rely on it to help them with their everyday computing.  We don’t want to stop you being able to get work done.  This is why we continue to maintain Unity 7 while we develop Unity 8.  If you want to take Unity 8 for a spin and see how its coming along then you can; if you want to get your work done, we’re making that experience better for you every day.  Best of all, both of these options are available to you with no detriment to the other.

Things that we’re getting in the new Ubuntu Desktop

  1. Applications decoupled from the OS updates.  Traditionally a given release of Ubuntu has shipped with the versions of the applications available at the time of release.  Important updates and security fixes are back-ported to older releases where required, but generally you had to wait for the next release to get the latest and greatest set of applications.  The new desktop packaging system means that application developers can push updates out when they are ready and the user can benefit right away.
  2. Application isolation.  Traditionally applications can access anything the user can access; photos, documents, hardware devices, etc.  On other platforms this has led to data being stolen or rendered otherwise unusable.  Isolation means that without explicit permission any Click packaged application is prevented from accessing data you don’t want it to access.
  3. A full SDK for writing Ubuntu apps.  The SDK which many people are already using to write apps for the phone will allow you to write apps for the desktop as well.  In fact, your apps will be write once run anywhere – you don’t need to write a “desktop” app or a “phone” app, just an Ubuntu app.

What we have now

The easiest way to try out the Unity 8 Desktop Preview is to use the daily Ubuntu Desktop Next live image:   http://cdimage.ubuntu.com/ubuntu-desktop-next/daily-live/current/   This will allow you to boot into a Unity 8 session without touching your current installation.  An easy 10 step way to write this image to a USB stick is:

  1. Download the ISO
  2. Insert your USB stick in the knowledge that it’s going to get wiped
  3. Open the “Disks” application
  4. Choose your USB stick and click on the cog icon on the righthand side
  5. Choose “Restore Disk Image”
  6. Browse to and select the ISO you downloaded in #1
  7. Click “Start restoring”
  8. Wait
  9. Boot and select “Try Ubuntu….”
  10. Done *

* Please note – there is currently a bug affecting the Unity 8 greeter which means you are not automatically logged in when you boot the live image.  To log in you need to:

  1. Switch to vt1 (ctrl-alt-f1)
  2. type “passwd” and press enter
  3. press enter again to set the current password to blank
  4. enter a new password twice
  5. Check that the password has been successfully changed
  6. Switch back to vt7 (ctrl-alt-f7)
  7. Enter the new password to login

 

Here are some screenshots showing what Unity 8 currently looks like on the desktop:

00000009000000190000003100000055000000690000011000000183000001950000020700000255000002630000032800000481

The team

The people working on the new desktop are made up of a few different disciplines.  We have a team dedicated to Unity 7 maintenance and bug fixes who are also responsible for Unity 8 on the desktop and feed in a lot of support to the main Unity 8 & Mir teams. We have the Ubuntu Desktop team who are responsible for many aspects of the underlying technologies used such as GNOME libraries, settings, printing etc as well as the key desktop applications such as Libreoffice and Chromium.  The Ubuntu desktop team has some of the longest serving members of the Ubuntu family, with some people having been here for the best part of ten years.

How you can help

We need to log all the bugs which need to be fixed in order to make Unity 8 the best desktop there is.  Firstly, we need people to test the images and log bugs.  If developers want to help fix those bugs, so much the better.  Right now we are focusing on identifying where the work done for the phone doesn’t work as expected on the desktop.  Once those bugs are logged and fixed we can rely on the CI system described above to make sure that they stay fixed.

Link to daily ISOs:  http://cdimage.ubuntu.com/ubuntu-desktop-next/daily-live/current/

Bugs:  https://bugs.launchpad.net/ubuntu/+source/unity8-desktop-session

IRC:  #ubuntu-desktop on Freenode

Read more
UbuntuTouch

在前面的一些文章中,我们已经介绍了一些怎么利用Qt和C++ API来创建一个Scope。它们都是一些基本的Scope。在这篇文章中,我们将介绍department Scope,并掌握开发它的方法。Department Scope将会在许多的Scope中进行分类搜寻。更多关于Scope的介绍可以在网址http://developer.ubuntu.com/scopes/找到。我们最终的Scope的界面如下:


      


1)什么是department Scope


首先,坦率地说,我们很难找到一个很确切的中文词来描述它。姑且叫它部门Scope吧。在上面的左图上,我们可以看到在“美食”的正右边,有一个向下的下拉箭头。点击它后,就可以看到如中间图所示的菜单。这也就是说,我们可以对点评网的每个category进行分别地搜索,而不是把不同领域的搜索结果都罗列出来。比方,我想找吃的,我只想知道和餐馆相关的信息,而不要和美容,娱乐相关的搜寻结果。通过我们对点评API的接口

http://api.dianping.com/v1/business/find_businesses?appkey=3562917596&sign=16B7FAB0AE9C04F356C9B1BE3BB3B77829F83EDA&category=美食&city=上海&latitude=31.18268013000488&longitude=121.42769622802734&sort=1&limit=20&offset_type=1&out_offset_type=1&platform=2

进行分析,我们可以把“category”设置为我们的部门,这样我们就可以对每个领域进行分别的搜寻。我们也可以通API接口来得到所有点评的category:

http://api.dianping.com/v1/metadata/get_categories_with_businesses

关于这个API的接口具体可以在链接找到。

2)创建一个基本的Scope

首先,我们来打开我们的Ubuntu SDK来创建一个最基本的应用。我们选择菜单“New file or Project”或使用热键“Ctrl+N”。我们选择“Unity Scope”模版。



我们给我们的应用一个名字“dianping”。我们同事也选择template的类型为“Empty scope”:

  
这样我们就创建了一个最基本的scope。我们可以点击它,可能没有什么太多的功能。

2)加入对Qt的支持

我们可以看到在项目的“src”目录下有两个目录:apiscope。api目录下的代码主要是为了来访问我们的web service来得到一个json或是xml的数据。在这个项目中,我们并不准备采用这个目录中的client类。有兴趣的开发者可以尝试把自己的client和scope的代码分开。

我们首先打开在“src”中的CMakeLists.txt文件,并加入如下的句子:

add_definitions(-DQT_NO_KEYWORDS)
find_package(Qt5Network REQUIRED)
find_package(Qt5Core REQUIRED)     
find_package(Qt5Xml REQUIRED)      

include_directories(${Qt5Core_INCLUDE_DIRS})    
include_directories(${Qt5Network_INCLUDE_DIRS})
include_directories(${Qt5Xml_INCLUDE_DIRS})    

....

# Build a shared library containing our scope code.
# This will be the actual plugin that is loaded.
add_library(
  scope SHARED
  $<TARGET_OBJECTS:scope-static>
)

qt5_use_modules(scope Core Xml Network) 

# Link against the object library and our external library dependencies
target_link_libraries(
  scope
  ${SCOPE_LDFLAGS}
  ${Boost_LIBRARIES}
)

我们可以看到,我们加入了对Qt Core,XML及Network库的调用。同时,我们也打开"tests/unit/CMakeLists.txt"文件,并加入“qt5_use_modules(scope-unit-tests Core Xml Network)":

# Our test executable.
# It includes the object code from the scope
add_executable(
  scope-unit-tests
  scope/test-scope.cpp
  $<TARGET_OBJECTS:scope-static>
)

# Link against the scope, and all of our test lib dependencies
target_link_libraries(
  scope-unit-tests
  ${GTEST_BOTH_LIBRARIES}
  ${GMOCK_LIBRARIES}
  ${SCOPE_LDFLAGS}
  ${TEST_LDFLAGS}
  ${Boost_LIBRARIES}
)

qt5_use_modules(scope-unit-tests Core Xml Network)

# Register the test with CTest
add_test(
  scope-unit-tests
  scope-unit-tests
)

重新编译项目,如果还有编译错误错误,请修正。

我们同时需要对scope.cpp进行修改。这里我们加入了一个”QCoreApplication”变量。这主要是为了我们能够使用signal/slot机制及生成一个Qt应用。我们来修改scope.h文件,并加QoreApplication的变量app及类的forward申明。我们也必须同时加入一个方法"run"。

class QCoreApplication; // added

namespace scope {
class Scope: public unity::scopes::ScopeBase {
public:
    void start(std::string const&) override;
    void stop() override;
    void run(); // added
    unity::scopes::PreviewQueryBase::UPtr preview(const unity::scopes::Result&,
                                                  const unity::scopes::ActionMetadata&) override;
    unity::scopes::SearchQueryBase::UPtr search(
            unity::scopes::CannedQuery const& q,
            unity::scopes::SearchMetadata const&) override;

protected:
    api::Config::Ptr config_;
    QCoreApplication *app; //added
};

我们同时打开scope.cpp,并做如下的修改:

#include <QCoreApplication> // added

...

void Scope::stop() {
    /* The stop method should release any resources, such as network connections where applicable */
    delete app;
}

void Scope::run()
{
    int zero = 0;
    app = new QCoreApplication(zero, nullptr);
}

这样我们的每个scope其实也是一个Qt应用在运行。重新编译我们的Scope,并在desktop上运行。至此,我们基本对我们的框架加入了基本的Qt支持。在下面的环节中,我们来一步一步地完成我的其它的部分。

3)代码讲解

src/scope/scope.cpp


这个文件定义了一个unity::scopes::ScopeBase的类。它提供了客户端用来和Scope交互的起始接口。
  • 这个类定义了“start", "stop"及"run"来运行scope。绝大多数开发者并不需要修改这个类的大部分实现。在我们的例程中,我们将不做任何的修改
  • 它也同时实现了另外的两个方法:search 和 preview。我们一般来说不需要修改这俩个方法的实现。但是他们所调用的函数在具体的文件中必须实现
注意:我们可以通过研究Scope API的头文件来对API有更多的认识。更多的详细描述,开发者可以在http://developer.ubuntu.com/api/scopes/sdk-14.10/查看。

在上一节中,我们已经基本上完成了对它的改造。对大多数的Scope来说,基本上我们不需要做很多的改变。对于我们的这个Scope,我们想使用cache来缓冲我们的数据,这样可以提高我们Scope的流畅度。这里我们对search函数做如下的修改:

sc::SearchQueryBase::UPtr Scope::search(const sc::CannedQuery &query,
                                        const sc::SearchMetadata &metadata) {

    const QString scopePath = QString::fromStdString(scope_directory());
    const QString cachePath =QString::fromStdString(cache_directory());

    // Boilerplate construction of Query
    return sc::SearchQueryBase::UPtr(new Query(query, metadata, scopePath,cachePath, config_));
}

同时我们也要对Query类中的构造函数进行修改,以便能够进行编译:

Query::Query(const sc::CannedQuery &query, const sc::SearchMetadata &metadata, QString const& scopeDir,
        QString const& cacheDir, Config::Ptr config) :
        sc::SearchQueryBase( query, metadata ),
        m_scopeDir( scopeDir ),
        m_cacheDir( cacheDir ),
        client_(config)
{
    qDebug() << "CacheDir: " << m_cacheDir;
    qDebug() << "ScopeDir " <<  m_scopeDir;

    qDebug() << m_urlRSS;
}

当然,我们要记得在我们的Query头文件中加入数据变量m_scopeDir及m_cacheDir:

class Query: public unity::scopes::SearchQueryBase {

....

private:
    QString m_scopeDir;
    QString m_cacheDir;
    ....
}

重新编译我们的Scope。如果大家此时还有任何的问题的话,可以下载我的源码

bzr branch lp:~liu-xiao-guo/debiantrial/dianpingdept1。

大家可以此为基础向下做练习。

src/scope/query.cpp


这个文件定义了一个unity::scopes::SearchQueryBase类。
这个类用来产生由用户提供的查询字符串而生产的查询结果。这个结果可能是基于json或是xml的。这个类可以用来进行对返回的结果处理并显示。

  • 得到由用户输入的查询字符串
  • 向web services发送请求
  • 生成搜索的结果(根据每个scope不同而不同)
  • 创建搜索结果category(比如不同的layout-- grid/carousel)
  • 根据不同的搜寻结果来绑定不同的category以显示我们所需要的UI
  • 推送不同的category来显示给最终用户
  • 基本上所有的代码集中在"run"方法中。这里我们加入了一个”QCoreApplication”变量。这主要是为了我们能够使用signal/slot机制。
接下来我们对“run”进行修改来达到搜寻的目的。对dianping API的接口来说,我们需要对其输入的URL进行签名。为了方便,我定义了如下的helper方法。

QString Query::getUrl(QString addr, QMap<QString, QString> map) {
    QCryptographicHash generator(QCryptographicHash::Sha1);

    QString temp;
    temp.append(appkey);
    QMapIterator<QString, QString> i(map);
    while (i.hasNext()) {
        i.next();
        // qDebug() << i.key() << ": " << i.value();
        temp.append(i.key()).append(i.value());
    }

    temp.append(secret);

    qDebug() << temp;

    qDebug() << "UTF-8: " << temp.toUtf8();

    generator.addData(temp.toUtf8());
    QString sign = generator.result().toHex().toUpper();

    QString url;
    url.append(addr);
    url.append("appkey=");
    url.append(appkey);

    url.append("&");
    url.append("sign=");
    url.append(sign);

    i.toFront();
    while (i.hasNext()) {
        i.next();
        // qDebug() << i.key() << ": " << i.value();
        url.append("&").append(i.key()).append("=").append(i.value());
    }

    qDebug() << "Final url: " << url;
    return url;
}

这里用到的“appKey”及“secret”是两个定义的QString常量。开发者需要到点评的网站进行申请。这里的addr就是请求的url的前面部分,比如http://api.dianping.com/v1/metadata/get_categories_with_businesses。这里的map实际上是像如下的一组数据,用来存储请求的参数的。我们利用这个方法来得到我们的department的url。如下:

Query::Query(const sc::CannedQuery &query, const sc::SearchMetadata &metadata, QString const& scopeDir,
        QString const& cacheDir, Config::Ptr config) :
        sc::SearchQueryBase( query, metadata ),
        m_scopeDir( scopeDir ),
        m_cacheDir( cacheDir ),
        // m_limit( 0 ),
        client_(config)
{
    qDebug() << "CacheDir: " << m_cacheDir;
    qDebug() << "ScopeDir " <<  m_scopeDir;

    QMap<QString,QString> map;
    map["format"] = "xml";

    m_urlRSS = getUrl(DEPARTMENTS,  map);
    qDebug() << "m_urlRSS: " << m_urlRSS;
}

我们可以把上面的代码加到Query类的构造函数中。这里的DEPARTMENTS定义如下:

const QString DEPARTMENTS = "http://api.dianping.com/v1/metadata/get_categories_with_businesses?";

我们可以通过打印的方式打印出来到Application Output窗口中:

m_urlRSS:  "http://api.dianping.com/v1/metadata/get_categories_with_businesses?appkey=3562917596&sign=4BAF8DD42A36538E17207A1C10F819571B00BF6E&format=xml"

如果我们把得到的url输入到浏览器中,我们会发现:




接下来,我们需要通过网路请求的方式得到上面的xml格式的数据并对它进行解析。为了能够得到我们需要的departments,我们对“run”方法做如下的修改:

void Query::run(sc::SearchReplyProxy const& reply) {
    qDebug() <<  "Run is started .............................!";

    // Create an instance of disk cache and set cache directory
    m_diskCache = new QNetworkDiskCache();
    m_diskCache->setCacheDirectory(m_cacheDir);

    QEventLoop loop;

    QNetworkAccessManager managerDepts;
    QObject::connect(&managerDepts, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
    QObject::connect(&managerDepts, &QNetworkAccessManager::finished,
                     [reply,this](QNetworkReply *msg){
        if( msg->error()!= QNetworkReply::NoError ){
            qWarning() << "failed to retrieve raw data, error:" << msg->error();
            rssError(reply,ERROR_Connection);
            return;
        }
        QByteArray data = msg->readAll();

        // qDebug() << "XML data is: " << data.data();

        QString deptUrl = rssDepartments( data, reply );

        CannedQuery cannedQuery = query();
        QString deptId = qstr(cannedQuery.department_id());
        qDebug() << "department id: " << deptId;

        if (!query().department_id().empty()){ // needs departments support
            qDebug() << "it is not empty xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx!";
            deptUrl = m_depts[deptId];
            qDebug() << "depatUrl: " << deptUrl;
        } else {
            qDebug() << "It is empty ===================================!";
        }

        if ( deptUrl.isEmpty() )
            return;
   });
    managerDepts.setCache(m_diskCache);
    managerDepts.get(QNetworkRequest(QUrl(m_urlRSS)));
    loop.exec();
}

这里其实很简单,我们通过对m_urlRSS的请求,并把得到的结果传给rssDepartments来解释所得到的xml格式的数据。每一个department都有一个叫做department_id来识别。它是一个独有的区别其他的String。rss_Departments的实现如下:

QString Query::rssDepartments( QByteArray &data, unity::scopes::SearchReplyProxy const& reply ) {
    QDomElement docElem;
    QDomDocument xmldoc;
    DepartmentList rss_depts;
    QString firstname = "";

    CannedQuery myquery( SCOPE_NAME );
    myquery.set_department_id( TOP_DEPT_NAME );

    Department::SPtr topDept;

    if ( !xmldoc.setContent(data) ) {
        qWarning()<<"Error importing data";
        return firstname;
    }

    docElem = xmldoc.firstChildElement("results");
    if (docElem.isNull()) {
        qWarning() << "Error in data," << "results" << " not found";
        return firstname;
    }

    docElem = docElem.firstChildElement("categories");
    if ( docElem.isNull() ) {
        qWarning() << "Error in data," << "categories" << " not found";
        return firstname;
    }

    docElem = docElem.firstChildElement("category");

    // Clear the previous departments since the URL may change according to settings
    m_depts.clear();

    int index = 0;
    while ( !docElem.isNull() ) {

        QString category = docElem.attribute("name","");
        qDebug() << "category: " << category;

        if ( !category.isEmpty() ) {
            QString url = getDeptUrl(category);

            QString deptId = QString::number(index);

            if (firstname.isEmpty()) {
                //Create the url here
                firstname = url;
                topDept = move(unity::scopes::Department::create( "",
                                                                  myquery, category.toStdString()));
            } else {
                Department::SPtr aDept = move( unity::scopes::Department::create( deptId.toStdString(),
                                              myquery, category.toStdString() ) );
                rss_depts.insert( rss_depts.end(), aDept );
            }

            m_depts.insert( QString::number(index), url );
            index++;
        }

        docElem = docElem.nextSiblingElement("category");
    }

    // Dump the deparmemts
    QMapIterator<QString, QString> i(m_depts);
    while (i.hasNext()) {
        i.next();
         qDebug() << i.key() << ": " << i.value();
    }

    topDept->set_subdepartments( rss_depts );

     try {
        reply->register_departments( topDept );
    } catch (std::exception const& e) {
        qWarning() << "Error happened: " << e.what();
    }

    return firstname;
}

这个方法通过解析,并生产相应的department。完整的代码可以在

bzr branch lp:~liu-xiao-guo/debiantrial/dianpingdept2

运行我们的Scope。我们可以看到所生产的department。



现在显然我们还看不到任何东西因为我们没有对我们的department进行搜寻。接下来,我们可以按照文章“怎么在Ubuntu Scope中获取location地址信息”来设置获得我们所需要的位置信息。在手机上,我们可以通过网路或GPS来获得我们所需要的位置信息。在电脑上目前还没有支持。通过获得的位置信息,我们通过点评对当地的位置进行搜索。

我们接下来对“run”更进一步地修改来对我们得到的department进行查询:

void Query::run(sc::SearchReplyProxy const& reply) {
    qDebug() <<  "Run is started .............................!";

    // Initialize the scopes
    initScope();

    // Get the current location of the search
    auto metadata = search_metadata();
    if ( metadata.has_location() ) {
        qDebug() << "Location is supported!";
        auto location = metadata.location();

        if ( location.has_altitude()) {
            cerr << "altitude: " << location.altitude() << endl;
            cerr << "longitude: " << location.longitude() << endl;
            cerr << "latitude: " << location.latitude() << endl;
            auto latitude = std::to_string(location.latitude());
            auto longitude = std::to_string(location.longitude());
            m_longitude = QString::fromStdString(longitude);
            m_latitude = QString::fromStdString(latitude);
        }

        if ( m_longitude.isEmpty() ) {
            m_longitude = DEFAULT_LONGITUDE;
        }
        if ( m_latitude.isEmpty() ) {
            m_latitude = DEFAULT_LATITUDE;
        }

        qDebug() << "m_longitude1: " << m_longitude;
        qDebug() << "m_latitude1: " << m_latitude;
    } else {
        qDebug() << "Location is not supported!";
        m_longitude = DEFAULT_LONGITUDE;
        m_latitude = DEFAULT_LATITUDE;
    }

    // Create an instance of disk cache and set cache directory
    m_diskCache = new QNetworkDiskCache();
    m_diskCache->setCacheDirectory(m_cacheDir);

    QEventLoop loop;

    QNetworkAccessManager managerDepts;
    QObject::connect(&managerDepts, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
    QObject::connect(&managerDepts, &QNetworkAccessManager::finished,
                     [reply,this](QNetworkReply *msg){
        if( msg->error()!= QNetworkReply::NoError ){
            qWarning() << "failed to retrieve raw data, error:" << msg->error();
            rssError(reply,ERROR_Connection);
            return;
        }
        QByteArray data = msg->readAll();

        // qDebug() << "XML data is: " << data.data();

        QString deptUrl = rssDepartments( data, reply );

        CannedQuery cannedQuery = query();
        QString deptId = qstr(cannedQuery.department_id());
        qDebug() << "department id: " << deptId;

        if (!query().department_id().empty()){ // needs departments support
            qDebug() << "it is not empty xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx!";
            deptUrl = m_depts[deptId];
            qDebug() << "depatUrl: " << deptUrl;
        } else {
            qDebug() << "It is empty ===================================!";
        }

        if ( deptUrl.isEmpty() )
            return;

        QEventLoop loop;
        QNetworkAccessManager managerRSS;
        QObject::connect( &managerRSS, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
        QObject::connect( &managerRSS, &QNetworkAccessManager::finished,
                         [reply,this](QNetworkReply *msg ){
            if( msg->error() != QNetworkReply::NoError ){
                qWarning() << "failed to retrieve specific dept raw data, error:" <<msg->error();
                rssError( reply, ERROR_Connection );
                return;
            }

            QByteArray data = msg->readAll();
            if( query().query_string().empty() ){
                rssImporter( data, reply, CATEGORY_HEADER );
            } else {
                rssImporter( data, reply, CATEGORY_SEARCH );
            }

        });
        managerRSS.setCache( m_diskCache );
        managerRSS.get( QNetworkRequest( QUrl(deptUrl)) );
        loop.exec();

    });
    managerDepts.setCache(m_diskCache);
    managerDepts.get(QNetworkRequest(QUrl(m_urlRSS)));
    loop.exec();
}

上面我们可以看到我们定义了另外一个QEventLoop。在这里,我们通过对刚才所得到的deptUrl做一个新的请求,并把得到的数据传到rssImporter函数中进行解析。

void Query::rssImporter(QByteArray &data, unity::scopes::SearchReplyProxy const& reply, QString title) {
    QDomElement docElem;
    QDomDocument xmldoc;
    CannedQuery cannedQuery = query();
    QString query = qstr( cannedQuery.query_string() );

    if ( !xmldoc.setContent( data ) ) {
        qWarning()<<"Error importing data";
        return;
    }

    docElem = xmldoc.documentElement();
    //find result
    docElem = docElem.firstChildElement("businesses");
    if (docElem.isNull()) {
        qWarning()<<"Error in data,"<< "result" <<" not found";
        return;
    }

    CategoryRenderer rdrGrid(CR_GRID);
    CategoryRenderer rdrCarousel(CR_CAROUSEL);

    auto carousel = reply->register_category("dianpingcarousel", title.toStdString(), "", rdrCarousel);
    auto grid = reply->register_category("dianpinggrid", "", "", rdrGrid);
    bool isgrid = false;

    docElem = docElem.firstChildElement("business");

    while (!docElem.isNull()) {
        QString business_id = docElem.firstChildElement("business_id").text();
        // qDebug() << "business_id: " << business_id;

        QString name = docElem.firstChildElement("name").text();
        // qDebug() << "name: "  << name;

        // Let's get rid of the test info in the string
        name = removeTestInfo(name);

        QString branch_name = docElem.firstChildElement("branch_name").text();
        // qDebug() << "branch_name: " << branch_name;

        QString address = docElem.firstChildElement("address").text();
        // qDebug() << "address: " << address;

        QString telephone = docElem.firstChildElement("telephone").text();
        // qDebug() << "telephone: " << telephone;

        QString city = docElem.firstChildElement("city").text();
        // qDebug() << "city: " << city;

        QString photo_url = docElem.firstChildElement("photo_url").text();
        // qDebug() << "photo_url: " << photo_url;

        QString s_photo_url = docElem.firstChildElement("s_photo_url").text();
        // qDebug() << "s_photo_url: " << s_photo_url;

        QString rating_s_img_uri = docElem.firstChildElement("rating_s_img_uri").text();
        // qDebug() << "rating_s_img_uri: " << rating_s_img_uri;

        QString business_url = docElem.firstChildElement("business_url").text();
        // qDebug() << "business_url: " << business_url;

        QDomElement deals = docElem.firstChildElement("deals");
        QDomElement deal = deals.firstChildElement("deal");
        QString summary = deal.firstChildElement("description").text();
        // qDebug() << "Summary: " << summary;

        if ( !query.isEmpty() ) {
            if ( !name.contains( query, Qt::CaseInsensitive ) &&
                 !summary.contains( query, Qt::CaseInsensitive ) &&
                 !address.contains( query, Qt::CaseInsensitive ) ) {
                qDebug() << "it is going to be skipped";
                docElem = docElem.nextSiblingElement("business");
                continue;
            } else {
                qDebug() << "it is going to be listed!";
            }
        }

        docElem = docElem.nextSiblingElement("business");

        // for each result
        const std::shared_ptr<const Category> * top;

        if ( isgrid ) {
          top = &grid;
          isgrid = false;
        } else {
          isgrid = true;
          top = &carousel;
        }

        CategorisedResult catres((*top));

        catres.set_uri(business_url.toStdString());
        catres.set_dnd_uri(business_url.toStdString());
        catres.set_title(name.toStdString());
        catres["subtitle"] = address.toStdString();
        catres["summary"] = summary.toStdString();
        catres["fulldesc"] = summary.toStdString();
        catres.set_art(photo_url.toStdString());
        catres["art2"] = s_photo_url.toStdString();
        catres["address"] = Variant(address.toStdString());
        catres["telephone"] = Variant(telephone.toStdString());

        //push the categorized result to the client
        if (!reply->push(catres)) {
            break; // false from push() means search waas cancelled
        }
    }

    qDebug()<<"parsing ended";
}

请注意,我们在上面的代码中使用了如下的代码一对每个department所搜寻的结果再次根据在search输入框中所输入的字符串进行匹配,从而可以更加缩小所显示的内容:

        if ( !query.isEmpty() ) {
            if ( !name.contains( query, Qt::CaseInsensitive ) &&
                 !summary.contains( query, Qt::CaseInsensitive ) &&
                 !address.contains( query, Qt::CaseInsensitive ) ) {
                qDebug() << "it is going to be skipped";
                docElem = docElem.nextSiblingElement("business");
                continue;
            } else {
                qDebug() << "it is going to be listed!";
            }
        }


创建并注册CategoryRenderers

在本例中,我们创建了两个JSON objects. 它们是最原始的字符串,如下所示,它有两个field:template及components。template是用来定义是用什么layout来显示我们所搜索到的结果。这里我们选择的是”grid"及小的card-size。components项可以用来让我们选择预先定义好的field来显示我们所需要的结果。这里我们添加了"title"及“art"。

[html] view plaincopy
  1. std::string CR_GRID = R"(  
  2.     {  
  3.         "schema-version" : 1,  
  4.         "template" : {  
  5.             "category-layout" : "grid",  
  6.             "card-size": "small"  
  7.         },  
  8.         "components" : {  
  9.             "title" : "title",  
  10.             "art" : {  
  11.                 "field": "art",  
  12.                 "aspect-ratio": 1.6,  
  13.                 "fill-mode": "fit"  
  14.             }  
  15.         }  
  16.     }  
  17. )";  

更多关于 CategoryRenderer 类的介绍可以在 docs找到。

我们为每个JSON Object创建了一个CategoryRenderer,并同时向reply object注册:

  1. CategoryRenderer rdrGrid(CR_GRID);  
  2. CategoryRenderer rdrCarousel(CR_CAROUSEL);  
  3.   
  4. QString title = queryString + "美味";  
  5.   
  6. auto carousel = reply->register_category("dianpingcarousel", title.toStdString(), "", rdrCarousel);  
  7. auto grid = reply->register_category("dianpinggrid""""", rdrGrid);  


我们可以把得到的数据通过qDebug的方式进行打印并调试。这里加入的代码很多,你可以在如下的地址下载我的代码:


bzr branch lp:~liu-xiao-guo/debiantrial/dianpingdept3

运行我们的Scope, 我们可以看到如下的画面:

  

大家可以点击图片。我们其实还没完成preview的部分,在下面我们会加入更多的信息来显示我们所得到的信息。我们可以输入一个字符串并使得list的内容更少。比如,我们可以输入”朝阳区“来更进一步地缩小我们的显示的list。

src/dianping-preview.cpp

这个文件定义了一个unity::scopes::PreviewQueryBase类。

这个类定义了一个widget及一个layout来展示我们搜索到的结果。这是一个preview结i果,就像它的名字所描述的那样。

  • 定义在preview时所需要的widget
  • 让widget和搜索到的数据field一一对应起来
  • 定义不同数量的layout列(由屏幕的尺寸来定)
  • 把不同的widget分配到layout中的不同列中
  • 把reply实例显示到layout的widget中

大多数的代码在“run&quot;中实现。跟多关于这个类的介绍可以在http://developer.ubuntu.com/api/scopes/sdk-14.10/previewwidgets/找到。

Preview

Preview需要来生成widget并连接它们的field到CategorisedResult所定义的数据项中。它同时也用来为不同的显示环境(比如屏幕尺寸)生成不同的layout。根据不同的显示环境来生成不同数量的column。

Preview Widgets

这是一组预先定义好的widgets。每个都有一个类型。更据这个类型我们可以生成它们。你可以在这里找到Preview Widget列表及它们提供的的field类型。

这个例子使用了如下的widgets

  • header:它有title及subtitle field
  • image:它有source field有来显示从哪里得到这个art
  • text:它有text field
  • action:用来展示一个有"Open"的按钮。当用户点击时,所包含的URI将被打开

如下是一个例子,它定义了一个叫做“headerId"的PreviewWidget。第二个参数是它的类型"header"。

  1. PreviewWidget w_header("headerId""header");  

我们的代码在如下的地址可以找到:

bzr branch lp:~liu-xiao-guo/debiantrial/dianpingdept4


重新运行我们的Scope,我们可以看到如下的画面。在Preview的画面中,我们可以看到更多的信息,比如电话号码。同时我们可以点击“Open”,并进入到网页看到更多的信息。

  

  


4)加入设置

我们在这里想对dianping Scope做一个设置。比如我想有更多的搜寻的结果,而不是每次只有最多20个。我们可以通过文章“如何在Ubuntu Scope中定义设置变量并读取”来多我们的limit进行设置。首先,在Query类中加入函数:

// The followoing function is used to retrieve the settings for the scope
void Query::initScope()
{
    qDebug() << "Going to retrieve the settings!";

    unity::scopes::VariantMap config = settings();  // The settings method is provided by the base class
    if (config.empty())
        qDebug() << "CONFIG EMPTY!";

    m_limit = config["limit"].get_double();
    cerr << "limit: " << m_limit << endl;
}

并在“run”的开始部分调用它:

void Query::run(sc::SearchReplyProxy const& reply) {
    qDebug() <<  "Run is started .............................!";

    // Initialize the scopes
    initScope();

 ....
}

同时不要忘记在“data”目录下生产相应的.ini文件(/dianping/data/com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini)。其内容如下:

[limit]
type = number
defaultValue = 20
displayName = 搜寻条数

我们也同时需要对“data”目录下的CMakeLists.txt文件进行修改。添加如下的部分到其中:

configure_file(
  "com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini"
  "${CMAKE_BINARY_DIR}/src/com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini"
)

INSTALL(
  FILES "${CMAKE_BINARY_DIR}/src/com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini"
  DESTINATION "${SCOPE_INSTALL_DIR}"
)

我们可以运行一下“Run CMake”,这样,我们在Project中可以看到新添加的.ini文件。重新运行我们的Scope,并在Scope的右上角的设置图标(像有锯齿的 )去尝试改变limit的值,看看效果是什么样的。

  

我们也可以同时修改“data”目录下的logo及icon文件来使得我们的Scope更像一个branded Scope。最终所有的源码可以在如下的地址下载:

bzr branch lp:~liu-xiao-guo/debiantrial/dianpingdept5

大家如果有什么建议,请告诉我。



作者:UbuntuTouch 发表于2014-10-14 16:01:44 原文链接
阅读:112 评论:0 查看评论

Read more
Greg Lutostanski

Agenda

  • Review ACTION points from previous meeting

ACTION: all to review blueprint work items before next weeks meeting

  • U Development
  • Server & Cloud Bugs (caribou)
  • Weekly Updates & Questions for the QA Team (psivaa)
  • Weekly Updates & Questions for the Kernel Team (smb, sforshee, arges)
  • Ubuntu Server Team Events
  • Open Discussion
  • Announce next meeting date, time and chair

Minutes

Final Freeze 9 days out
  • Check on FTBFS packages — seems like there has been good progress
  • Make sure are up to date, if resources are needed now is the time to ask.
  • Release bugs, no high priority ones, juju mirs and openstack bits are being worked.
  • kickinz1 brought up two bcache bugs (LP #1377130 and LP #1377142) to the kernel team for help.
Meeting Actions

None

Agree on next meeting date and time

Next meeting will be on Tuesday, Oct 14th at 16:00 UTC in #ubuntu-meeting.

IRC Log

http://ubottu.com/meetingology/logs/ubuntu-meeting/2014/ubuntu-meeting.2014-10-07-16.03.html

Read more
UbuntuTouch

在本遍文章中,我们来讲解怎么对我们的Ubuntu Scope进行设置。对Scope而言,有些时候我们希望能够使用设置来改变我们的显示,或对我们的搜索进行重新定义。关于更多Scope的开发,请参阅网站:http://developer.ubuntu.com/scopes/

1)首先创建一个最基本的Scope

我们首先打开SDK,并选择“Unity Scope”模版。我们选择一个项目的名称为“settingscope”:



接下来,我们选择“Empty scope”。这样我们就创建了我们的一个最基本的scope了。



2)加入代码来完成设置功能


首先,我们打开项目中的“data”文件夹,并创建一个如下的文件名:

com.ubuntu.developer.liu-xiao-guo.settingscope_settingscope-settings.ini

注意这个文件名和Scope的设置文件

com.ubuntu.developer.liu-xiao-guo.settingscope_settingscope.ini

只有细小的差别。只是在它的后面加上“-settings"即可。记住千万不要改变这个规则。注意这个文件名和项目的名称的不同而不同

为了能够对这个文件进行设置和安装,我们也同时需要对“data”目录下的“CMakeLists.txt”文件加入如下的内容:


configure_file(
  "com.ubuntu.developer.liu-xiao-guo.settingscope_settingscope-settings.ini"
  "${CMAKE_BINARY_DIR}/src/com.ubuntu.developer.liu-xiao-guo.settingscope_settingscope-settings.ini"
)

INSTALL(
  FILES "${CMAKE_BINARY_DIR}/src/com.ubuntu.developer.liu-xiao-guo.settingscope_settingscope-settings.ini"
  DESTINATION "${SCOPE_INSTALL_DIR}"
)

这样我们的设置文件就可以安装到目标中了。下面,我们可以对我们的设置文件进行配置。打开我们的设置文件:

[location]
type = string
defaultValue = London
displayName = Location


[distanceUnit]
type = list
defaultValue = 1
displayName = Distance Unit
displayName[de] = Entfernungseinheit
displayValues = Kilometers;Miles
displayValues[de] = Kilometer;Meilen


[age]
type = number
defaultValue = 23
displayName = Age


[enabled]
type = boolean
defaultValue = true
displayName = Enabled


# Setting without a default value
[color]
type = string
displayName = Color


[limit]
type = number
defaultValue = 20
displayName = 搜寻条数



在这里,我们定义了一些设置的名称,比如“location”。它被定义为“string”,同时它还有一个默认的值“London”。显示的提示为“Location”,当然我们也可以把它修改为“位置”(对中文而言)。


为了能够在应用中访问我们,我们可以修改我们的代码如下:

void Query::run(sc::SearchReplyProxy const& reply) {

    // Read the settings
    initScope();

    try {
        // Start by getting information about the query
        const sc::CannedQuery &query(sc::SearchQueryBase::query());

        // Trim the query string of whitespace
        string query_string = alg::trim_copy(query.query_string());

        Client::ResultList results;
        if (query_string.empty()) {
            // If the string is empty, pick a default
            results = client_.search("default");
        } else {
            // otherwise, use the search string
            results = client_.search(query_string);
        }

        // Register a category
        auto cat = reply->register_category("results", "Results", "",
                                            sc::CategoryRenderer(CATEGORY_TEMPLATE));

        for (const auto &result : results) {
            sc::CategorisedResult res(cat);

            cerr << "it comes here: " << m_limit << endl;

            // We must have a URI
            res.set_uri(result.uri);

            // res.set_title(result.title);
            res.set_title( m_location );
            res["subtitle"] = std::to_string(m_limit);

            // Set the rest of the attributes, art, description, etc
            res.set_art(result.art);
            res["description"] = result.description;

            // Push the result
            if (!reply->push(res)) {
                // If we fail to push, it means the query has been cancelled.
                // So don't continue;
                return;
            }
        }
    } catch (domain_error &e) {
        // Handle exceptions being thrown by the client API
        cerr << e.what() << endl;
        reply->error(current_exception());
    }
}

void Query::initScope()
{
    unity::scopes::VariantMap config = settings();  // The settings method is provided by the base class
    if (config.empty())
        cerr << "CONFIG EMPTY!" << endl;

    m_location = config["location"].get_string();     // Prints "London" unless the user changed the value
    cerr << "location: " << m_location << endl;

    m_limit = config["limit"].get_double();
    cerr << "limit: " << m_limit << endl;
}

这里“initScope”在“Run”中被调用。在InitScope中,我们通过“settings()”来读取设置的值。为了显示的方便,我们在“Run”中,也对读取的值进行简单的显示:

            // res.set_title(result.title);
            res.set_title( m_location );
            res["subtitle"] = std::to_string(m_limit);

我们重新运行我们的Scope,并可以看到如下的图片:

   

我们也可以在我们的Application Output窗口中看到设置的变化:



整个项目的源码可以在如下的地址下载:

bzr branch lp:~liu-xiao-guo/debiantrial/settingscope




作者:UbuntuTouch 发表于2014-10-14 13:12:28 原文链接
阅读:214 评论:0 查看评论

Read more
David Callé

A scope is a tailored view for a set of data, that can use custom layouts, display and branding options. From RSS news feeds to weather data and search engine results, the flexibility of scopes allows you to provide a simple, recognizable and consistent experience with the rest of the OS.

Scopes can also integrate with system-wide user accounts (email, social networks…), split your content into categories and aggregate into each others (for example, a “shopping” scope aggregating results from several store scopes).

unity-8-scopes

In this tutorial, you will learn how to write a scope in C++ for SoundCloud, using the Ubuntu SDK. Read…

Read more