使用golang来设计我们的Ubuntu Scope

我们知道golang越来越被很多的开发者来开发应用。go语言也可以用于开发Ubuntu Scope。在今天的教程中,我们将详细介绍如何使用go语言来开发我们的Scope。这对于很多的不太熟悉C/C++的开发者来说,无疑是一个福音。对我来说,这个语言也是比较新的。如果大家想学习golang的话,建议大家阅读“Go
by Example
”。

IDE选择

由于一些原因,目前我们的Ubuntu SDK并没有支持go语言的Scope的开发。可喜的是,我们可以使用Command Line来完成我们的开发。俗话说,好镰不误砍柴功。一个好的工具无疑能帮我们更快更好地开发。我目前使用的编辑器是LiteIDE。这个是转为go语言而设计的IDE,非常简洁而使用,建议大家试用。

安装开发环境

我们首先必须安装golang包

$sudo apt-get install golang

为了说明问题的方便,大家可以先下载我的模版Scope:

$git clone https://gitcafe.com/ubuntu/goscope.git

在自己的Terminal下键入上述的命令,你就可以在你所在的目录下发现一个叫做“goscope”的目录:

[email protected]:~/release/goscope$ ls -l
total 68
-rwxrwxr-x 1 liuxg liuxg 2886  7月  2 12:37 build-click-package.sh
-rwxrwxr-x 1 liuxg liuxg  752  7月  2 12:37 build.sh
-rwxrwxr-x 1 liuxg liuxg 1144  7月  2 12:37 clean.sh
-rw-rw-r-- 1 liuxg liuxg 9835  7月  2 12:37 goscope.go
-rw-rw-r-- 1 liuxg liuxg  329  7月  2 12:37 goscope.ini
-rw-rw-r-- 1 liuxg liuxg  102  7月  2 12:37 goscope-security.json
-rw-rw-r-- 1 liuxg liuxg 8403  7月  2 12:37 icon.jpg
-rw-rw-r-- 1 liuxg liuxg 4851  7月  2 12:37 logo.jpg
-rw-rw-r-- 1 liuxg liuxg  435  7月  2 12:37 manifest.json
-rwxrwxr-x 1 liuxg liuxg 1293  7月  2 12:37 run.sh
-rwxrwxr-x 1 liuxg liuxg 1666  7月  2 12:37 setup-chroot-go.sh
drwxrwxr-x 3 liuxg liuxg 4096  7月  2 12:37 src

从上面的显示中,我们可以看到除了我们期望的goscope.go文件外,我们多了几个脚本来帮我们完成我们的工作。我们可以按照如下的命令把下载后的script变为可以执行的脚本

$chmod +x *.sh

首先,我们来看一下我们的build.sh。

build.sh

#!/bin/bash

#
#  usage: ./build.sh
#         it builds project and produces the armhf click package
#         ./build.sh -d
#		  it builds the project and deploy it to the phone
#  A developer needs to change the armhf names in the following script according tuo your project
#

export GOPATH=`pwd`
go get launchpad.net/go-unityscopes/v2
./setup-chroot-go.sh ubuntu-sdk-15.04 vivid
./build-click-package.sh goscope liu-xiao-guo ubuntu-sdk-15.04 vivid

if [ $# -eq 1 ]
then
	if [ $1 = "-d" ]
	then
		echo "Start to deploy to the phone ..."
		adb push ./goscope.liu-xiao-guo/goscope.liu-xiao-guo_1.0.0_armhf.click /tmp
		adb shell "sudo -iu phablet pkcon --allow-untrusted install-local /tmp/goscope.liu-xiao-guo_1.0.0_armhf.click"
		exit 0
	fi
fi

从这个脚本中,我们可以看到当脚本执行的时候,它执行:

go get launchpad.net/go-unityscopes/v2

这个语句的作用是从上面的地址处下载最新的“go-unityscope”版本2。当你们下载完我的模版后,其实里面已经有一个叫做“src”的目录。里面已经包含了所有的所需要的文件。

当我们加入“-d”选项后,这个script将会自动帮我们把脚本部署到手机中去。记得根据自己的scope名字不同,需要修改部署部分的click包的文件名及目录名字

setup-chroot-go.sh

#!/bin/bash

# Function that executes a given command and compares its return command with a given one.
# In case the expected and the actual return codes are different it exits
# the script.
# Parameters:
#               $1: Command to be executed (string)
#               $2: Expected return code (number), Can be not defined.
function executeCommand()
{
    # gets the command
    CMD=$1
    # sets the return code expected
    # if it's not definedset it to 0
    OK_CODE=$2
    if [ -n $2 ]
    then
        OK_CODE=0
    fi
    # executes the command
    ${CMD}

    # checks if the command was executed successfully
    RET_CODE=$?
    if [ $RET_CODE -ne $OK_CODE ]
    then
        echo "ERROR executing command: \"$CMD\""
        echo "Exiting..."
        exit 1
    fi
}

# ******************************************************************************
# *                                   MAIN                                     *
# ******************************************************************************

if [ $# -ne 2 ]
then
    echo "usage: $0 FRAMEWORK_CHROOT SERIES_CHROOT"
    exit 1
fi

CHROOT=$1
SERIES=$2

sudo click chroot -aarmhf -f$CHROOT -s $SERIES create
sudo click chroot -aarmhf -f$CHROOT -s $SERIES maint apt-get install golang-go golang-go-linux-arm golang-go-dbus-dev golang-go-xdg-dev golang-gocheck-dev golang-gosqlite-dev golang-uuid-dev libgcrypt20-dev:armhf libglib2.0-dev:armhf libwhoopsie-dev:armhf libdbus-1-dev:armhf libnih-dbus-dev:armhf libsqlite3-dev:armhf crossbuild-essential-armhf

echo "Executing go get launchpad.net/go-unityscopes/v2 ...."
GOPATH=`pwd` go get launchpad.net/go-unityscopes/v2
echo "Done."

这个脚本是为了帮我们下载我们所需要的chroots,这样可以进行交叉编译armhf架构从而部署到我们的手机上。如果大家已经安装好自己的Ubuntu SDK,并且已经安装好所需要的armhf chroot,这个script将不会下载任何的东西。

build-click-package.sh

#/bin/bash

# Function that executes a given command and compares its return command with a given one.
# In case the expected and the actual return codes are different it exits
# the script.
# Parameters:
#               $1: Command to be executed (string)
#               $2: Expected return code (number), may be undefined.
function executeCommand()
{
    # gets the command
    CMD=$1
    # sets the return code expected
    # if it's not definedset it to 0
    OK_CODE=$2
    if [ -n $2 ]
    then
        OK_CODE=0
    fi
    # executes the command
    eval ${CMD}

    # checks if the command was executed successfully
    RET_CODE=$?
    if [ $RET_CODE -ne $OK_CODE ]
    then
	echo ""
        echo "ERROR executing command: \"$CMD\""
        echo "Exiting..."
        exit 1
    fi
}

# ******************************************************************************
# *                                   MAIN                                     *
# ******************************************************************************

if [ $# -ne 4 ]
then
    echo "usage: $0 SCOPE_NAME DEVELOPER_NAME FRAMEWORK_CHROOT SERIES_CHROOT"
    exit 1
fi

SCOPE_NAME=$1
DEVELOPER_NAME=$2
CHROOT=$3
SERIES=$4

CURRENT_DIR=`pwd`

FILE_NAME="${SCOPE_NAME}.${DEVELOPER_NAME}"
MANIFEST_NAME="${SCOPE_NAME}.${DEVELOPER_NAME}"

echo -n "Removing ${FILE_NAME} directory... "
executeCommand "rm -rf ./${FILE_NAME}"
echo "Done"

echo -n "Creating clean ${FILE_NAME} directory... "
executeCommand "mkdir -p ${FILE_NAME}/${FILE_NAME}"
echo "Done"

echo -n "Copying scope ini file... "
executeCommand "cp $SCOPE_NAME.ini ${FILE_NAME}/${FILE_NAME}/${FILE_NAME}_${SCOPE_NAME}.ini"
echo "Done"

echo -n "Copying the logo file ... "
executeCommand "cp logo.jpg ${FILE_NAME}/${FILE_NAME}/logo.jpg"
echo "Done"

echo -n "Copying the icon file ... "
executeCommand "cp icon.jpg ${FILE_NAME}/${FILE_NAME}/icon.jpg"
echo "Done"

echo -n "Setting scope name in ini file..."
executeCommand 'sed -i "s/%SCOPE_NAME%/${FILE_NAME}/g" ${FILE_NAME}/${FILE_NAME}/${FILE_NAME}_${SCOPE_NAME}.ini'
echo "Done"

echo -n "Copying scope json files... "
executeCommand "cp *.json ${FILE_NAME}/"
echo "Done"

echo -n "Setting scope name in manifest file..."
executeCommand 'sed -i "s/%SCOPE_NAME%/${MANIFEST_NAME}/g" ${FILE_NAME}/manifest.json'
echo "Done"

echo -n "Cross compiling ${FILE_NAME}..."
executeCommand "click chroot -aarmhf -f$CHROOT -s $SERIES run CGO_ENABLED=1 GOARCH=arm GOARM=7 PKG_CONFIG_LIBDIR=/usr/lib/arm-linux-gnueabihf/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig GOPATH=/usr/share/gocode/:$GOPATH CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ go build -ldflags '-extld=arm-linux-gnueabihf-g++' -o ${FILE_NAME}/${FILE_NAME}/${FILE_NAME}"
echo "Done"

executeCommand "cd ./${FILE_NAME}"

echo -n "Building click package ... "
executeCommand "click build ./"
echo "Done"

executeCommand "cd .."

我们可以通过这个脚本来交叉编译我们的goscope armhf click包。使用时,就像上面的build.sh中展示的那样:

$./build-click-package.sh goscope liu-xiao-guo ubuntu-sdk-15.04 vivid

这里,我们把项目的Scope名,开发者的名字,framework 及Ubuntud的系列号传入即可。

run.sh

#!/bin/bash

#
# This is the script to build and run the scope on desktop environment.
# A developer needs to change the following variable according to your projectt
# 		SCOPE_NAME=goscope
# 		DEVELOPER_NAME=liu-xiao-guo
#
#

function executeCommand()
{
    # gets the command
    CMD=$1
    # sets the return code expected
    # if it's not definedset it to 0
    OK_CODE=$2
    if [ -n $2 ]
    then
        OK_CODE=0
    fi
    # executes the command
    eval ${CMD}

    # checks if the command was executed successfully
    RET_CODE=$?
    if [ $RET_CODE -ne $OK_CODE ]
    then
	echo ""
        echo "ERROR executing command: \"$CMD\""
        echo "Exiting..."
        exit 1
    fi
}

export GOPATH=`pwd`

SCOPE_NAME=goscope
DEVELOPER_NAME=liu-xiao-guo

FILE_NAME="${SCOPE_NAME}.${DEVELOPER_NAME}"

echo -n "Removing ${FILE_NAME} directory... "
executeCommand "rm -rf ./${FILE_NAME}"
echo "Done"

echo -n "Copying scope ini file... "
executeCommand "cp $SCOPE_NAME.ini ${FILE_NAME}_${SCOPE_NAME}.ini"
echo "Done"

echo -n "Setting scope name in ini file..."
executeCommand 'sed -i "s/%SCOPE_NAME%/${FILE_NAME}/g" ${FILE_NAME}_${SCOPE_NAME}.ini'
echo "Done"

echo -n "Building the scope"
executeCommand "go build -o ${FILE_NAME}"

unity-scope-tool ${FILE_NAME}_${SCOPE_NAME}.ini

这个脚本是为了把我们的Scope在Desktop的环境中进行编译,并使用unity-scope-tool来启动我们的Scope:

clean.sh

#!/bin/bash

#
# This file cleans all of the intermediate files produced during the compilation. For each project
# a developer needs to customize the variables
#     SCOPE_NAME
# 	  DEVELOPER_NAME
#
#

function executeCommand()
{
    # gets the command
    CMD=$1
    # sets the return code expected
    # if it's not definedset it to 0
    OK_CODE=$2
    if [ -n $2 ]
    then
        OK_CODE=0
    fi
    # executes the command
    eval ${CMD}

    # checks if the command was executed successfully
    RET_CODE=$?
    if [ $RET_CODE -ne $OK_CODE ]
    then
	echo ""
        echo "ERROR executing command: \"$CMD\""
        echo "Exiting..."
        exit 1
    fi
}

SCOPE_NAME=goscope
DEVELOPER_NAME=liu-xiao-guo

FILE_NAME="${SCOPE_NAME}.${DEVELOPER_NAME}"

echo -n "Removing ${FILE_NAME} directory... "
executeCommand "rm -rf ./${FILE_NAME}"
echo "Done"

echo -n "Removing ${FILE_NAME}_${SCOPE_NAME}.ini ..."
executeCommand "rm -f ${FILE_NAME}_${SCOPE_NAME}.ini"
echo "Done"

echo -n "Removing ${FILE_NAME} ..."
executeCommand "rm -f ${FILE_NAME}"
echo "Done"

echo -n "Removing pkg directory ..."
executeCommand "rm -rf pkg"
echo "Done"

这个脚本是为了我们能够删除我们在编译过程中所产生任何的中间文件。

goscope.go

package main

import (
	"launchpad.net/go-unityscopes/v2"
	"log"
	"encoding/json"
	"net/url"
	"net/http"
)

const searchCategoryYellow = `{
    "schema-version" : 1,
    "template" : {
        "category-layout" : "vertical-journal",
        "card-layout": "horizontal",
        "card-size": "small",
        "collapsed-rows": 0
     },
    "components" : {
        "title" : "title",
        "subtitle":"subtitle",
        "summary":"summary",
        "art":{
        	"field": "art",
       		"aspect-ratio": 1
        }
    }
}`

const searchCategoryTemplate = `{
    "schema-version" : 1,
    "template" : {
        "category-layout" : "carousel",
        "card-size": "large",
        "overlay" : true
    },
    "components" : {
        "title" : "title",
        "art" : {
            "field": "art",
            "aspect-ratio": 1.6,
            "fill-mode": "fit"
        }
    }
}`

// SCOPE ***********************************************************************

var scope_interface scopes.Scope

type MyScope struct {
	BaseURI string
	Key     string
	URI		string
	Dir     string
	base *scopes.ScopeBase
}

type WathereResponse struct {
	WeatherList []Weather `json:"results"`
	Date string `json:"date"`
}

type Weather struct {
	CurrentCity string `json:"currentCity"`
	Pm25 string `json:"pm25"`
	IndexList []Index `json:"index"`
	Weather_datalist []Weather_data `json:"weather_data"`
}

type Index struct {
	Title string `json:"title"`
	Zs string `json:"zs"`
	Tipt string `json:"tipt"`
	Des string `json:"des"`
}

type Weather_data struct {
	Date string `json:"date"`
	DayPictureUrl string `json:"dayPictureUrl"`
	NightPictureUrl string `json:"nightPictureUrl"`
	Weather string `json:"weather"`
	Wind string `json:"wind"`
	Temperature string `json:"temperature"`
}

func (s *MyScope) buildUrl(url2 string, params map[string]string) string {
	query := make(url.Values)
	for key, value := range params {
		query.Set(key, value)
	}
	log.Println(url2 + query.Encode())
	return url2 + query.Encode()
}

// This is used to get results from a webservice
func (s *MyScope) get(url string, params map[string]string, result interface{}) error {
	resp, err := http.Get(s.buildUrl(url, params))
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	return decoder.Decode(result)
}

func (s *MyScope) Search(q *scopes.CannedQuery, metadata *scopes.SearchMetadata, reply *scopes.SearchReply, cancelled <-chan bool) error {
	root_department := s.CreateDepartments(q, metadata, reply)
	reply.RegisterDepartments(root_department)

	query := q.QueryString()
	log.Println(query)	

	// Try to get the city name
	loc := metadata.Location()
	city := loc.City;
	log.Println("city: ", city)

	if query == "" {
		if q.DepartmentID() == "" {
			query = city
		} else {
			query = q.DepartmentID()
		}
	} 

	log.Println("query: ", query)

	var response WathereResponse

	if err := s.get(s.BaseURI, map[string]string{"location": query, "ak": s.Key, "output": "json"}, &response); err != nil {
		return err
	} else {
		log.Println("there is no error!")
	}

	// log.Println(response)
	date := response.Date;
	log.Println("date: ", date)

	var cat *scopes.Category;

	if len(q.QueryString()) == 0 && q.DepartmentID() == "" {
		cat = reply.RegisterCategory("weather", query, "", searchCategoryTemplate)
	} else {
		cat = reply.RegisterCategory("weather", "", "", searchCategoryTemplate)
	}

	for _, data := range response.WeatherList {
		result := scopes.NewCategorisedResult(cat)
		result.SetURI(s.URI)

//		log.Println("Current city:", data.CurrentCity)
//		log.Println("PM25: ", data.Pm25)

		var yellocalendar string = ""
		for _, index := range data.IndexList {
//			log.Println("title: ", index.Title)
//			log.Println("zs: ", index.Zs)
//			log.Println("tipt: ", index.Tipt)
//			log.Println("Des: ", index.Des)

			yellocalendar += index.Title + " "
			yellocalendar += index.Zs + " "
			yellocalendar += index.Tipt + " "
			yellocalendar += index.Des
		}

		for i, weather := range data.Weather_datalist {
//			log.Println("date: ", weather.Date)
//			log.Println("dayPictureUrl: ", weather.DayPictureUrl)
//			log.Println("nightPictureUrl: ", weather.NightPictureUrl)
//			log.Println("weather: ",weather.Weather)
//			log.Println("wind: ", weather.Wind)
//			log.Println("temperature: ", weather.Temperature)

			result.SetTitle(weather.Date)
			result.SetArt(weather.DayPictureUrl)
			result.Set("wind", weather.Wind)
			result.Set("weather", weather.Weather)
			result.Set("temperature", weather.Temperature)

			if err := reply.Push(result); err != nil {
				return err
			}

			result.SetArt(weather.NightPictureUrl)
			if err := reply.Push(result); err != nil {
				return err
			}			

			// Push the yellow calender now
			if i == 0  {
				cat1 := reply.RegisterCategory("weather1", "今天天气", "", searchCategoryYellow)
				result1 := scopes.NewCategorisedResult(cat1)								

				result1.SetURI(s.URI)
				result1.SetTitle(date)
				result1.SetArt(weather.DayPictureUrl)
				result1.Set("subtitle", weather.Weather + " " + weather.Wind + " " +  weather.Temperature + "  PMI: " +  data.Pm25)
				result1.Set("summary", yellocalendar)

				if err := reply.Push(result1); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (s *MyScope) Preview(result *scopes.Result, metadata *scopes.ActionMetadata, reply *scopes.PreviewReply, cancelled <-chan bool) error {
	layout1col := scopes.NewColumnLayout(1)
	layout2col := scopes.NewColumnLayout(2)
	layout3col := scopes.NewColumnLayout(3)

	// Single cyolumn layout
	layout1col.AddColumn("header", "image",  "wind", "weather", "temperature", "summary", "actions")

	// Two column layout
	layout2col.AddColumn("header")
	layout2col.AddColumn("image", "wind", "weather", "temperature", "summary", "actions")

	// Three cokumn layout
	layout3col.AddColumn("header")
	layout3col.AddColumn("image", "wind", "weather", "temperature","summary", "actions")
	layout3col.AddColumn()

	// Register the layouts we just created
	reply.RegisterLayout(layout1col, layout2col, layout3col)

	header := scopes.NewPreviewWidget("header", "header")

	// It has title and a subtitle properties
	header.AddAttributeMapping("title", "title")
	header.AddAttributeMapping("subtitle", "subtitle")

	// Define the image section
	image := scopes.NewPreviewWidget("image", "image")
	// It has a single source property, mapped to the result's art property
	image.AddAttributeMapping("source", "art")

	// Define the summary section
	description := scopes.NewPreviewWidget("summary", "text")
	description.AddAttributeMapping("text", "summary")

	wind := scopes.NewPreviewWidget("wind", "text")
	wind.AddAttributeMapping("text", "wind")

	weather := scopes.NewPreviewWidget("weather", "text")
	weather.AddAttributeMapping("text", "weather")

	temperature := scopes.NewPreviewWidget("temperature", "text")
	temperature.AddAttributeMapping("text", "temperature")

	// build variant map.
	var uri string

	if err := result.Get("uri", &uri); err != nil {
		log.Println(err)
	}

	tuple1 := make(map[string]interface{})
	tuple1["id"] = "open"
	tuple1["label"] = "Open"
	tuple1["uri"] = uri

	actions := scopes.NewPreviewWidget("actions", "actions")
	actions.AddAttributeValue("actions", []interface{}{tuple1})

	var summary string
	if err := result.Get("summary", &summary); err != nil {
		log.Println(err)
	}

	if len(summary) > 0 {
		reply.PushWidgets(header, image, description, actions)
	} else {
		reply.PushWidgets(header, image, wind, weather, temperature, actions)
	}

	return nil
}

func (s *MyScope) SetScopeBase(base *scopes.ScopeBase) {
	s.base = base
}

func (s *MyScope) GetSubdepartments1(query *scopes.CannedQuery,
	metadata *scopes.SearchMetadata,
	reply *scopes.SearchReply) *scopes.Department {
	active_dep, err := scopes.NewDepartment("wuhan", query, "湖北")

	if err == nil {
//		active_dep.SetAlternateLabel("Rock Music Alt")
		department, _ := scopes.NewDepartment("武汉", query, "武汉")
		active_dep.AddSubdepartment(department)

		department2, _ := scopes.NewDepartment("宜昌", query, "宜昌")
		active_dep.AddSubdepartment(department2)

		department3, _ := scopes.NewDepartment("随州", query, "随州")
		active_dep.AddSubdepartment(department3)
	}

	return active_dep
}

func (s *MyScope) GetSubdepartments2(query *scopes.CannedQuery,
	metadata *scopes.SearchMetadata,
	reply *scopes.SearchReply) *scopes.Department {
	active_dep, err := scopes.NewDepartment("changsha", query, "湖南")

	if err == nil {
		department, _ := scopes.NewDepartment("长沙", query, "长沙")
		active_dep.AddSubdepartment(department)

		department2, _ := scopes.NewDepartment("株洲", query, "株洲")
		active_dep.AddSubdepartment(department2)
	}

	return active_dep
}

func (s *MyScope) CreateDepartments(query *scopes.CannedQuery,
	metadata *scopes.SearchMetadata,
	reply *scopes.SearchReply) *scopes.Department {

	department, _ := scopes.NewDepartment("", query, "选择地点")

	dept1 := s.GetSubdepartments1(query, metadata, reply)
	if dept1 != nil {
		department.AddSubdepartment(dept1)
	}

	dept2 := s.GetSubdepartments2(query, metadata, reply)
	if dept2 != nil {
		department.AddSubdepartment(dept2)
	}

	return department
}

// MAIN ************************************************************************

func main() {
	scope := &MyScope {
		BaseURI: "http://api.map.baidu.com/telematics/v3/weather?",
		Key:     "DdzwVcsGMoYpeg5xQlAFrXQt",
		URI: 	 "http://www.weather.com.cn/html/weather/101010100.shtml",
		Dir:     "",
	}

	scope_interface = scope

	if err := scopes.Run(scope); err != nil {
		log.Fatalln(err)
	}
}

这是我们的goscope的go语言程序设计。在这个goscope里,我们使用了百度的天气API来显示天气的数据。整个scope的设计其实和C++的Scope设计比较相似,但是显得更加简洁明了。

我们可以通过如下的命令来把我们的Scope打包并部署到我们的手机上:

$./build.sh -d

如果我们只想得到armhf的click包,我们可以不需要“-d”参数。在手机上的运行情况:

   

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-10 19:22:47

使用golang来设计我们的Ubuntu Scope的相关文章

利用golang和QML来开发Ubuntu应用

在前面的文章"使用golang来设计我们的Ubuntu Scope"中,我们已经介绍了如何利用golang来开发Ubuntu Scope.在今天的文章中,我们来简单介绍一下如何使用golang来开发QML应用.这对于一些熟悉golang语言的,但是不是很熟悉C++的开发这来说,无疑是一个好的选择.虽然我们大多数的QML应用只需要QML加上一些Javascript的脚本即可,但是我们可以使用Qt C++或Go语言来拓展它的功能,来做一些需要计算或特殊功能的部分. 首先,我们来查看我们中国

细细品味Ubuntu Scope中的category renderer模版

当我第一次接触Ubuntu Scope时,我发现这个Category Renderer太神奇.它可以把我们想要的数据很简单而直接的方式呈现给我们.但是由于资料的限制,我们很难知道它最终的显示的形式是什么样的.我们可以在我们的英文的网站的文章"Customization and branding"找到一下信息.但是总觉得意犹未尽,加之没有代码,有时很难理解它到底讲的是什么.在这篇文章中,我们来详细地介绍各种模版,并看看它们的显示格式.详细这对广大的开发者来说非常有用.我们可以修改这些模版

在Ubuntu Scope的模版中利用attributes来显示额外的信息

我在昨天的文章中介绍了我设计的优酷Scope.在今天的练习中,我将对它的模版做一些小的改动,利用模版中的attributes项使得它的显示更加生动. 如果感兴趣的朋友,可以在如下的地址下载最新的youku scope: git clone https://gitcafe.com/ubuntu/youku_keywords.git 首先,我们在query.cpp中对它的模版做如下的改动: query.cpp const std::string NORMAL_TEMPLATE = R"( { &qu

如何在Ubuntu Scope中定义设置变量并读取

在本遍文章中,我们来讲解怎么对我们的Ubuntu Scope进行设置.对Scope而言,有些时候我们希望能够使用设置来改变我们的显示,或对我们的搜索进行重新定义.关于更多Scope的开发,请参阅网站:http://developer.ubuntu.com/scopes/ 1)首先创建一个最基本的Scope 我们首先打开SDK,并选择"Unity Scope"模版.我们选择一个项目的名称为"settingscope": 接下来,我们选择"Empty scop

利用reviews PreviewWidget在Ubuntu Scope中显示评价等级

我们可以利用reviews PreviewWidget来对我们的结果进行显示评价.比如对点评来说,如果是5星的评价,我们可以显示5个星表示客户对商品最高认可. 参阅我们的API的连接,我们可以看到如下的代码: { PreviewWidget w1("summary", "reviews"); w1.add_attribute_value("rating-icon-empty", Variant("file:///tmp/star-emp

如何在Ubuntu Scope中利用Filter来更加精准地提高搜索的质量

在Ubuntu的Scope,目前正在研发一个新的Filter的功能.我们可以在我们的开发者网站找到有关filter的更多的信息.在那里你可以看到一些关于filter的介绍,但是真正地入手去利用它还是有一定的难度的.今天在我们的例程中,我们来具体展示如何利用filter实现更好的搜索.在实际的应用中,比如我们可以通过filter来实现如下的ctrip的Scope:     在上面的中间的图中,我们可以看到"重庆"被选中了,在第二个列中,我们可以使用我们的department来进行从一个城

利用gallery在Ubuntu Scope中显示多张图片

在这篇文章中,我们将介绍如何使用gallery PreviewWidget在Scope Preview中显示多幅图片.更多关于PreviewWidget类型可以参阅API. 首先,我们来下载我们上一节课里讲到的scopetemplate例程: git clone https://gitcafe.com/ubuntu/scopetemplates_video.git 为了能够显示多幅图片,我们对我们的程序做了如下的修改: query.cpp // add an array to show the

Ubuntu Scope简介及开发流程

在这个视频里,我们介绍了在Ubuntu平台上的Scope,并讲解了如何开发Scope. 视频地址:http://v.youku.com/v_show/id_XODQ3MDY5NTQ0.html 视频中的源码: bzr branch lp:~liu-xiao-guo/debiantrial/openmap

利用video PreviewWidget在Ubuntu Scope中播放video

在先前的例程中,我们探讨了如何利用audio PreviewWidget在Scope中播放音乐.在这篇文章中,我们将介绍如何使用videoPreviewWidget来播放一个video. 我们首先来下载我在上一篇文章中的例程: git clone https://gitcafe.com/ubuntu/scopetemplates_audio.git 为了加入video PreviewWidget,我在我们的例程中加入了如下的句子: query.cpp r["videoSource"]