2013年12月29日日曜日

Mac版 Qt 5.2のWebViewはPlugin機能が無効になっていた件

未だに年賀状が倒せていない隠者です。年の瀬も近づいて来ていますが、皆様進捗どうですか?

さて、先週の土曜日に、Qt勉強会 #6 @Tokyoに参加して来ました。Qt 5.2も出たことなので、艦メモをビルドしようとがんばったのですが、なぜかFlashがインストールされていません扱いでした。Mac Book Proではソースからビルドしていたのですが、MBAでは横着して5.2の正式版はパッケージから入れており、Beta版のソースコードも削除した直後で、ビルドのできないSrc(インストーラからinstallできるけど、configureなどは入っていない)はあるものの、デバッグまではできませんでした。

一応、勉強会では時間いっぱい粘って、WebKitのおおよそのソースコード構成は把握してまして、年末休みに突入してから、こちらでもない、あっちでもないとあれこれ彷徨いましたが、何の事はないそもそもPluginが有効になってない事がわかりました。

WebKitは、様々なアーキテクチャや下回り用に、コードの一部をMakefileで切り替えて使うように構成されています。今回問題になったのは、PluginPackageの下回りの切り替え部分でした。

通常、Mac版では

qtwebkit/Source/WebCore/plugins/mac/PluginPackageMac.cpp

が使われるべき所が、

qtwebkit/Source/WebCore/plugins/PluginPackageNone.cpp

のコードが使われていました。このコードは、プラグイン未使用環境用で処理の実装はなく、失敗を返すように実装されています。これでビルドされている限り、Pluginは利用できなくなります。


qtwebkit/Source/WebCore/Target.pri を読むと


 enable?(NETSCAPE_PLUGIN_API) {
    SOURCES += plugins/npapi.cpp
    unix {
        mac {
            SOURCES += \
                plugins/mac/PluginPackageMac.cpp
            OBJECTIVE_SOURCES += \
                platform/text/mac/StringImplMac.mm \
                platform/mac/WebCoreNSStringExtras.mm \
                plugins/mac/PluginViewMac.mm
        } else {
            SOURCES += \
                plugins/qt/PluginPackageQt.cpp \
                plugins/qt/PluginViewQt.cpp
        }
    }
      :
 } else {
     SOURCES += \
         plugins/PluginPackageNone.cpp \
         plugins/PluginViewNone.cpp
 }


となっています。つまり、NETSCAPE_PLUGIN_APIが有効になっていないわけです。
ごそごそっと検索かけると、この辺の定義は以下で行われていました。
qtwebkit/Tools/qmake/mkspecs/features/features.prf


    # Nescape plugins support (NPAPI)
    xlibAvailable() {
        WEBKIT_CONFIG += \
            netscape_plugin_api \
            use_plugin_backend_xlib
        # WebKit2
        WEBKIT_CONFIG += \
            plugin_architecture_x11 \
            plugin_process
    } else: unix|win32-*:!embedded:!wince* {
        WEBKIT_CONFIG += netscape_plugin_api
        # WebKit2
        WEBKIT_CONFIG += plugin_architecture_unsupported
    } else {
        WEBKIT_CONFIG += plugin_architecture_unsupported
    }

Macの場合、xlib扱いにはなっておらず、その次のunix:!embedded:!wince* に引っかかるはずなのですが、ここに入らずにelseに入っていました。

!embedded {
    message("!!!!! embedded? !!!!")
}

というのを追加してビルドするとメッセージが出力されるじゃないですか。どうやら、誰かがembeddedを立てているようです。そのせいで、netscape_plugin_apiがWEBKIT_CONFIGに追加されない状態でビルドされていました。

本来はembeddedを落とすのが正しい対処なのですが、誰が立ててるのか見当たらないというか、grepすると多く出過ぎるので、とりあえず暫定的に以下を追加しました。

} else : mac {
    WEBKIT_CONFIG += netscape_plugin_api
    WEBKIT_CONFIG += plugin_architecture_unsupported
}

そうすると今度は、Source/WebCore/platform/qt/FileSystemQt.cpp がビルドエラーじゃないですか・・・・なんと言う嫌がらせ。

調べてみたら、原因はこれでした。

  • Q_WS_MAC is no longer defined in Qt 5.
そう、no longer definedとされていた、Q_WS_MACが定義されなくなってます。

でも、ソースコードでは、未だに数カ所使われていました。そのうち以下の場所でエラーに成ってくれました。エラーでなかったら気がつかないだろう、それ。



 bool unloadModule(PlatformModule module)
 {
 #if defined(Q_WS_MAC)
     CFRelease(module);
     return true;
 #elif defined(Q_OS_WIN)
     return ::FreeLibrary(module);
 #else

 #ifndef QT_NO_LIBRARY
     if (module->unload()) {
         delete module;
         return true;
     }
 #endif
     return false;
 #endif
 }


というわけで、複数ある、Q_WS_MACをQ_OS_MACに置き換える必要がありました。
変更箇所は多いので、diffで上げておきます。


diff --git a/Source/WebCore/page/qt/EventHandlerQt.cpp b/Source/WebCore/page/qt/EventHandlerQt.cpp
index f45f81d..885fcde 100644
--- a/Source/WebCore/page/qt/EventHandlerQt.cpp
+++ b/Source/WebCore/page/qt/EventHandlerQt.cpp
@@ -52,7 +52,7 @@
 namespace WebCore {
-#if defined(Q_WS_MAC)
+#if defined(Q_OS_MAC)
 const double EventHandler::TextDragDelay = 0.15;
 #else
 const double EventHandler::TextDragDelay = 0.0;

diff --git a/Source/WebCore/platform/FileSystem.h b/Source/WebCore/platform/FileSystem.h
index e1d5b7e..b5fcfa6 100644
--- a/Source/WebCore/platform/FileSystem.h
+++ b/Source/WebCore/platform/FileSystem.h
@@ -48,7 +48,7 @@
 #endif
 #endif
-#if USE(CF) || (PLATFORM(QT) && defined(Q_WS_MAC))
+#if USE(CF) || (PLATFORM(QT) && defined(Q_OS_MAC))
 typedef struct __CFBundle* CFBundleRef;
 typedef const struct __CFData* CFDataRef;
 #endif
@@ -80,7 +80,7 @@ typedef GModule* PlatformModule;
 #elif PLATFORM(EFL)
 typedef Eina_Module* PlatformModule;
 #elif PLATFORM(QT)
-#if defined(Q_WS_MAC)
+#if defined(Q_OS_MAC)
 typedef CFBundleRef PlatformModule;
 #elif !defined(QT_NO_LIBRARY)
 typedef QLibrary* PlatformModule;

diff --git a/Source/WebCore/platform/qt/FileSystemQt.cpp b/Source/WebCore/platform/qt/FileSystemQt.cpp
index b5d0096..1cd8e2c 100644
--- a/Source/WebCore/platform/qt/FileSystemQt.cpp
+++ b/Source/WebCore/platform/qt/FileSystemQt.cpp
@@ -242,7 +242,7 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length)
 bool unloadModule(PlatformModule module)
 {
-#if defined(Q_WS_MAC)
+#if defined(Q_OS_MAC)
     CFRelease(module);
     return true;

diff --git a/Source/WebCore/platform/qt/RenderThemeQStyle.cpp b/Source/WebCore/platform/qt/RenderThemeQStyle.cpp
index f85a75b..81f9278 100644
--- a/Source/WebCore/platform/qt/RenderThemeQStyle.cpp
+++ b/Source/WebCore/platform/qt/RenderThemeQStyle.cpp
@@ -117,7 +117,7 @@ RenderThemeQStyle::RenderThemeQStyle(Page* page)
 {
     int buttonPixelSize = 0;
     m_qStyle->getButtonMetrics(&m_buttonFontFamily, &buttonPixelSize);
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     m_buttonFontPixelSize = buttonPixelSize;
 #endif
 }
@@ -228,7 +228,7 @@ void RenderThemeQStyle::adjustButtonStyle(StyleResolver* styleResolver, RenderSt
     // Ditch the border.
     style->resetBorder();
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     if (style->appearance() == PushButtonPart) {
         // The Mac ports ignore the specified height for <input type="button"> elements
         // unless a border and/or background CSS property is also specified.
@@ -239,7 +239,7 @@ void RenderThemeQStyle::adjustButtonStyle(StyleResolver* styleResolver, RenderSt
     FontDescription fontDescription = style->fontDescription();
     fontDescription.setIsAbsoluteSize(true);
-#ifdef Q_WS_MAC // Use fixed font size and family on Mac (like Safari does)
+#ifdef Q_OS_MAC // Use fixed font size and family on Mac (like Safari does)
     fontDescription.setSpecifiedSize(m_buttonFontPixelSize);
     fontDescription.setComputedSize(m_buttonFontPixelSize);
 #else

まぁ、これでも実はビルドエラーが残っていまして、PluginPackageMac.cppで、他にもエラーが出ました。どうやら、WTF::RetainPtrが一部変更になっているようですが、ヘッダを帰ると影響が読めないので、PluginPackageMac.cppの方を一部修正しました。



diff --git a/Source/WebCore/plugins/mac/PluginPackageMac.cpp b/Source/WebCore/plugins/mac/PluginPackageMac.cpp
index 6b6c417..b40f0d4 100644
--- a/Source/WebCore/plugins/mac/PluginPackageMac.cpp
+++ b/Source/WebCore/plugins/mac/PluginPackageMac.cpp
@@ -138,7 +138,7 @@ bool PluginPackage::fetchInfo()
     if (mimeTypesFileName && CFGetTypeID(mimeTypesFileName.get()) == CFStringGetTypeID()) {
         WTF::RetainPtr<CFStringRef> fileName = (CFStringRef)mimeTypesFileName.get();
-        WTF::RetainPtr<CFStringRef> homeDir = adoptCF(homeDirectoryPath().createCFString());
+        WTF::RetainPtr<CFStringRef> homeDir = homeDirectoryPath().createCFString();
         WTF::RetainPtr<CFStringRef> path = adoptCF(CFStringCreateWithFormat(0, 0, CFSTR("%@/Library/Preferences/%@"), homeDir.get(), fileName.get()));
         WTF::RetainPtr<CFDictionaryRef> plist = readPListFile(path.get(), /*createFile*/ false, m_module);
@@ -255,7 +255,7 @@ bool PluginPackage::load()
         return true;
     }
-    WTF::RetainPtr<CFStringRef> path = adoptCF(m_path.createCFString());
+    WTF::RetainPtr<CFStringRef> path = m_path.createCFString();
     WTF::RetainPtr<CFURLRef> url = adoptCF(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(),
                                                                         kCFURLPOSIXPathStyle, false));


これ、自動テストにプラグインの登録、PluginViewの利用が入っていないのでしょうねぇ。
入っていれば、さすがにこんな大きなデグレード、しかもビルドも通されていない等というお粗末な状態をRelease版として出さないのでしょうけど・・・。

一応、このQt5.2でビルドした艦メモさんは無事に起動して、利用できました。



まぁ、timerでこけるという変な現象は出ましたが、とりあえずはゲームできて、画像付きでつぶやけたから、良しとしましょう。あとは、誰がembeddedを立ててるか調べないとなぁ・・・というあたりで、今日はここまでで、ゲームに戻ってろ号任務をクリアしてきます。


2013年11月5日火曜日

QQuickViewを子にもつQDialogをrootObjectのサイズで固定する方法はないものか・・・

艦コレ絶賛はまり中の隠者です。

先ほど、初めて撃沈を体験しました。改造直前だし、中破だけどイベントボス戦だから、いけるかなと思ったのですけど、がっかりです。最後にスクリーンショットとっておくべきでしたね・・・。

さて、そんな艦コレ専用ブラウザの艦メモですが、先日の記事に載せたように、タイマーダイアログが英語版だとうまくダイアログ内に収まっていませんでした。


このTimer Dialogですが、QDialogの中にQQuickViewを入れてあり、実際のダイアログはQMLで作成されています。Setで呼ばれる一覧等は、先日の日記の伊織さんのコメントから、ダウンロードされている事がわかりました。

で、このQDialogですが、uiファイルでサイズが固定にされていました。
しかし、後からQMLを変更したり、フォントなどの関係で、どうしてもQML部のサイズが事前に固定できない場合が出てきます。

さらにtimerDialog.qmlのrootのRectangleはサイズ指定がありません。内部のColumnに表示されるItemの分だけ自動でサイズが決まるようです。

QQuickViewの内部のコンテンツサイズを取得するにはどうしたらよいのでしょうか。QQuickView::rootObjectで、rootのQQuickItemを取得し、QQuickItem::childrenRect()を取り出せば、子のRectが入手できます。あとは、そのsizeに適度なマージンを入れて、QDialogのsetMinimumSizeとsetMaximumSizeに設定してあげれば、QMLのサイズに合わせてダイアログのサイズを固定できそうです。

void TimerDialog::showEvent(QShowEvent *event)
{
    Q_UNUSED(event);
    if(m_viewer == NULL){
        m_viewer = new QtQuick2ApplicationViewer(windowHandle());
        connect(m_viewer->engine(), SIGNAL(quit()), this, SLOT(closeQml()));

        //C++のデータをQML側へ公開
        m_viewer->rootContext()->setContextProperty("timerData", &m_timerdata);

        //QML設定して表示
        m_viewer->setSource(QUrl("qrc:///qml/KanmusuMemory/timerDialog.qml"));
        m_viewer->show();
        QSize contentSize = m_viewer->rootObject()->childrenRect().toRect().size() + QSize(DIALOG_MARGIN,DIALOG_MARGIN);
        setMinimumSize(contentSize);
        setMaximumSize(contentSize);
    }

}

childrenRectは、RectFを返すので、toRect()でRect化した後、size()を取って、それにマージンを加えています。

Githubには入れておきましたが、まだMacでしか確認していないので、修正をWindowsとLinuxで確認したらpull Requestしてみますか。


2013年10月30日水曜日

艦メモのメモ

先週の金曜日に、うっかり着任してしまい、艦コレはまり中の隠者です。

先日、開発者の @IoriAYANE さんから、Qtユーザー会の方でも開発者募集のメールが出ていた艦メモについて、メモ書きを残しておこうと思います。

まずは、伊織さんからのメッセージの転載。

> こんばんわ
> アプリはさくっと作ってさくっと放流の、いおりです。
> MLをもっとフランクに使っていこうぜって話題があったので。
>
>
> 艦メモという、DMMのゲーム「艦隊これくしょん」を遊ぶためのアプリを作ってます。
> ソースをGithubで公開しているので、もし艦これで遊んでてちょっといじってやるぜ!って
> 提督さんはぜひビルドしてみてください。
> そして、ぜひプルリクエストを送ってください!
> (チート機能は禁止ですよー、マクロとか)
>
> 艦これ
>
> 艦メモの紹介
>
> ビルド方法
>
> 艦メモのビルド方法(Windows編)
>
> 艦メモのビルド方法(Ubuntu編)
>
> 艦メモをビルドしてみた(MacOSX編)
>
> Github

続きまして、ディレクトリツリー。一度ビルドした後で取ったので、余計なものも入っているかもしれませんが。

KanmusuMemory
 - aboutdialog.cpp [いわゆるaboutダイアログ。貢献するとここにアカウント名が表示されるっぽい]
 - aboutdialog.h   [同上]
 - aboutdialog.ui  [同上]
 - cookiejar.cpp   [クッキー保存オブジェクト]
 - cookiejar.h     [同上]
 - favoritemenu.cpp [お気に入り機能、webpageform用かな?]
 - favoritemenu.h  [同上]
 - gamescreen.cpp   [キャプチャ時のGame画面切り出し?]
 - gamescreen.h     [同上]
 - i18n/ [翻訳ファイル - 伊織さんは英語で作ってから翻訳を作るそうです。すばらしぃ
   - qt_ja.qm
   - qt_ja_JP.qm
   - qt_ja_JP.ts
 - imageeditdialog.cpp  [画像編集ダイアログ]
 - imageeditdialog.h    [同上]
 - imageeditdialog.ui   [同上]
 - KanmusuMemory.icns
 - KanmusuMemory.ico
 - KanmusuMemory.pro [Qtのプロジェクトファイル。QtCreator使いはコレをQtCreatorで開く]
 - KanmusuMemory.qrc [Qtのリソース設定ファイル]
 - KanmusuMemory.rc  
 - kanmusumemory_global.h
 - LICENSE          [Apach2ライセンスですね]
 - main.cpp         [main関数はここ]
 - mainwindow.cpp   [main windowです]
 - mainwindow.h     [同上]
 - mainwindow.ui    [同上]
 - memorydialog.cpp [View Memoryダイアログ]
 - memorydialog.h   [同上]
 - memorydialog.ui  [同上]
 - qml/
   - KanmusuMemory/
     - ClipTool.qml
     - GradientEx.qml
     - imageEditDialog.qml
     - ImageEditView.qml
     - images/ 
       - spinner.png
     - js/
       - HttpAccess.js
     - memoryDialog.qml
     - test.qml
     - timerDialog.qml
     - TimerItem.qml
     - TimerSetting.qml
 - qtquick/
    - clipcursor.cpp
    - clipcursor.h
    - operatingsystem.cpp
    - operatingsystem.h
    - qfileasync.cpp
    - qfileasync.h
    - qmlfile.cpp
    - qmlfile.h
    - qtquick.pri
    - qtquick2applicationviewer.cpp
    - qtquick2applicationviewer.h
    - thumbnailprovider.h
    - timerdata.cpp
    - timerdata.h
 - README.md [githubでの説明用]
 - Readme.txt [艦メモについての説明書き]
 - resources/ 
   - alarm.mp3
   - downloaddata/
     - favoritedata.json
     - timerselectguide.json
     - timerselectguide_en.json
   - fav_icon_off.png
   - fav_icon_on.png
   - go_back.png
   - go_forward.png
   - icon.svg
   - KanmusuMemory128.png
   - KanmusuMemory16.png
   - KanmusuMemory256.png
   - KanmusuMemory32.png
   - KanmusuMemory48.png
   - KanmusuMemory512.png
   - KanmusuMemory64.png
   - KanmusuMemory80.png
   - KanmusuMemory96.png
   - mobile_icon.svg
   - mobile_icon_off.png
   - mobile_icon_on.png
   - reload.png
 - scripts/                [主にビルド後の配布パッケージ作成用スクリプト]
   - deb/                  [Ubuntu用debパッケージ作成用]
   - deploymac-dmg.sh      [dmgパッケージ作成用]
   - deploymac.sh          [Macデプロイ用スクリプト]
   - deploymaclibs.txt     [Macで利用するライブラリリスト]
   - deployubuntu.sh       [Ubuntuデプロイ用スクリプト] 
   - KanmusuMemory.sh 
   - macdeployhelper510.sh [deploymac.shから呼び出される]
   - Readme.txt            [Macデプロイスクリプトについて]
   - translate.bat         [lupdate呼び出し簡略化用?]
 - settingsdialog.cpp      [設定ダイアログ]
 - settingsdialog.h        [同上]
 - settingsdialog.ui       [同上]
 - tabwidget.cpp           [WebPageFormにタブを表示する用]
 - tabwidget.h             [同上]
 - timerdialog.cpp         [Timerダイアログ]
 - timerdialog.h           [同上]
 - timerdialog.ui          [同上]
 - tweetdialog.cpp         [ツイート用ダイアログ]
 - tweetdialog.h           [同上]
 - tweetdialog.ui          [同上]
 - twitterinfo_sample.h    [ツイッター用のヘッダサンプル。ビルド手順に従い、コピーと設定が必要]
 - webpageform.cpp         [Web表示ウィジェット - 配布版はまだ入っていない、ブラウザ分割ウィンド]
 - webpageform.h       [同上]
 - webpageform.ui      [同上]
 - webview.cpp             [QWebView拡張。WebPageFormとメインウィンドウで利用]
 - webview.h               [同上]

ほかのOSでも調べてからIssue登録予定だけど、Mac OS X(10.9)で、ビルドした環境での起動(英語表示)だと、以下の表示がウィンドウ内におさまってないらしい。

Timer Dialog

思い出のダイアログも以前は収まってなかったけど、update/merge後に試したら修正済みだったようです。最初にビルドした時は、キャンセルボタンも見えてなかったので、強制終了させてしまったのですけどね。同じ状態が再現した人はウィンドウを拡大すればキャンセルボタンがあるので、それでキャンセルできます。

ところで、Timerダイアログの参考時間は使いやすいのだけど、英語版でもそこだけは日本語なんですよねぇ。さすがにすべて英語訳するのは大変そうですけど。

大雑把にですがコードは読んだので、何か機能思いついたらごそごそ入れていってみたいなと思います。

P.S.
どうやら、翻訳ファイルには艦名が入っている模様。Timer用の翻訳データに見えるけど・・・・。もう少し調査が必要そう。

2013年10月21日月曜日

OSC2013 Tokyo/FallにQtユーザー会として参加してきました

先週は、準備に追われていた隠者です。本日はちょっとお疲れモードです。

10/19(土)と10/20(日)の二日間に渡り、明星大学にてOpen Source Conference 2013 Tokyo/Fallが開催されました。隠者の参加するQtユーザー会もこちらに出典してきました。

展示内容は、実は12日に各自で作りましょうというおおざっぱな流れとなり、1週間で用意したものだったのですが、みんながんばったために、机に置ききれないという事態に。


iPad mini(iOS), iPod touch(iOS), Nexus7 (Android 4.3), Galaxy Nexus(JCROM 4.3), Galaxy Nexus(Ubuntu Phone?), Nexus7(Plasma Active), Armadillo 480(Linux) , Raspberry pi(Linux), あと機種をメモし忘れましたが、Android端末のほか、展示担当者が用意したPC等でQt/QMLを動かして展示していました。

20日の方は、QML本の折戸さんも名古屋から駆けつけてくださり、大切な自分のアカウントでログインして艦メモのデモを見せてくださいました。

「ぜ、絶対に出撃とか、資源使い尽くしたりとかやめてください」といいながら、はらはしつつずっと近くにいらっしゃいましたが・・・。

こちらの艦メモは、Qtに含まれるブラウザの機能で艦コレをプレイしながら、画面のキャプチャー画像をつけてTwitterにつぶやく機能付きの艦メモ専用ブラウザだそうです。実装は、Qt5のQtWidgetsとQMLのハイブリットだそうです。ソースコードもGithubで公開されています。



上記は隠者のAmazon アソシエイトのリンクですので、回避したい方は、Amazonで直接探してみてください。 「Qt Quickではじめるクロスプラットフォーム UIプログラミング」です。なお、達人出版会の方で、電子書籍版も販売されています。お値段的には、電子書籍の方が安いので、おすすめです。




一応、書籍もずらずら並べてみたりして、アピールしてみました。わずかでもQtに興味を持ってくださった方が居たらいいなぁ。

ちなみに、隠者は、勢いで展示用に購入したMacBookAir (2013)で、VMWare Fusionを使ってMac, Linux, Windowsでのデモ動作を展示してました。PCの方の展示は持ち回りで午前中だけだったりしたので、見れなかった人も多いかもしれませんが・・・。



蛇足ですが、20日は、Android ABC 2013a も重なっていて、そちらにも顔を出したかったのですが、片付けの都合もあって、残念ながら裏会のみの参加になってしまいました。裏会を見る限りかなりにぎわっていたので、盛り上がったのかな。

ABCに参加していなかったことと、最近はあまりAndroid側の活動をしていないので、はじっこの方で小さくなっておきました。とりあえず、知らない人も多かったので、フリーで撮って良しなかっしーだけ貼っておきます。


2013年10月16日水曜日

Qt5.2-alpha1 for iOS

先週土曜日にQtユーザー会の勉強会 #4 @東京に参加してきた隠者です。

既に残すところ1週間なのですが、来週の19日、20日に行われるOSC2013 Tokyo/Fall への出し物について 話し合いがもたれました。実は、参加自体は決定していたものの、のんびりまったりがモットー(?)の集まりですので、参加以外はほとんど決定してませんでした。

そんなわけで、分担を決めた結果、OSXやiPhoneユーザーの隠者は、iOS版について調査することになりました。というわけで、ちまちまやってみました。

まず、iOS版を使うには、iOS開発環境が必須となります。

用意するもの

  • XCodeの動作するMac OS X
  • XCodeのインストール
  • XCodeへのCommand Line Toolsのインストール
  • (ハードウェアで動かすには) Apple Developer Programへの登録(有償)
XCodeは、App Storeから無償で入手できます。
Command Line Toolsは、XCodeのメニューからPreference→Downloadsと選択していくと、一覧にあるので、そこからインストールしておいて下さい。


Build手順

現状ではシミュレータ版とハードウェア版でビルド手順が異なります。つまり2種類用意しておかなくてはならないようです。

Simulator版

1. Full Sourceコードの入手(5.2.0 Alpha1)
$ cd ~/
$ git clone git://gitorious.org/qt/qt5.git qt5-ios-sim
$ cd qt5-ios-sim
$ git checkout refs/tags/v5.2.0-alpha1
$ perl init-repository

2. qtbaseのビルド(ビルドは一部のみ)
$ cd ~/qt5-ios-sim/qtbase
$ ./configure -xplatform macx-ios-clang -developer-build -opensource -confirm-license -nomake examples -nomake tests -release -sdk iphonesimulator
$ make -j 4

3. (オプション) QtQuick 1.0用のビルド
$ cd ~/qt5-ios-sim/qtscript
$ ~/qt5-ios-sim/qtbase/bin/qmake
$ make -j 4
$ cd ~/qt5-ios-sim/qtquick1
$ ~/qt5-ios-sim/qtbase/bin/qmake
$ make -j 4

4. simple demoを使って動作検証
$ cd ~/
$ git clone git://github.com/msorvig/qt-ios-demo.git qt-ios-demo-sim
$ cd qt-ios-demo-sim
$ ~/qt5-ios-sim/qtbase/bin/qmake
$ open qt-ios-demo.xcodeproj

IOS版のアプリは、プロジェクトファイルをXCodeで起動してビルド・実行になります。



ちなみに、qtbase/examples/widgets/graphicsview/chip も4と同じようにqmakeしてXCodeで開くと、実行できました。




実機版

わざわざ分けましたけど、ほとんど変わりありません。自分で再現作業するときに楽なので分けただけです。変更点は色を変えています。

ただ、実機版で試すためには、Apple Developer Programを購入して、Appleの認証を受ける必要があります。証明書の取得、App IDの入手、実機の登録なども当然必要で、この辺りの手順は、各種書籍やWebサイトにHow To がありますので、そちらを参照して、まずは簡単なアプリの実機動作を確認しておいてください。

残念ながら、Qtはそこら辺りを省略したり、楽にしたりするものではありません。

1. Full Sourceコードの入手(5.2.0 Alpha1)
$ cd ~/
$ git clone git://gitorious.org/qt/qt5.git qt5-ios
$ cd qt5-ios
$ git checkout refs/tags/v5.2.0-alpha1
$ perl init-repository

2. qtbaseのビルド(ビルドは一部のみ)
$ cd ~/qt5-ios/qtbase
$ ./configure -xplatform macx-ios-clang -developer-build -opensource -confirm-license -nomake examples -nomake tests -release
$ make -j 4

3. (オプション) QtQuick 1.0用のビルド
$ cd ~/qt5-ios/qtscript
$ ~/qt5-ios/qtbase/bin/qmake
$ make -j 4
$ cd ~/qt5-ios/qtquick1
$ ~/qt5-ios/qtbase/bin/qmake
$ make -j 4

4. simple demoを使って動作検証
$ cd ~/
$ git clone git://github.com/msorvig/qt-ios-demo.git
$ cd qt-ios-demo
$ ~/qt5-ios/qtbase/bin/qmake
$ open qt-ios-demo.xcodeproj

これで、XCodeが起動しますので、実機で起動することになります。
iPad miniで動かすと以下のような感じになります。


ついでなので、実機でも4000 chipデモ

これらは、今週末のOSC2013 Tokyoにて展示しておきますので、興味があればお立ち寄り下さいませ。

2013年10月8日火曜日

QPlanetのコード公開そして後悔

ご無沙汰しておりました隠者です。

本当は勉強会参加直後にブログを書く予定だったのですが、ここ最近いろいろと立て続けにあった関係で、ずるずると先延ばしという相変わらずの恥ずかしい状況でしたが、寝付けないのを良いことに朝4時にこそこそ書いていたりします。

さて、名古屋の勉強会ネタにと調べ、そしてQtユーザー会@東京の1,2,3の時間を使ってこそこそやっておりました、QtでPlanetを作ってみよう計画は、一応いろいろと問題を残しながらある程度のところまできました。


本家の画像とスタイルを真似させていただいて、それらしい格好のページを作れるようにはなりました。

ソースコードも、中途半端で使い方とかビルド方法とかのドキュメントが全く用意できていないかなり恥ずかしい感じのコードなのですが、とりあえずgithubに登録しておきました。

そもそもが、Qtを使ってとは名ばかりで、ほとんどXQueryで書いています。
Qtには、QXmlPatternsというモジュールがあり、XQueryが使えるようになっているのですが、どうもいまいち何に使うのか謎が多く、今まで遠くから眺めていました。

でまぁ、ネタ的に利用してみたのですが、コレが使いにくい、使いにくい。
XQueryのコードは何とも気持ち悪い感じ(*個人的な感想です)になってしまいますし、おまけに、QXmlPatternsのよく落ちる事・・・。ちょっと変な事をすると、すぐにSIGSEGV。

bindVariable系は鬼門な感じで、思うように動作せず、結局いびつな感じの処理の仕方になっています。

RSSから必要なデータを抜き出してHTML化するわけなのですが、まぁ、XMLを扱う言語ですので、変換途中に、一部を除いてCharacter Referenceが扱えません。&copy;とか出てくるとエラーになります。おまけに、RSSにはHTMLのタグが参照文字に置換されて配信されていたりするわけですが、この置換をQXmlPatternsの内部で処理できず、Qtのコード側にひっぱってきて変換をかけるという情けない感じになってしまいました。

Qt4.8とQt5.1で試しましたが、どちらも似たような感じで、この落ち方からすると、たぶん利用者は少ないのだろうなぁと感じています。

元Nokiaの某たすくさんには、この無駄な努力をかわいそうな人を見る目で見られるし、泣きながら作業する感じでしたね。

まぁ、隠者は不勉強で、XQuery自体を使うのが初めてだったせいもあるでしょう。がんがん使っている人がきちんと考えて書けば、もっときれいで、もっと効率的で、もっとすっきりと、QXmlPatternsでさっくり動くQuery文が書けるものだと信じたいところですが・・・・まぁ、はやらないのにはそれなりの理由があるんですかね。

無理にQXmlPatternsですべてやるという方針は捨てて、QXmlPatternsで必要な情報を拾い出す事だけに専念して、メインの変換処理は、すべてQtで実装さえすれば、たぶん1日かからずに終わったでしょうねぇ・・・とほほ。

公開しておいてなんですが、実はRSSに相対アドレスが埋め込まれていたりするものがあるので、この変換のためには、HTMLに変換した後で、src属性を修正しなくてはならないのですが、前述の通り、文字参照の扱いがQXmlPatterns内部では処理できず、かなりいただけない状況です。

時間ができたら、やっぱりXQueryをあきらめるという方針で作業してみようかなと思っています。

いや、XQueryでできるだろ!って人は是非直して見てください。

P.S.
いや、QXmlPatternsを直せよ!って心の声は聞かなかった事に・・・。

2013年7月25日木曜日

Qt勉強会#1 @Tokyoに参加してきました

途中まで書きかけ日記を数日放置していた隠者です。
日曜日にはほとんどできていたのですが、装飾とか色づけとか、小さな手直しとか余計な事をちまちまやっていたら、水曜日になってました。内容は、20日(土)に参加してきた勉強会のお話です。

関東Qt勉強会を改めQtユーザー会による「Qt勉強会 #1」に参加してきました。今回は発表はなしの「もくもく会」です。

ちなみに、知らない人のために、もくもく会とは、一つ所にあつまりながら、各自黙々とお勉強をするお勉強会でして。ただ一人だけでやってるわけではなく、困った事があったら、プロジェクターを借りて、こんな事になっちゃったのだけど、誰かなにかしりませんか?と聞く事も出来る会です。

隠者のように独り身で、部屋で勉強し放題という人間ばかりではないので、こういう機会が貴重な方もいらっしゃいますし、普段人前で発表なんて無理って人でも、ちょっとこんな事でっていう話をするだけなら、敷居も低いということで、こういう勉強会も面白いものです。

ちなみに、隠者の内職は、名古屋で話してきたQPlanet(仮)の続きです。
Planetというのは、この隠者のブログを、Qtユーザー会のPlanetというページで転載しているPython製のFeed agregatorというアプリケーションです。qt-users.jpでは、これをcronで動作させているそうです。

RSSやAtom等をかき集めて静的なページを作成してくれるツールなのですが、Slide Shareの埋め込み iframe が反映されなかったり、タスクさんのSilk製のBlogも登録されていないようで、もう少し簡単に登録管理や、反映できるようにQtで作れないものかなぁと思ってしまいまして。よし、QPlanetを作ろうとか思ってみています。

QtのXML Patternsモジュールを使えば、XMLを簡単に取得・加工できる事は、名古屋行きの時に調べてありましたが、RSS 1.0, RSS 2.0, Atom 1.0等の3種類を分別して、変換していくという辺りの途中で止まっていたので、続きをやってきました。
詳細は全部完成したら、Qt勉強会でまた発表したいなと思っていますが、ざっくりと。

XQueryによるFeedリストの取得とSimpleなXMLへの変換


xmlpatternsに含まれるQXmlQueryクラスは、XQueryの実行ができます。
そこで、与えられたFeedのURLリストを巡回して、RSSやAtomを取得していき、静的Webページに載せる必要最小限の共通XMLへと変換します。

ベースとなる記事は、IBMにぴったりの物があります。
RSS と Atom の情報を XQuery を使って集約する
ただし、バージョンの違いか、実行エンジンの違いか、IBMの記事そのままでは動作しませんでした。そこで、自分なりに試行錯誤して、Qtで使えるコードに修正しました。
ただし、隠者は、XQueryはこれが初めてで、正直いってどこまで正しいか不安があります。
ツッコミはコメントのこしていただくか(ただしいつコメントに気がつくか不明)、@hermit4 でつぶやいて下されば直す努力はします。

なお、出来上がるXMLのauthor情報は、著者の情報が無いFeedもありまして、その辺りについてまだ調査中のため、ダミーが入ってたりします。ごめんなさい。

declare namespace atom="http://www.w3.org/2005/Atom";
declare namespace rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare namespace rss="http://purl.org/rss/1.0/";
declare namespace dc="http://purl.org/dc/elements/1.1/";
declare namespace content="http://purl.org/rss/1.0/modules/content/";
declare variable $months := ('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec');

declare function local:convDate($origdate as xs:string) 
{
    let $dateTokens := tokenize($origdate,' ')
    let $month := string(index-of($months,lower-case($dateTokens[3])))
    let $date  := concat($dateTokens[4],'-',
                         if (string-length($month)=1) then concat('0',$month) else $month,
                         '-',$dateTokens[2])
    let $time  := string($dateTokens[5])
    return string(concat($date,'T',$time,'Z'))
};

declare function local:formatDate($orgdate as xs:string) as xs:dateTime
{
    if (matches($orgdate, "^[0-9]{4}-[0-9]{2}-[0-9]{2}T.*")) then 
        xs:dateTime($orgdate)
    else 
        xs:dateTime(local:convDate($orgdate))
};

declare function local:simple-feed($title,$pubdate,$content,$link,$name)
{
    let $convdate := local:formatDate($pubdate)
    return 
        <item>
            <title>{$title}</title>
            <pubdate>{$convdate}</pubdate>
            <link>{$link}</link>
            <content>{$content}</content>
            <author>
                <name>{$name}</name>
            </author>
        </item>
};

declare function local:convert-atom($feeddoc)
{
    for $i in $feeddoc/atom:feed/atom:entry
    return local:simple-feed ($i/atom:title/text(),
                              $i/atom:published/text(),
                              $i/atom:content/text(),
                              $i/atom:link[@rel="" or @rel="alternate"][href],
                              $i/atom:author/atom:name/text())
};

declare function local:convert-rss10($feeddoc)
{
    for $i in $feeddoc/rdf:RDF/rss:item
    return local:simple-feed($i/rss:title/text(),
                             $i/dc:date/text(),
                             $i/content:encoded/text(),
                             $i/rss:link/text(), "aaa")
};

declare function local:convert-rss20($feeddoc)
{
    for $i in $feeddoc/rss/channel/item
    return local:simple-feed($i/title/text(),
                             $i/pubDate/text(),
                             if (count($i/content:encoded) > 0 ) 
                                 then $i/content:encoded/text() 
                                 else $i/description/text() ,
                             $i/link/text(), "bbb")
};

declare function local:convert-feed($url)
{
    let $feeddoc := doc($url)
    return if (count($feeddoc/atom:feed/atom:entry) > 0) then 
        local:convert-atom($feeddoc)
    else if (count($feeddoc/rdf:RDF/rss:item) > 0) then 
        local:convert-rss10($feeddoc)
    else 
        local:convert-rss20($feeddoc)
};

let $merged := for $url in tokenize($feedlist,',')
    return if (doc-available($url)) then local:convert-feed($url)
    else ()

let $merged := for $item in $merged
    order by $item/pubdate descending
    return $item

return
<planet> 
{
    for $item in $merged[days-from-duration(current-dateTime() - xs:dateTime(./pubdate)) <= $recentdays or position() <= $minitems]
        return $item
}
</planet>

いきなり長い上に、見慣れない長いコードですが、これがXQueryというやつです。
Qt部分から設定する変数を使って動作するため、これだけ見るとXQueryを知っている人もさっぱりかもしれません。

Qt部分では、イカのコードで変数を設定します。

    QStringList urls = QStringList() << "http://qt5.jp/rss.qml"
                                     << "http://relog.xii.jp/atom-qt.xml"
                                     << "http://blog.hermit4.info/feeds/posts/default/-/Qt"
                                     << "http://qt-labs.jp/feed";

    QXmlQuery query(QXmlQuery::XQuery10);
    query.bindVariable("feedlist", QVariant(urls.join(",")));
    query.bindVariable("recentdays", QVariant(int(7)));
    query.bindVariable("minitems", QVariant(int(6)));

これにより、Qtのプログラム側から、XQueryで利用する変数が定義できるのです。
いずれ、Qt側でファイルから読み込むコードを書く予定ですが、今の所は、以下の変数の事だけ覚えておいて下さい。

  • $feedlist = URLの","区切り文字列
  • $recentdays = 7
  • $minitems = 6

1. namespaceの定義


まずは、読み込むfeedのXMLが利用しているnamespaceを定義します。

declare namespace atom="http://www.w3.org/2005/Atom";

というやつですね。これがないと、思うようにXMLを取得できません。必要な名前空間をすべて記載していっています。Qt側でも出来るようなのですが、まぁ、よしとしましょう。

2. 関数の定義


XQueryでは、処理を関数化する事ができます。隠者は以下のような関数を作成しています。
  • local:convDate($origdate as xs:string)
    英語表記の日時表現を、YYYY-MM-DDThh:mm:ssの表現に変換する。
    タイムゾーンは現状、GMTしか無かったので、常にZを付けてしまっていて修正が必要
  • local:formatDate($orgdate as xs:string) as xs:dateTime
    文字列の日時表記をxs:DateTime型変数に変換する
  • local:simple-feed($title,$pubdate,$content,$link,$name)
    共通XMLのフォーマット
  • local:convert-atom($feeddoc)
    Atom 1.0のデータをパースして、simple-feedに渡す
  • local:convert-rss10($feeddoc)
    RSS 1.0のデータをパースして(ry
  • local:convert-rss20($feeddoc)
    RSS 2.0のデータをパースして(ry
  • local:convert-feed($url)
    feedがどのフォーマットか判別して変換関数を呼び出す
といった関数を用意しています。


3. XQueryの開始部

では、これか関数を使って変換を実装している箇所が何をしているのか順を追ってみていきます。

let $merged := for $url in tokenize($feedlist,',')
    return if (doc-available($url)) then local:convert-feed($url)
    else ()

$feedlist変数のカンマ区切り文字列を","で文字配列に分けています。その上で、配列の一つずつを取り出して、そのURLが有効なdocを取得できるURLか検証し、有効なものであれば、convert-feedを実行します。実行結果は、$merged変数に格納されます。

まぁ、後はこの中でフォーマットを判別して、記事の情報について必要な所だけ抜き出してsimpleな共通のXML表現<item>リストに変換しているわけです。

let $merged := for $item in $merged
    order by $item/pubdate descending
    return $item

続いて、変換されたSimpleなXMLの中をループしながら、日付降順で並べ変えて$merged変数に入れ直しています。

return
<planet> 
{
    for $item in $merged[days-from-duration(current-dateTime() - xs:dateTime(./pubdate)) <= $recentdays or position() <= $minitems]
        return $item
}
</planet>

最後に、出来上がったXMLから$recentdays以内の記事か、$minitems数に達するまでのfeedを抜き出して、<planet>タグで覆って完了です。

これを実行すると、以下のようなXMLが出来上がるという寸法です。

<planet>
    <item>
        <title>Qt 勉強会 #1 @Tokyo 開催しました</title>
        <pubdate>2013-07-22T09:50:00Z</pubdate>
        <link>http://qt5.jp/qt-meetup-1-tokyo-report.html</link>
        <content>&lt;p&gt;
    2013年7月20日(土曜日)に &lt;a href="http://qt-users.doorkeeper.jp/events/4619" target="_blank"&gt;Qt 勉強会 #1 @Tokyo&lt;/a&gt; を &lt;a href="http://www.ptp.co.jp/" target="_blank"&gt;株式PTP&lt;/a&gt; さんのミーティングルームで開催しました。
&lt;/p&gt;
&lt;p&gt;
    今回からは「関東Qt勉強会」ではなく、「Qt 勉強会」という名前で再スタートしました。
&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p&gt;Qt 勉強会 &lt;a href="http://t.co/1O5ArTQl85"&gt;pic.twitter.com/1O5ArTQl85&lt;/a&gt;&lt;/p&gt;&amp;mdash; Tasuku Suzuki (@task_jp) &lt;a href="https://twitter.com/task_jp/statuses/358440009327587328"&gt;July 20, 2013&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;
    今回はもくもく会ということで、各自好きなことをしながら分からないことがあったら誰かに聞くというゆる〜い感じでした。
&lt;/p&gt;
&lt;p&gt;
    私は、10月/11月に開催される &lt;a href="http://www.qtdeveloperdays.com/" target="_blank"&gt;Qt Developer Days&lt;/a&gt; の発表の応募のための文章を必死に考えていました。
&lt;/p&gt;
&lt;h3&gt;Qt 勉強会 #2 @Tokyo&lt;/h3&gt;
&lt;p&gt;
    &lt;a href="http://qt-users.doorkeeper.jp/events/5014" target="_blank"&gt;Qt 勉強会 #2 @Tokyo&lt;/a&gt; を &lt;a href="http://www.google.com/calendar/event?action=TEMPLATE&amp;text=Qt+%E5%8B%89%E5%BC%B7%E4%BC%9A+%232+%40Tokyo&amp;details=http%3A%2F%2Fqt-users.doorkeeper.jp%2Fevents%2F5014&amp;dates=20130810T040000Z%2F20130810T090000Z&amp;location=&amp;trp=truesprop=website:http%3A%2F%2Fqt-users.doorkeeper.jp%2F&amp;sprop=name:Qt+%E5%8B%89%E5%BC%B7%E4%BC%9A+%28Doorkeeper%29" target="_blank"&gt;2013/08/10 (土)&lt;/a&gt; に開催します。お気軽にお越しください。
&lt;/p&gt;
&lt;p&gt;
    &lt;a href="http://qt-users.doorkeeper.jp/events/5014" class="doorkeeper-registration-widget"&gt;Qt 勉強会 #2 @Tokyo&lt;/a&gt;
    &lt;script src="https://d1dqic1fklzs1z.cloudfront.net/assets/widget.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;/p&gt;
</content>
        <author>
            <name>bbb</name>
        </author>
    </item>
    <item>
        <title>Qt Quickはじめませんか?</title>
        <pubdate>2013-07-16T13:27:10Z</pubdate>
        <link/>
        <content>
        &lt;p&gt;というわけで、Qt Quickの入門書を書きました。8/1発売です。&lt;/p&gt;

&lt;p&gt;「Qt QuickではじめるクロスプラットフォームUIプログラミング」&lt;/p&gt;

&lt;p&gt;と、題してQt Quickでの開発からリリースまでを解説しています。&lt;br /&gt;
Qt Quickで使用するQMLはCやJavaとは少し雰囲気の違う言語なので、どのように組み上げていくかを解説しています。&lt;br /&gt;
Qt Quickのすべての機能を解説しきれませんが、開発に必要な内容はひと通り網羅しています。&lt;/p&gt;

&lt;p&gt;Windows/Linux/Macへの対応方法も必要に応じて解説してます。&lt;br /&gt;
Androidへの対応も進んでいて、紹介しているサンプルをAndroidで動かすこともできます。&lt;/p&gt;

&lt;p&gt;これからますますおもしろくなりそうなQt Quickをはじめませんか?&lt;br /&gt;
ぜひ、本書を手にとって頂ければと思います。&lt;/p&gt;

&lt;p&gt;&lt;iframe src="http://rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=ioriayane-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=4048915126" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;p&gt;(出版を無事迎えれそうなのは、お世話になっている皆様のおかげです。特にO氏、S氏、D氏に感謝です。)&lt;br /&gt;
&lt;/p&gt;
        
    </content>
        <author>
            <name>IoriAYANE</name>
        </author>
    </item>
    <item>
        <title>QtQuick本ついに</title>
        <pubdate>2013-07-16T03:45:00Z</pubdate>
        <link>http://qt5.jp/the-qtquick-book-coming-soon.html</link>
        <content>&lt;blockquote class="twitter-tweet" data-partner="tweetdeck"&gt;&lt;p&gt;発売日を人に聞いて知ったよ、QtQuick本ついに。 &lt;a href="http://t.co/VIzo4zGQAl"&gt;http://t.co/VIzo4zGQAl&lt;/a&gt; via @&lt;/p&gt;&amp;mdash; 理音伊織 (@IoriAYANE) &lt;a href="https://twitter.com/IoriAYANE/statuses/355961176745705472"&gt;July 13, 2013&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;p&gt;
    「&lt;a href="http://ascii.asciimw.jp/books/books/detail/978-4-04-891512-0.shtml" target="_blank"&gt;Qt QuickではじめるクロスプラットフォームUIプログラミング&lt;/a&gt;」が 8/1 に発売されます。
&lt;/p&gt;
&lt;p&gt;
    初心者から上級者まで、Qt Quick に興味がある人すべてにおすすめできる本なので、今すぐ &lt;a href="http://amzn.to/15hhZ64" target="_blank"&gt;Amazon&lt;/a&gt; で予約を!
&lt;/p&gt;</content>
        <author>
            <name>bbb</name>
        </author>
    </item>
    <item>
        <title>名古屋Qt勉強会#9 に参加しました</title>
        <pubdate>2013-07-16T03:30:00Z</pubdate>
        <link>http://qt5.jp/qt-meetup-nagoya-9-report.html</link>
        <content>&lt;p&gt;
    7月13日に &lt;a href="http://xmldo.jp/seminarroom" target="_blank"&gt;ニューキャスト様セミナールーム&lt;/a&gt;  で開催された &lt;a href="http://www.zusaar.com/event/826006" target="_blank"&gt;名古屋Qt勉強会#9 7/13&lt;/a&gt; に参加してきました。
&lt;/p&gt;
&lt;p&gt;
    &lt;a href="http://www.zusaar.com/event/326005" target="_blank"&gt;名古屋Qt勉強会 #5&lt;/a&gt; 以来、約1年ぶり(多分)4回目の参加になります。
&lt;/p&gt;
&lt;h2&gt;&lt;a href="http://www.ustream.tv/recorded/35744325" target="_blank"&gt;Qt for Android&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
    年末にリリース予定の Qt 5.2 で正式対応となる Qt for Android の最新状況についての発表でした。発表は Qt 5.1 RC1 ベースだったのですが、Qt 5.1 の正式版と Qt Creator 2.8.0 の組み合わせでどのくらい状況が改善されているのかが気になるところでした。
&lt;/p&gt;
&lt;p&gt;
    最近お友達に Android 端末をもらったので、何か作ってみようと思います。
&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p&gt;Qt名古屋勉強会の発表資料です。 &lt;a href="http://t.co/6LEhAzVZke"&gt;http://t.co/6LEhAzVZke&lt;/a&gt;&lt;/p&gt;&amp;mdash; 理音伊織 (@IoriAYANE) &lt;a href="https://twitter.com/IoriAYANE/statuses/355930919082786818"&gt;July 13, 2013&lt;/a&gt;&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href="http://www.ustream.tv/recorded/35745459" target="_blank"&gt;RaspberryPiを使ってQtでプレゼン&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p&gt;これからはプレゼンは持ち歩く時代らしい。 Raspberry Piをプロジェクターに直結し電源もUSBから &lt;a href="http://t.co/7VNUPcFp"&gt;http://t.co/7VNUPcFp&lt;/a&gt; &lt;a href="http://t.co/lOnrfm4I"&gt;http://t.co/lOnrfm4I&lt;/a&gt; &lt;a href="http://t.co/CmA4PwC8"&gt;http://t.co/CmA4PwC8&lt;/a&gt;&amp;#10;&lt;a href="https://twitter.com/search?q=%23QtJP&amp;amp;src=hash"&gt;#QtJP&lt;/a&gt;&lt;/p&gt;&amp;mdash; nekomatu (@nekomatu) &lt;a href="https://twitter.com/nekomatu/statuses/279822352756383746"&gt;December 15, 2012&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;
    を実際に自分で試したみたという発表でした。
&lt;/p&gt;
&lt;blockquote class="twitter-tweet"&gt;&lt;p&gt;Qt名古屋勉強会#9の発表資料です。 &lt;a href="http://t.co/4tYr4OhSVY"&gt;http://t.co/4tYr4OhSVY&lt;/a&gt;&amp;#10;&lt;a href="https://twitter.com/search?q=%23qtjp&amp;amp;src=hash"&gt;#qtjp&lt;/a&gt; &lt;a href="https://twitter.com/search?q=%23qtngy&amp;amp;src=hash"&gt;#qtngy&lt;/a&gt;&lt;/p&gt;&amp;mdash; sazus (@sazus) &lt;a href="https://twitter.com/sazus/statuses/355943723919622144"&gt;July 13, 2013&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;
    どうでもいいことなのですが、なるべく短い HDMI ケーブルを用意して、電源もプロジェクターの USB から取って無線のマウスで操作するなどの細かい工夫が必要です。
&lt;/p&gt;
&lt;h2&gt;&lt;a href="http://www.ustream.tv/recorded/35746715" target="_blank"&gt;Qtでウェブサービスを作ろう&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
    &lt;a href="http://silk.qtquick.me/" target="_blank"&gt;QML を使ったシンプルなウェブフレームワーク Silk&lt;/a&gt; と、Silk を使って作られた、「あとで」「後で」で始まる自分のつぶやきを、自動で pocket に保存する簡単なサービス &lt;a href="http://tweet2pocket.com/" target="_blank"&gt;Tweet 2 Pocket (ベータ)&lt;/a&gt; の紹介をしました。
&lt;/p&gt;
&lt;p&gt;
    &lt;script async class="speakerdeck-embed" data-slide="6" data-id="888edd90cd340130e3ce465a590f0cb7" data-ratio="1.33507170795306" src="//speakerdeck.com/assets/embed.js"&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;
    クライアントサイドもサーバーサイドも Qt で書けるようになると楽ですね。
&lt;/p&gt;
&lt;h2&gt;&lt;a href="http://www.ustream.tv/recorded/35747717" target="_blank"&gt;Q Planetに挑戦中&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
    QtXmlPatterns を使って RSS リーダー?を作るという発表でした。QtXmlPatterns はなかなか使わないのでとても勉強になりました。
&lt;/p&gt;
&lt;blockquote class="twitter-tweet" data-partner="tweetdeck"&gt;&lt;p&gt;QPlanet作成に挑戦中 &lt;a href="http://t.co/A2mDf7JC0x"&gt;http://t.co/A2mDf7JC0x&lt;/a&gt; &lt;a href="https://twitter.com/search?q=%23qtjp&amp;amp;src=hash"&gt;#qtjp&lt;/a&gt; &lt;a href="https://twitter.com/search?q=%23qtngy&amp;amp;src=hash"&gt;#qtngy&lt;/a&gt;&lt;/p&gt;&amp;mdash; hermit4(がんばりたい) (@hermit4) &lt;a href="https://twitter.com/hermit4/statuses/355930442567925760"&gt;July 13, 2013&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;</content>
        <author>
            <name>bbb</name>
        </author>
    </item>
    <item>
        <title>Qt 5.1.0 の変更点(補足)</title>
        <pubdate>2013-07-16T02:28:51Z</pubdate>
        <link>http://qt-labs.jp/2013/07/changes-in-qt-5-1-0-additional-notes.html</link>
        <content>&lt;p&gt;&lt;a href="http://qt-labs.jp/2013/07/qt-5-1-0-released.html"&gt;Qt 5.1.0 がリリース&lt;/a&gt; されました。5.1.0 の主な変更点は &lt;a href="http://qt-labs.jp/2013/04/qt-5-1-alpha.html"&gt;5.1.0 アルファ版のリリース記事&lt;/a&gt; に書いていますが、そこにない変更点について補足しておきます。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;</content>
        <author>
            <name>bbb</name>
        </author>
    </item>
    <item>
        <title>名古屋Qt勉強会#9に参加しました</title>
        <pubdate>2013-07-14T14:51:00+09:00</pubdate>
        <link/>
        <content>どうも、さっぱりブログを書かない日々が続いています隠者です。&lt;br /&gt;&lt;br /&gt;今回、3連休ということもあって、ぶらっと3泊4日で名古屋に出かけてきました。&lt;br /&gt;今回の目的は、名古屋Qt勉強会 #9への参加です。&lt;br /&gt;&lt;br /&gt;今回の内容は&lt;br /&gt;&lt;ul&gt;&lt;li&gt;IoriAYANEさんによる「Qt for Android」&lt;/li&gt;&lt;li&gt;sazusさんによる「RaspberryPiを使ってQtでプレゼン」&lt;/li&gt;&lt;li&gt;taskさんによる「Qtでウェブサービスを作ろう」&lt;/li&gt;&lt;/ul&gt;といった内容のあと、せっかくなので、こっそり飛び入りで、「 QPlanetに挑戦中」ってな内容で発表させていただきました。 &lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="" frameborder="0" height="356" marginheight="0" marginwidth="0" mozallowfullscreen="" scrolling="no" src="http://www.slideshare.net/slideshow/embed_code/24195504" style="border-width: 1px 1px 0; border: 1px solid #CCC; margin-bottom: 5px;" webkitallowfullscreen="" width="427"&gt; &lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;内容は、関東Qtユーザー会で話した続きのつもりで、実際こんな物を作ろうとしています。今こんな感じですって発表のつもりでしたけど、元々予定に無かった発表なので、思いっきりはしょって飛ばして話して来ました。&lt;br /&gt;&lt;br /&gt;本当は、名古屋もQtユーザー会として名前とか色々統一しませんか的な話もしなきゃならなかったのですが、名古屋Qt勉強会というと著名人の「ザウルス先生」とか「帽子猫の王」とか「さるぼぼの王」とかいらっしゃいますし、かなりドキドキしながらの参加でしたので、結局話せずじまい。&lt;br /&gt;&lt;br /&gt;本当は、たすくさんが話すだろうなと思って、フォローするつもりで参加したのですが、たすくさんは隠者が話す物だとおもっていたようで。&lt;br /&gt;&lt;br /&gt;なにせ名古屋というと、PF部等で濃いお話を聞かせて下さるまごろく先生とか、隠者自身の職業プログラマとしての最初の師匠も名古屋出身ということで、凄い技術者がごろごろしている所という印象が強かったりします。&lt;br /&gt;&lt;br /&gt;まぁ、でも、懇親会のピザも美味しかったり、色々食べ歩いたり、見て歩いたりと、普段は出不精で旅行らしい旅行なんて凄い久しぶりだったので、堪能しました。&lt;br /&gt;&lt;br /&gt;</content>
        <author>
            <name>hermit4(隠者)</name>
        </author>
    </item>
</planet>

まぁ、正直ここまで書いておいてなんですが、XQueryの構文はいまいち気持ちが悪くてなじめないのですよねぇ。もっとシンプル簡単簡潔に書けないものなのでしょうか・・・。

ちなみに、上記のXQueryをagregate.xqという名前で保存して、それを使って呼び出すお試しコードは以下の通りです。

#include <QCoreApplication>
#include <QTextStream>
#include <QStringList>
#include <QXmlQuery>
#include <QFile>
#include <QDebug>

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);
    QFile agregate("agregate.xq");
    agregate.open(QIODevice::ReadOnly);

    QStringList urls = QStringList() << "http://qt5.jp/rss.qml"
                                     << "http://relog.xii.jp/atom-qt.xml"
                                     << "http://blog.hermit4.info/feeds/posts/default/-/Qt"
                                     << "http://qt-labs.jp/feed";


    QXmlQuery query(QXmlQuery::XQuery10);
    query.bindVariable("feedlist", QVariant(urls.join(",")));
    query.bindVariable("recentdays", QVariant(int(7)));
    query.bindVariable("minitems", QVariant(int(6)));
    query.setQuery(&agregate);
    if(!query.isValid()) {
        qDebug() << "invalid query";
        return 1;
    }
    QString result;
    if(!query.evaluateTo(&result)) {
        qDebug() << "eavaluate error";
    }
    QTextStream(stdout) << result << endl;
    return 0;
}



次回の日記は、上記のXMLをHTMLに変換する辺りを頑張りたいと思います。