Full Code of penk/terrarium-app for AI

master 564aec92ad5b cached
38 files
61.3 KB
16.4k tokens
7 symbols
1 requests
Download .txt
Repository: penk/terrarium-app
Branch: master
Commit: 564aec92ad5b
Files: 38
Total size: 61.3 KB

Directory structure:
gitextract_mb_qe0pv/

├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── patches/
│   └── expose_loader_errorstring_invokable.patch
├── platform/
│   ├── android/
│   │   └── AndroidManifest.xml
│   ├── arch/
│   │   └── terrarium.desktop
│   ├── ios/
│   │   ├── Images.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── LaunchImage.launchimage/
│   │   │       └── Contents.json
│   │   └── Info.plist
│   ├── mac/
│   │   ├── Info.plist
│   │   └── icon.icns
│   └── ubuntu/
│       ├── debian/
│       │   ├── changelog
│       │   ├── compat
│       │   ├── control
│       │   ├── copyright
│       │   ├── install
│       │   ├── rules
│       │   └── source/
│       │       └── format
│       ├── manifest.json
│       ├── terrarium.desktop
│       └── terrarium.json
├── qml/
│   ├── BottomBar.qml
│   ├── CustomButton.qml
│   ├── HttpServer.qml
│   ├── NaviBar.qml
│   ├── QtWebKit.qml
│   ├── QtWebView.qml
│   ├── assets.qrc
│   └── main.qml
├── src/
│   ├── documenthandler.cpp
│   ├── documenthandler.h
│   ├── main.cpp
│   ├── qmlhighlighter.cpp
│   ├── qmlhighlighter.h
│   ├── quickitemgrabber.cpp
│   └── quickitemgrabber.h
└── terrarium-app.pro

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# C++ objects and libs

*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.dll
*.dylib

# Qt-es

/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.moc
moc_*.cpp
qrc_*.cpp
ui_*.h
Makefile*
*-build-*

# QtCreator

*.autosave
*.swp
*.app
*.dmg
*deployment-settings.json

# Project files
Terrarium
Terrarium.build
Terrarium.xcodeproj
.tmp
terrarium_plugin_import.cpp
terrarium_qml_plugin_import.cpp
qt.conf


================================================
FILE: .gitmodules
================================================
[submodule "qhttpserver"]
	path = qhttpserver
	url = https://github.com/rschroll/qhttpserver.git
        ignore = dirty


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2014-2015 Chen, Ping-Hsun

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
Terrarium - UI Prototyping Tool for Coders
=========

![Doge](http://i.imgur.com/Z0KMIaf.png)

Terrarium is a cross platform QML Playground: the view [renders lively](http://i.imgur.com/MCA641U.gif) as you type in the editor, makes prototyping and experimenting with [QtQuick](http://qt.digia.com/qtquick/) a lot more fun!  

It monitors changes in its `TextEdit`, and triggers the view to reload source from the local http server. If you're looking for a file system watcher implementation, please refer to [QML LiveReload](https://github.com/penk/qml-livereload).

### More details on http://www.terrariumapp.com

## Download

* [iOS](https://itunes.apple.com/us/app/terrarium/id891232736?ls=1&mt=8)
* [Android](https://play.google.com/store/apps/details?id=com.terrariumapp.penk.Terrarium) or [download apk](https://github.com/penk/terrarium-app/releases/download/V1.5/TerrariumApp_1.5.apk)
* [Mac OSX](https://github.com/penk/terrarium-app/releases/download/V1.5/Terrarium-1.5.dmg)
* [Ubuntu Linux](https://github.com/penk/terrarium-app/releases/download/V1.5/terrarium_1.5_amd64.deb)
* [Ubuntu Touch](https://github.com/penk/terrarium-app/releases/download/V1.5/com.ubuntu.developer.penk.terrarium_1.5_armhf.click)

## Build Instructions

    git clone https://github.com/penk/terrarium-app.git
    cd terrarium-app && git submodule init && git submodule update
    qmake && make

## Platform Specific Instructions

### For Arch-Linux
Just go to AUR:
`yaourt -S terrarium-git`

### For Mac OSX/iOS

To add icons to iOS build, first generate and open `Terrarium.xcodeproj`, switch AppIcon to use [Assets Catalog](https://developer.apple.com/library/ios/recipes/xcode_help-image_catalog-1.0/Recipe.html), then replace `Terrarium/Images.xcassets/` directory with `platform/ios/Images.xcassets`.

As for Mac OSX, refer to `macdeployqt` command in `terrarium-app.pro` file.

### For Ubuntu Desktop/Phone

If you're using Qt packages from apt archive instead of [qt-project.org](http://download.qt-project.org/) releases, here's the dependencies:

    sudo apt-get install qt5-qmake qt5-default qtbase5-dev qtdeclarative5-dev build-essential

All `debian/` package information can be found under `platform/ubuntu/` directory, copy it to current path and build the package by:

    cp -r platform/ubuntu/debian .
    cp platform/ubuntu/terrarium.desktop .
    dpkg-buildpackage -b

If you're building click package, execute following command on device (for native compile):

    cp platform/ubuntu/* .
    click build .

And install it

    pkcon --allow-untrusted install-local com.ubuntu.developer.penk.terrarium_1.5_armhf.click

### For Android

First generate your keystore by `keytool`

    keytool -genkey -v -keystore ../TerrariumApp.keystore -alias TerrariumApp -keyalg RSA -keysize 2048 -validity 10000

then

    ~/Qt5.4.1/5.4/android_armv7/bin/qmake
    make
    make install INSTALL_ROOT=../android-terrarium

Build and sign apk by:

    ~/Qt5.4.1/5.4/android_armv7/bin/androiddeployqt --input \
        android-libTerrarium.so-deployment-settings.json \
        --output ../android-terrarium --release --sign ../TerrariumApp.keystore TerrariumApp

## Screenshots

* [Android 5.0.0](http://i.imgur.com/0X6e6wK.png)
* [iOS 8.2](http://i.imgur.com/n2EPoha.png)
* [Mac OSX 10.10.2](http://i.imgur.com/Z0KMIaf.png)
* [Ubuntu Touch](http://i.imgur.com/KShLea0.png)
* [Ubuntu 14.10](http://i.imgur.com/TI2rLIX.png)

## LICENSE

Copyright © 2014-2015 Ping-Hsun (penk) Chen <penkia@gmail.com>  
The source code is, unless otherwise specified, distributed under the terms of the MIT License.

## CREDITS

* [DocumentHandler](https://github.com/khertan/ownNotes) by Benoît HERVIER
* [QMLHighligher](https://gitorious.org/aalperts-automatons/bragi) by Alan Alpert
* [QHttpServer](https://github.com/rschroll/qhttpserver) by Robert Schroll
* [Font Awesome](http://fontawesome.io) by Dave Gandy


================================================
FILE: patches/expose_loader_errorstring_invokable.patch
================================================
--- qtdeclarative-everywhere-src-5.11.1.orig/src/quick/items/qquickloader.cpp
+++ qtdeclarative-everywhere-src-5.11.1/src/quick/items/qquickloader.cpp
@@ -629,6 +629,25 @@
     }
 }
 
+QString QQuickLoader::errorString() const
+{
+   Q_D(const QQuickLoader);
+   QString ret;
+   if(d->component->errors().isEmpty())
+      return ret;
+
+   if (d->component && d->component->isError()) {
+        const QList<QQmlError> errorList = d->component->errors();
+        for (const QQmlError &e : errorList) {
+            ret += e.url().toString() + QLatin1Char(':') +
+              QString::number(e.line()) + QLatin1Char(' ') +
+              e.description() + QLatin1Char('\n');
+        }
+   }
+ 
+   return ret;
+}
+
 void QQuickLoaderIncubator::setInitialState(QObject *o)
 {
     loader->setInitialState(o);
--- qtdeclarative-everywhere-src-5.11.1.orig/src/quick/items/qquickloader_p.h
+++ qtdeclarative-everywhere-src-5.11.1/src/quick/items/qquickloader_p.h
@@ -76,6 +76,7 @@
     void setActive(bool newVal);
 
     Q_INVOKABLE void setSource(QQmlV4Function *);
+    Q_INVOKABLE QString errorString() const;
 
     QUrl source() const;
     void setSource(const QUrl &);


================================================
FILE: platform/android/AndroidManifest.xml
================================================
<?xml version='1.0' encoding='utf-8'?>
<manifest package="com.terrariumapp.penk.Terrarium" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.5" android:versionCode="124" android:installLocation="auto">
    <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
        <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
                  android:name="org.qtproject.qt5.android.bindings.QtActivity"
                  android:label="@string/app_name"
                  android:screenOrientation="unspecified"
                  android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <meta-data android:name="android.app.lib_name" android:value="Terrarium"/>
            <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
            <meta-data android:name="android.app.repository" android:value="default"/>
            <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
            <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
            <!-- Deploy Qt libs as part of package -->
            <meta-data android:name="android.app.bundle_local_qt_libs" android:value="1"/>
            <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
            <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
            <!-- Run with local libs -->
            <meta-data android:name="android.app.use_local_qt_libs" android:value="1"/>
            <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
            <meta-data android:name="android.app.load_local_libs" android:value="plugins/platforms/android/libqtforandroid.so:lib/libQt5QuickParticles.so"/>
            <meta-data android:name="android.app.load_local_jars" android:value="jar/QtAndroid.jar:jar/QtAndroidAccessibility.jar:jar/QtAndroid-bundled.jar:jar/QtAndroidAccessibility-bundled.jar"/>
            <meta-data android:name="android.app.static_init_classes" android:value=""/>
            <!--  Messages maps -->
            <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
            <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
            <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
            <!--  Messages maps -->

            <!-- Splash screen -->
            <!--
            <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
            -->
            <!-- Splash screen -->
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="14"/>
    <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>

    <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
         Remove the comment if you do not require these default permissions. -->
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

        <uses-permission android:name="android.permission.CAMERA" />
        <uses-feature android:name="android.hardware.camera" />
        <uses-feature android:name="android.hardware.camera.autofocus" />

    <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
         Remove the comment if you do not require these default features. -->
        <uses-feature android:glEsVersion="0x00020000" android:required="true" />

</manifest>


================================================
FILE: platform/arch/terrarium.desktop
================================================
[Desktop Entry]
Version=1.5
Name=Terrarium
GenericName=Terrarium
Comment=UI Prototyping Tool for Coders
Type=Application
Icon=terrarium-app.png
Exec=Terrarium
Terminal=false
MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;
X-Ubuntu-Touch=true


================================================
FILE: platform/ios/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon.png",
      "scale" : "1x"
    },
    {
      "size" : "29x29",
      "idiom" : "iphone",
      "filename" : "Icon@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "iphone",
      "filename" : "Icon-40@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "57x57",
      "idiom" : "iphone",
      "filename" : "Icon-1.png",
      "scale" : "1x"
    },
    {
      "size" : "57x57",
      "idiom" : "iphone",
      "filename" : "Icon@2x-1.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-60@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "Icon-60@3x.png",
      "scale" : "3x"
    },
    {
      "size" : "29x29",
      "idiom" : "ipad",
      "filename" : "Icon-Small-1.png",
      "scale" : "1x"
    },
    {
      "size" : "29x29",
      "idiom" : "ipad",
      "filename" : "Icon-Small@2x-1.png",
      "scale" : "2x"
    },
    {
      "size" : "40x40",
      "idiom" : "ipad",
      "filename" : "Icon-40.png",
      "scale" : "1x"
    },
    {
      "size" : "40x40",
      "idiom" : "ipad",
      "filename" : "Icon-40@2x-1.png",
      "scale" : "2x"
    },
    {
      "size" : "50x50",
      "idiom" : "ipad",
      "filename" : "Icon-Small-50.png",
      "scale" : "1x"
    },
    {
      "size" : "50x50",
      "idiom" : "ipad",
      "filename" : "Icon-Small-50@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "72x72",
      "idiom" : "ipad",
      "filename" : "Icon-72.png",
      "scale" : "1x"
    },
    {
      "size" : "72x72",
      "idiom" : "ipad",
      "filename" : "Icon-72@2x.png",
      "scale" : "2x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "Icon-76.png",
      "scale" : "1x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "Icon-76@2x.png",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: platform/ios/Images.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "iphone",
      "scale" : "1x",
      "orientation" : "portrait"
    },
    {
      "idiom" : "iphone",
      "scale" : "2x",
      "orientation" : "portrait"
    },
    {
      "orientation" : "portrait",
      "idiom" : "iphone",
      "filename" : "Default-568h@2x.png",
      "subtype" : "retina4",
      "scale" : "2x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "iphone",
      "minimum-system-version" : "7.0",
      "scale" : "2x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "iphone",
      "filename" : "Default-568h@2x.png",
      "minimum-system-version" : "7.0",
      "subtype" : "retina4",
      "scale" : "2x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "ipad",
      "extent" : "to-status-bar",
      "scale" : "1x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "ipad",
      "extent" : "to-status-bar",
      "scale" : "2x"
    },
    {
      "orientation" : "landscape",
      "idiom" : "ipad",
      "extent" : "to-status-bar",
      "scale" : "1x"
    },
    {
      "orientation" : "landscape",
      "idiom" : "ipad",
      "extent" : "to-status-bar",
      "scale" : "2x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "ipad",
      "minimum-system-version" : "7.0",
      "extent" : "full-screen",
      "scale" : "1x"
    },
    {
      "orientation" : "portrait",
      "idiom" : "ipad",
      "minimum-system-version" : "7.0",
      "extent" : "full-screen",
      "scale" : "2x"
    },
    {
      "orientation" : "landscape",
      "idiom" : "ipad",
      "minimum-system-version" : "7.0",
      "extent" : "full-screen",
      "scale" : "1x"
    },
    {
      "orientation" : "landscape",
      "idiom" : "ipad",
      "minimum-system-version" : "7.0",
      "extent" : "full-screen",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: platform/ios/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDisplayName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundleExecutable</key>
	<string>Terrarium</string>
	<key>CFBundleGetInfoString</key>
	<string>Created by Qt/QMake</string>
	<key>CFBundleIcons</key>
	<dict/>
	<key>CFBundleIcons~ipad</key>
	<dict/>
	<key>CFBundleIdentifier</key>
	<string>com.terrariumapp.${PRODUCT_NAME:rfc1034identifier}</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.5</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1.5.1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>NOTE</key>
	<string>This file was generated by Qt/QMake.</string>
	<key>UIStatusBarHidden</key>
	<true/>
	<key>UIStatusBarHidden~ipad</key>
	<true/>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>
</dict>
</plist>


================================================
FILE: platform/mac/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>Terrarium</string>
	<key>CFBundleIconFile</key>
	<string>icon.icns</string>
	<key>CFBundleIdentifier</key>
	<string>com.terrariumapp.terrarium</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>1.0</string>
	<key>CFBundleName</key>
	<string>Terrarium</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
        <key>NSPrincipalClass</key>
        <string>NSApplication</string>
        <key>NSHighResolutionCapable</key>
        <string>True</string>
</dict>
</plist>


================================================
FILE: platform/ubuntu/debian/changelog
================================================
terrarium (1.5) trusty; urgency=medium

  * Bump version

 -- Ping-Hsun Chen (penk) <penkia@gmail.com>  Mon, 16 Mar 2015 11:10:32 +0800

terrarium (0.1) trusty; urgency=medium

  * Initial commit

 -- Ping-Hsun Chen (penk) <penkia@gmail.com>  Tue, 17 Jun 2014 10:19:26 +0000


================================================
FILE: platform/ubuntu/debian/compat
================================================
8


================================================
FILE: platform/ubuntu/debian/control
================================================
Source: terrarium
Priority: extra
Maintainer: Ping-Hsun Chen (penk) <penkia@gmail.com>
Build-Depends: debhelper (>= 8.0.0),
        qt5-qmake,
        qt5-default,
        qtbase5-dev,
        qtdeclarative5-dev
Standards-Version: 3.9.4
Section: misc
Homepage: http://www.terrariumapp.com

Package: terrarium
Section: misc
Architecture: i386 amd64 armhf
Depends: ${misc:Depends},
 	 ${shlibs:Depends},
 	 qmlscene,
         libqt5sql5-sqlite,
         qtdeclarative5-qtquick2-plugin,
         qtdeclarative5-window-plugin,
Description: Live QML Editor and Viewer
 Terrarium is an open source QML Playgrounds


================================================
FILE: platform/ubuntu/debian/copyright
================================================
Files: *
Copyright: 2014 Ping-Hsun Chen (penk) <penkia@gmail.com>
License: MIT

License: MIT
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 .
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 .
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.


================================================
FILE: platform/ubuntu/debian/install
================================================
terrarium.desktop /usr/share/applications
terrarium-app.png /usr/share/terrarium/
Terrarium /usr/bin/


================================================
FILE: platform/ubuntu/debian/rules
================================================
#!/usr/bin/make -f

# Uncomment this to turn on verbose mode.
# #export DH_VERBOSE=1

%:
	dh $@


================================================
FILE: platform/ubuntu/debian/source/format
================================================
3.0 (native)


================================================
FILE: platform/ubuntu/manifest.json
================================================
{
"description": "UI Prototyping Tool for Coders",
"framework": "ubuntu-sdk-14.04",
"architecture": "armhf",
"hooks": {
"terrarium": {
"apparmor": "terrarium.json",
"desktop": "terrarium.desktop"
}
},
"maintainer": "Penk Chen <penkia@gmail.com>",
"name": "com.ubuntu.developer.penk.terrarium",
"title": "Terrarium",
"version": "1.5"
}


================================================
FILE: platform/ubuntu/terrarium.desktop
================================================
[Desktop Entry]
Version=1.5
Name=Terrarium
GenericName=Terrarium
Comment=UI Prototyping Tool for Coders
Type=Application
Icon=./terrarium-app.png
Exec=./Terrarium
Terminal=false
MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;
X-Ubuntu-Touch=true


================================================
FILE: platform/ubuntu/terrarium.json
================================================
{
"policy_groups": [
"networking",
"sensors",
"webview"
],
"policy_version": 1.1
}


================================================
FILE: qml/BottomBar.qml
================================================
import QtQuick 2.0

Rectangle {
    anchors {
        bottom: parent.bottom
        left: background.left
        margins: 5 * scaleRatio 
    }
    radius: 0.5 * height
    height: 50 * scaleRatio
    width: height 
    gradient: Gradient {
        GradientStop { position: 0.0; color: "#70787F" }
        GradientStop { position: 1.0; color: "#383C40" }
    }
    CustomButton {
        id: viewSwitchButton
        anchors.fill: parent
        //anchors { top: parent.top; left: parent.left }
        anchors.margins: -20 //os_type[platform] == 'ios' ? 12 : 0
        // "\uf121" : fa-code, to editor
        // "\uf0db" : fa-columns, to splitted view
        // "\uf144" : fa-play-circle, to viewer 
        icon.text: 
            if (splitState=='viewer' && root.width * scaleRatio > 600) { "\uf0db" } 
            else if (splitState=='viewer') { "\uf121" } 
            else if (splitState=='editor') { "\uf144" } 
            else if (splitState=='splitted') { "\uf121" }
            else "\uf144"
        defaultColor: "#CAD8E5"
        onClicked: {
            // splitted -> editor -> viewer 
            if (splitState == 'editor')
                splitState = 'viewer';
            else if (splitState == 'viewer' && root.width * scaleRatio > 600)
                splitState = 'splitted';
            else 
                splitState = 'editor';

            view.state = splitState;
        }
    }
}


================================================
FILE: qml/CustomButton.qml
================================================
import QtQuick 2.0

Item {
    id: button
    width: 30 * scaleRatio; height: 30 * scaleRatio; 
    property alias icon: buttonIcon
    property variant defaultColor: "#CAD8E5"
    signal clicked()
    anchors { margins: 10 }
    Text {
        id: buttonIcon
        anchors.centerIn: parent
        font { family: fontAwesome.name; pointSize: os_type[platform] == 'ios' ? 32 : 26 }
        color: defaultColor
        MouseArea {
            anchors.fill: parent
            anchors.margins: -5 * scaleRatio
            onPressed: button.clicked()
        }
    }
}


================================================
FILE: qml/HttpServer.qml
================================================
import QtQuick 2.0
import HttpServer 1.0

HttpServer {
    id: server
    Component.onCompleted: listen(platformIP, 5000)
    onNewRequest: {
        var route = /^\/\?/;
        if (request.url.toString().match(/\/update\?/)) {
            editor.text = decodeURI(request.url.toString().replace(/\/update\?/, "")).replace(/%23/g, '#');
            console.log(editor.text)
            response.writeHead(200)
            response.end()
            reloadView();
        }
        else if ( route.test(request.url) ) {
            response.writeHead(200)
            response.write(editor.text)
            response.end()
        }
        else {
            response.writeHead(404)
            response.end()
        }
    }
}


================================================
FILE: qml/NaviBar.qml
================================================
import QtQuick 2.0
import QtGraphicalEffects 1.0

Rectangle {
    id: navigationBar
    width: parent.width
    height: 44 * scaleRatio
    anchors {
        bottom: parent.bottom
        left: parent.left
    }
    color: "white"

    Rectangle {
        id: repeater
        border.color: "#007edf"
        width: 240 * scaleRatio
        height: 29 * scaleRatio 
        anchors.centerIn: parent 
        radius: 5 
        smooth: true
        visible: false
        Row {
            Rectangle {
                width: 80 *scaleRatio ; height: 29 * scaleRatio
                color: splitState == 'editor' ? "#007edf" : "transparent"
                Text {
                    text: "Editor"
                    color: splitState == 'editor' ? "white" : '#007edf'
                    anchors.centerIn: parent
                    font.pointSize: 15
                }
            }
            Rectangle {
                width: 80 * scaleRatio; height: 29 * scaleRatio
                border.width: 1
                border.color: "#007edf"
                color: splitState == 'splitted' ? "#007edf" : "transparent"
                Text {
                    text: "Split"
                    color: splitState == 'splitted' ? "white" : "#007edf"
                    anchors.centerIn: parent
                    font.pointSize: 15
                }
            }
            Rectangle {
                width: 80 * scaleRatio; height: 29 * scaleRatio
                color: splitState == 'viewer' ? "#007edf" : "transparent"
                Text {
                    text: "Viewer"
                    color: splitState == 'viewer' ? "white" : "#007edf"
                    anchors.centerIn: parent
                    font.pointSize: 15
                }
            }
        }

    }
    Rectangle {
        id: mask
        width: repeater.width
        height: repeater.height
        anchors.fill: repeater
        radius: 5
    }
    OpacityMask {
        visible: (parent.state === 'view')
        anchors.fill: repeater
        source: repeater
        maskSource: mask
    }

    Row {
        anchors.centerIn: parent
        visible: (parent.state === 'view')
        MouseArea {
            width: 80 * scaleRatio
            height: 29 * scaleRatio
            onPressed: splitState = 'editor'
        }
        MouseArea {
            width: 80 * scaleRatio
            height: 29 * scaleRatio
            onPressed: splitState = 'splitted'
        }
        MouseArea {
            width: 80 * scaleRatio
            height: 29 * scaleRatio
            onPressed: splitState = 'viewer'
        }
    }

    Text {
        visible: (parent.state == 'selection')
        anchors {
            left: parent.left
            verticalCenter: parent.verticalCenter
            margins: 10 * scaleRatio 
        }
        font { family: fontAwesome.name; pointSize: 26 }
        text: "\uf057"
        color: 'grey'
        MouseArea {
            anchors.fill: parent
            anchors.margins: -5 * scaleRatio
            onPressed: { 
                navigationBar.state = 'view'; 
                editor.deselect();
            }
        }
    }

    Row {
        anchors.centerIn: parent
        visible: (parent.state === 'selection')
        spacing: 20 * scaleRatio
        Text {
            visible: (editor.selectionStart !== editor.selectionEnd)
            color: "#007edf"
            font.pointSize: 17
            text: "Cut"
            MouseArea {
                anchors.fill: parent
                anchors.margins: -5 * scaleRatio
                onPressed: editor.cut()
            }
        }
        Text {
            visible: (editor.selectionStart !== editor.selectionEnd)
            color: "#007edf"
            font.pointSize: 17
            text: "Copy"
            MouseArea {
                anchors.fill: parent
                anchors.margins: -5 * scaleRatio
                onPressed: { 
                    editor.copy()
                    editor.deselect()
                }
            }
        }
        Text {
            visible: (editor.selectionStart === editor.selectionEnd)
            color: "#007edf"
            font.pointSize: 17
            text: "Select"
            MouseArea {
                anchors.fill: parent
                anchors.margins: -5 * scaleRatio
                onPressed: editor.selectWord()
            }
        }
        Text {
            visible: (editor.selectionStart === editor.selectionEnd)
            color: "#007edf"
            font.pointSize: 17
            text: "Select All"
            MouseArea {
                anchors.fill: parent
                anchors.margins: -5 * scaleRatio
                onPressed: editor.selectAll()
            }
        }
        Text {
            visible: (editor.canPaste === true)
            color: "#007edf"
            font.pointSize: 17
            text: "Paste"
            MouseArea {
                anchors.fill: parent
                anchors.margins: -5 * scaleRatio
                onPressed: editor.paste()
            }
        }
    }

    states: [
        State { 
            name: "view"
        },
        State {
            name: "selection"
        }
    ]
}


================================================
FILE: qml/QtWebKit.qml
================================================
import QtWebKit 3.0
import QtWebKit.experimental 1.0

WebView {}


================================================
FILE: qml/QtWebView.qml
================================================
import QtWebView 1.0

WebView {}


================================================
FILE: qml/assets.qrc
================================================
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/"> 
    <file>main.qml</file>
    <file>HttpServer.qml</file>
    <file>BottomBar.qml</file>
    <file>NaviBar.qml</file>
    <file>CustomButton.qml</file>
    <file>fontawesome-webfont.ttf</file>
    <file>shadow.png</file>
    <file>QtWebKit.qml</file>
    <file>QtWebView.qml</file>
</qresource>
</RCC>


================================================
FILE: qml/main.qml
================================================
import QtQuick 2.0
import QtQuick.Window 2.0

import HttpServer 1.0
import QtQuick.LocalStorage 2.0
import DocumentHandler 1.0

Window {
    id: root
    width: Screen.width
    height: Screen.height
    visible: true
    title: "Terrarium - UI Prototyping Tool for Coders"

    property variant httpServer: {}
    property variant httpd: {}
    property string splitState: (root.width * scaleRatio > 600) ? 'splitted' : 'editor'
    property variant os_type: { '0': 'macx', '1': 'ios', '2': 'android', '3': 'linux', '4': 'default' }
    property variant platformSetting: {
        'ios': { 'lineNumberSpacing': -1, 'lineNumberPadding' : 20, 'defaultFont': 'Courier New' },
        'macx': { 'lineNumberSpacing': -1, 'lineNumberPadding' : 20, 'defaultFont': 'Menlo' },
        'android': { 'lineNumberSpacing': 0, 'lineNumberPadding' : 20, 'defaultFont': 'Droid Sans Mono' },
        'linux': { 'lineNumberSpacing': 0, 'lineNumberPadding' : 20, 'defaultFont': 'Droid Sans Mono' },
        'default': { 'lineNumberSpacing': 0, 'lineNumberPadding' : 20, 'defaultFont': 'Droid Sans Mono' },
    }
    property variant lineNumberPadding: platformSetting[os_type[platform]]['lineNumberPadding']
    property variant lineNumberSpacing: platformSetting[os_type[platform]]['lineNumberSpacing']
    property variant scaleRatio: Screen.pixelDensity.toFixed(0) / 5

    FontLoader { id: fontAwesome; source: "fontawesome-webfont.ttf" }

    Component.onCompleted: {

        // FIXME: workaround for Ubuntu Phone
        if ((scaleRatio < 1) && (os_type[platform]==='linux')) scaleRatio = 2;

        httpServer = Qt.createComponent("HttpServer.qml");
        if (httpServer.status == Component.Ready) {
            httpd = httpServer.createObject(root, {'id': 'httpd'});
            timer.running = true;
        } else {
            console.log('error loading http server')
        }
        var db = getDatabase();
        db.transaction(
                function(tx) {
                    var result = tx.executeSql("SELECT * FROM previous");
                    for (var i=0; i < result.rows.length; i++) {
                        editor.text = result.rows.item(i).editor
                    }
                    tx.executeSql("DROP TABLE IF EXISTS previous");
                }
        );
    }

    Component.onDestruction: {
        saveContent();
    }

    function saveContent() {
        var db = getDatabase();
        db.transaction(
            function(tx) { tx.executeSql('insert into previous values (?);', editor.text); }
        );
    }

    function getDatabase() {
        var db = LocalStorage.openDatabaseSync("terrarium", "1.0", "file saving db", 100000);
        db.transaction(function(tx) {tx.executeSql('CREATE TABLE IF NOT EXISTS previous (editor TEXT)'); });
        return db;
    }

    Timer {
        id: timer
        interval: 500; running: false; repeat: false
        onTriggered: reloadView()
    }

    function reloadView() {
        viewLoader.setSource('http://'+platformIP+':5000/?'+Math.random()) // workaround for cache
    }

    NaviBar {
        state: "view"
        id: navibar
        z: 2
    }

    Item {
        id: view
        state: root.splitState
        width: root.width/2
        height: root.height
        anchors { top: parent.top; right: parent.right; bottom: navibar.top; }
        visible: opacity > 0 ? true : false

        Rectangle {
            color: 'grey'
            visible: errorMessage.text != ""
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.bottom: Screen.top
            anchors.bottomMargin: errorMessage.text == "" ? 0 : -height
            width: parent.width
            height: errorMessage.height

            Behavior on anchors.bottomMargin {
                NumberAnimation { duration: 150; easing.type: Easing.OutQuad }
            }

            Text {
                id: errorMessage
                anchors { left: parent.left; right: parent.right; top: parent.top; margins: 20; topMargin: 10 }
                font.pointSize: 20
                wrapMode: Text.WordWrap
                text: ""
            }
        }

        Loader {
            id: viewLoader
            anchors.fill: parent
            property variant errorLineNumber: 0
            onStatusChanged: {
                if (viewLoader.status == Loader.Error) {
                    errorMessage.text = viewLoader.errorString().replace(/http:\/\/.*:5000\/\?.*?:/g, "Line: ");

                    // restart http server when connection refused
                    var connectionRefused = /Connection refused/;
                    if (connectionRefused.test(errorMessage.text)) {
                        httpd.destroy();
                        httpd = httpServer.createObject(root, {'id': 'httpd'});
                        saveContent();
                        reloadView();
                    }

                    errorLineNumber = errorMessage.text.match(/^Line: (.*?) /)[1];
                    lineNumberRepeater.itemAt(errorLineNumber - 1).bgcolor = 'red'
                } else {
                    errorMessage.text = "";
                    if (errorLineNumber > 0)
                        lineNumberRepeater.itemAt(errorLineNumber - 1).bgcolor = 'transparent'
                }
            }
        }

        states: [
            State {
                name: "splitted"
                PropertyChanges { target: view; width: root.width/2 }
                PropertyChanges { target: view; opacity: 1 }
                PropertyChanges { target: background; width: root.width/2 }
                PropertyChanges { target: background; opacity: 1 }
            },
            State {
                name: "editor"
                PropertyChanges { target: view; width: 0 }
                PropertyChanges { target: view; opacity: 0 }
                PropertyChanges { target: background; width: root.width }
                PropertyChanges { target: background; opacity: 1 }
            },
            State {
                name: "viewer"
                PropertyChanges { target: view; width: root.width }
                PropertyChanges { target: view; opacity: 1 }
                PropertyChanges { target: background; width: 0 }
                PropertyChanges { target: background; opacity: 0 }
            }
        ]
        transitions: [
            Transition {
                to: "*"
                NumberAnimation { target: view; properties: "width"; duration: 300; easing.type: Easing.InOutQuad; }
                NumberAnimation { target: background; properties: "width"; duration: 300; easing.type: Easing.InOutQuad; }
            }
        ]
    }

    Rectangle {
        id: background
        width: root.width/2
        height: root.height
        anchors { top: parent.top; left: parent.left; bottom: navibar.top}
        color: '#1d1f21'
        visible: opacity > 0 ? true : false

        Flickable {
            id: flickable
            anchors { fill: parent; }
            flickableDirection: Flickable.VerticalFlick
            boundsBehavior: Flickable.DragOverBounds
            contentWidth: parent.width
            contentHeight: editor.height
            clip: true

            Column {
                id: lineNumber
                anchors { margins: 20; left: parent.left; top: parent.top }
                spacing: lineNumberSpacing
                Repeater {
                    id: lineNumberRepeater
                    model: editor.lineCount
                    Text {
                        property alias bgcolor: rect.color
                        width: 20
                        text: index + 1
                        color: 'lightgray'
                        font.pointSize: editor.font.pointSize
                        horizontalAlignment: TextEdit.AlignHCenter
                        Rectangle {
                            id: rect
                            color: 'transparent'
                            anchors.fill: parent
                            opacity: 0.5
                        }
                    }
                }
            }

            Rectangle {
                id: editorCurrentLineHighlight
                anchors {
                    left: lineNumber.right
                    margins: lineNumberPadding
                }
                visible: editor.focus
                width: editor.width
                height: editor.cursorRectangle.height
                y: editor.cursorRectangle.y + lineNumberPadding
                color: '#454545'
            }

            TextEdit {
                id: editor
                anchors {
                    margins: lineNumberPadding
                    left: lineNumber.right; right: parent.right; top: parent.top
                }
                wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere;
                renderType: Text.NativeRendering
                onTextChanged: timer.restart();

                onSelectedTextChanged: {
                    if (editor.selectedText === "") {
                        navibar.state = 'view'
                    }
                }
                // FIXME: stupid workaround for indent
                Keys.onPressed: {
                    if (event.key == Qt.Key_BraceRight) {
                        editor.select(0, cursorPosition)
                        var previousContent = editor.selectedText.split(/\r\n|\r|\n/)
                        editor.deselect()
                        var currentLine = previousContent[previousContent.length - 1]
                        var leftBrace = /{/, rightBrace = /}/;
                        if (!leftBrace.test(currentLine)) {
                            editor.remove(cursorPosition, cursorPosition - currentLine.length);
                            currentLine = currentLine.toString().replace(/ {1,4}$/, "");
                            editor.insert(cursorPosition, currentLine);
                        }
                    }
                }
                Keys.onReturnPressed: {
                    editor.select(0, cursorPosition)
                    var previousContent = editor.selectedText.split(/\r\n|\r|\n/)
                    editor.deselect()
                    var currentLine = previousContent[previousContent.length - 1]
                    var leftBrace = /{/, rightBrace = /}/;
                    editor.insert(cursorPosition, "\n")
                    var whitespaceAppend = currentLine.match(new RegExp(/^[ \t]*/))  // whitespace
                    if (leftBrace.test(currentLine)) // indent
                        whitespaceAppend += "    ";
                    editor.insert(cursorPosition, whitespaceAppend)
                }

                // style from Atom dark theme:
                // https://github.com/atom/atom-dark-syntax/blob/master/stylesheets/syntax-variables.less
                color: '#c5c8c6'
                selectionColor: '#0C75BC'
                selectByMouse: true
                font { pointSize: 18; family: platformSetting[os_type[platform]]['defaultFont'] }

                text: documentHandler.text
                inputMethodHints: Qt.ImhNoPredictiveText

                DocumentHandler {
                    id: documentHandler
                    target: editor
                    Component.onCompleted: {
                        documentHandler.text = "import QtQuick 2.0\n\nRectangle { \n    color: '#FEEB75'" +
                            "\n    Text { \n        anchors.centerIn: parent" +
                            "\n        text: 'Hello, World!' \n    } \n}"
                    }
                }

                // FIXME: add selection / copy / paste popup
                MouseArea {
                    id: handler
                    // FIXME: disable on desktop
                    enabled: os_type[platform] != 'macx'
                    anchors.fill: parent
                    propagateComposedEvents: true
                    onPressed: {
                        editor.cursorPosition = parent.positionAt(mouse.x, mouse.y);
                        editor.focus = true
                        navibar.state = 'view'
                        Qt.inputMethod.show();
                    }
                    onPressAndHold: {
                        navibar.state = 'selection'
                        Qt.inputMethod.hide();
                    }
                    onDoubleClicked: {
                        editor.selectWord()
                        navibar.state = 'selection'
                    }
                }
            } // end of editor

        }
    }
    Image {
        fillMode: Image.TileHorizontally
        source: "shadow.png"
        width: navibar.width
        anchors.bottom: navibar.top
        height: 6
    }
}


================================================
FILE: src/documenthandler.cpp
================================================
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Quick Controls module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "documenthandler.h"

#include <QtGui/QTextDocument>
#include <QtGui/QTextCursor>
#include <QtGui/QFontDatabase>
#include <QtCore/QFileInfo>

DocumentHandler::DocumentHandler()
    : m_target(0)
    , m_doc(0)
    , m_cursorPosition(-1)
    , m_selectionStart(0)
    , m_selectionEnd(0)
    , m_highlighter(0)
{
}

void DocumentHandler::setTarget(QQuickItem *target)
{
    m_doc = 0;
    m_highlighter = 0;
    m_target = target;
    if (!m_target)
        return;

    QVariant doc = m_target->property("textDocument");
    if (doc.canConvert<QQuickTextDocument*>()) {
        QQuickTextDocument *qqdoc = doc.value<QQuickTextDocument*>();
        if (qqdoc) {
            m_doc = qqdoc->textDocument();
            m_highlighter = new QMLHighlighter(m_doc);
            //m_highlighter = new Highlighter(m_doc);
        }
    }
    emit targetChanged();
}

void DocumentHandler::setText(const QString &arg)
{
    if (m_text != arg) {
        m_text = arg;
        emit textChanged();
    }
}

QString DocumentHandler::text() const
{
    return m_text;
}

void DocumentHandler::setCursorPosition(int position)
{
    if (position == m_cursorPosition)
        return;

    m_cursorPosition = position;

    reset();
}

void DocumentHandler::reset()
{

}


QTextCursor DocumentHandler::textCursor() const
{
    QTextCursor cursor = QTextCursor(m_doc);
    if (m_selectionStart != m_selectionEnd) {
        cursor.setPosition(m_selectionStart);
        cursor.setPosition(m_selectionEnd, QTextCursor::KeepAnchor);
    } else {
        cursor.setPosition(m_cursorPosition);
    }
    return cursor;
}

void DocumentHandler::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
    QTextCursor cursor = textCursor();
    if (!cursor.hasSelection())
        cursor.select(QTextCursor::WordUnderCursor);
    cursor.mergeCharFormat(format);
}

void DocumentHandler::setSelectionStart(int position)
{
    m_selectionStart = position;
}

void DocumentHandler::setSelectionEnd(int position)
{
    m_selectionEnd = position;
}



================================================
FILE: src/documenthandler.h
================================================
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Quick Controls module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#ifndef DOCUMENTHANDLER_H
#define DOCUMENTHANDLER_H

#include <QQuickTextDocument>
#include "qmlhighlighter.h"
#include <QtGui/QTextCharFormat>
#include <QtCore/QTextCodec>

#include <qqmlfile.h>

QT_BEGIN_NAMESPACE
class QTextDocument;
QT_END_NAMESPACE

class DocumentHandler : public QObject
{
    Q_OBJECT

    Q_ENUMS(HAlignment)

    Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged)
    Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
    Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged)
    Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged)

    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)

public:
    DocumentHandler();

    QQuickItem *target() { return m_target; }

    void setTarget(QQuickItem *target);

    void setCursorPosition(int position);
    void setSelectionStart(int position);
    void setSelectionEnd(int position);

    int cursorPosition() const { return m_cursorPosition; }
    int selectionStart() const { return m_selectionStart; }
    int selectionEnd() const { return m_selectionEnd; }

    QString text() const;

public Q_SLOTS:
    void setText(const QString &arg);

Q_SIGNALS:
    void targetChanged();
    void cursorPositionChanged();
    void selectionStartChanged();
    void selectionEndChanged();
    void textChanged();

private:
    void reset();


    QTextCursor textCursor() const;
    void mergeFormatOnWordOrSelection(const QTextCharFormat &format);

    QQuickItem *m_target;
    QTextDocument *m_doc;

    int m_cursorPosition;
    int m_selectionStart;
    int m_selectionEnd;

    QMLHighlighter *m_highlighter;

    QString m_text;

};

#endif


================================================
FILE: src/main.cpp
================================================
#include <QtQuick/QQuickView>
#include <QtGui/QGuiApplication>
#include <QtQml>
#if QT_VERSION > QT_VERSION_CHECK(5, 1, 0)
#include <QQmlApplicationEngine>
#endif
#include "qhttpserver/src/qhttpserver.h"
#include "qhttpserver/src/qhttprequest.h"
#include "qhttpserver/src/qhttpresponse.h"
#include "qhttpserver/src/qhttpconnection.h"
#include "documenthandler.h"
#include "quickitemgrabber.h"
#if USE_WEBENGINE
#include <qtwebengineglobal.h>
#endif

int main(int argc, char *argv[])
{
    QStringList imports, plugins;

    QGuiApplication app(argc, argv);
    app.setApplicationName("Terrarium");
    app.setOrganizationName("terrariumapp");
    app.setOrganizationDomain("terrariumapp.com");

#if defined(Q_OS_MACX)
    int platformId = 0;
#elif defined(Q_OS_IOS)
    int platformId = 1;
#elif defined(Q_OS_ANDROID)
    int platformId = 2;
#elif defined(Q_OS_LINUX)
    int platformId = 3;
#else
    int platformId = 4;
#endif 

    qmlRegisterType<QHttpServer>("HttpServer", 1, 0, "HttpServer");
    qmlRegisterType<DocumentHandler>("DocumentHandler", 1, 0, "DocumentHandler");
    qmlRegisterUncreatableType<QHttpRequest>("HttpServer", 1, 0, "HttpRequest", "Do not create HttpRequest directly");
    qmlRegisterUncreatableType<QHttpResponse>("HttpServer", 1, 0, "HttpResponse", "Do not create HttpResponse directly");

    QString platformIP; 
    foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) {
        if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost))
             platformIP = address.toString();
    }

    // Handle command line arguments
    const QStringList arguments = QCoreApplication::arguments();
    for (int i = 1, size = arguments.size(); i < size; ++i) {
      const QString lowerArgument = arguments.at(i).toLower();
      if (lowerArgument == QLatin1String("-i") && i + 1 < size) {
        imports.append(arguments.at(++i));
      } else if (lowerArgument == QLatin1String("-p") && i + 1 < size) {
        plugins.append(arguments.at(++i));
      }
    }

#if USE_WEBENGINE
    QtWebEngine::initialize();
#endif

#if QT_VERSION > QT_VERSION_CHECK(5, 1, 0)
    QQmlApplicationEngine engine;

    for(int i = 0; i < imports.size(); ++i) {
      engine.addImportPath(imports[i]);
    }
    for(int i = 0; i < plugins.size(); ++i) {
      engine.addPluginPath(plugins[i]);
    }
    engine.rootContext()->setContextProperty("platform", QVariant::fromValue(platformId));
    engine.rootContext()->setContextProperty("platformIP", QVariant::fromValue(platformIP));
    engine.rootContext()->setContextProperty("Grabber",new QuickItemGrabber(&app));
    engine.load(QUrl("qrc:///main.qml"));
#else
    QQuickView view;
    view.engine()->rootContext()->setContextProperty("platform", QVariant::fromValue(platformId));
    view.engine()->rootContext()->setContextProperty("platformIP", QVariant::fromValue(platformIP));
    view.setSource(QUrl("qrc:///main.qml"));
    view.show();
#endif 
    return app.exec();
}


================================================
FILE: src/qmlhighlighter.cpp
================================================
#include "qmlhighlighter.h"
#include <QColor>

void QMLHighlighter::highlightBlock(const QString &text)
{
    QTextCharFormat keywordFormat;
    keywordFormat.setForeground(QColor("#d7ffaf")); // Identifier
    QTextCharFormat typeFormat;
    typeFormat.setForeground(QColor("#afffff")); // Type
    QTextCharFormat commentFormat;
    commentFormat.setForeground(QColor("#8a8a8a")); // Comment 
    QTextCharFormat numericConstantFormat;
    numericConstantFormat.setForeground(QColor("#ffffd7")); // Constant 
    QTextCharFormat stringConstantFormat;
    stringConstantFormat.setForeground(QColor("#ffffd7")); 

    QRegExp type("\\b[A-Z][A-Za-z]+\\b");
    QRegExp numericConstant("[0-9]+\\.?[0-9]*");
    QRegExp stringConstant("['\"].*['\"]");//Not multiline strings, but they're rare
    QRegExp lineComment("//[^\n]*");
    QRegExp startComment("/\\*");
    QRegExp endComment("\\*/");

    applyBasicHighlight(text, type, typeFormat);
    applyBasicHighlight(text, numericConstant, numericConstantFormat);
    applyBasicHighlight(text, stringConstant, stringConstantFormat);
    applyBasicHighlight(text, lineComment, commentFormat);

    setCurrentBlockState(0);

    int startIndex = 0;
    if (previousBlockState() != 1)
        startIndex = text.indexOf(startComment);

    while (startIndex >= 0) {
        int endIndex = text.indexOf(endComment, startIndex);
        int commentLength;
        if (endIndex == -1) {
            setCurrentBlockState(1);
            commentLength = text.length() - startIndex;
        } else {
            commentLength = endIndex - startIndex
                + endComment.matchedLength();
        }
        setFormat(startIndex, commentLength, commentFormat);
        startIndex = text.indexOf(startComment,
                startIndex + commentLength);
    }

}

void QMLHighlighter::applyBasicHighlight(const QString &text, QRegExp &re, QTextCharFormat &format)
{
    int index = text.indexOf(re);
    while (index >= 0) {
        int length = re.matchedLength();
        setFormat(index, length, format);
        index = text.indexOf(re, index + length);
    }
}


================================================
FILE: src/qmlhighlighter.h
================================================
#include <QSyntaxHighlighter>

class QMLHighlighter : public QSyntaxHighlighter
{
    Q_OBJECT
public:
        //BUG: QSyntaxHighlighter(0) crashes!
    QMLHighlighter(QObject* parent=new QObject()) : QSyntaxHighlighter(parent)
    {

    }
    QMLHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent)
    {
    }
protected:
    virtual void highlightBlock(const QString &text);
private:
    void applyBasicHighlight(const QString &text, QRegExp &re, QTextCharFormat &format);
};


================================================
FILE: src/quickitemgrabber.cpp
================================================
/** Author:  Ben Lau (https://github.com/benlau)
 */
#include <QtGlobal>
#include <QtCore>
#include <QQuickWindow>
#include <QOpenGLFunctions>
#include "quickitemgrabber.h"

#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
#include <private/qquickitem_p.h>
#include <private/qquickshadereffectsource_p.h>
#else
// Added since Qt 5.4
#include <QQuickItemGrabResult>
#endif


QuickItemGrabber::QuickItemGrabber(QObject *parent) :
    QObject(parent)
{
    m_busy = false;
    m_ready = false;
}

bool QuickItemGrabber::busy() const
{
    return m_busy;
}

bool QuickItemGrabber::grab(QQuickItem *target,QSize targetSize)
{
    if (m_busy ||
        target == 0  ||
        !target->window() ||
        !target->window()->isVisible() ) {
        return false;
    }
    m_ready = false;
    m_targetSize = targetSize;
    m_target = target;
    m_window = target->window();

    if (m_targetSize.isEmpty()) {
        m_targetSize = QSize(m_target->width(),m_target->height());
    }

#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))

    QQuickItemPrivate::get(m_target)->refFromEffectItem(false);

    m_target->window()->update();

    connect(m_window.data(),SIGNAL(beforeSynchronizing()),
            this,SLOT(ready()),Qt::DirectConnection);

    connect(m_window.data(),SIGNAL(afterRendering()),
            this,SLOT(capture()),Qt::DirectConnection);
#else

    result = target->grabToImage(m_targetSize);

    if (result.isNull()) {
        qDebug() << "Can't grab target item";
        return false;
    }

    connect(result.data(),SIGNAL(ready()),
            this,SLOT(onGrabResultReady()));
#endif

    setBusy(true);

    return true;
}

bool QuickItemGrabber::save(QString filename)
{
    if (m_image.isNull()) {
        qWarning() << "QuickItemGrabber::save() - The image is null";
        return false;
    }
    return m_image.save(filename);
}

void QuickItemGrabber::ready()
{
    m_ready = true;
}

#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
void QuickItemGrabber::onGrabResultReady()
{
    QImage image =  result->image();
    setImage(image);

    result.clear();
    setBusy(false);
    emit grabbed();
}
#endif

QImage QuickItemGrabber::image() const
{
    return m_image;
}

#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))

void QuickItemGrabber::capture()
{
    if (!m_ready) { // It is not ready yet
        return;
    }

    if (m_target) { // Just in case the item is destroyed before rendering completed
        QOpenGLContext* context = QOpenGLContext::currentContext();

        QQuickShaderEffectTexture *m_texture = new QQuickShaderEffectTexture(m_target);
        m_texture->setItem(QQuickItemPrivate::get(m_target)->itemNode());

        // Set the source rectangle
        QSize sourceSize;
        sourceSize = QSize(m_target->width(),m_target->height());
        m_texture->setRect(QRectF(0, sourceSize.height(), sourceSize.width(), -sourceSize.height()));

        QSize maxSize = maxTextureSize();
        /*
        if (!maxSize.isValid()) {
            GLint param;

            QOpenGLFunctions glFuncs(context);
            glFuncs.glGetIntegerv(GL_MAX_TEXTURE_SIZE,&param);

            maxSize = QSize(param,param);
            setMaxTextureSize(maxSize);
        }

        QSize textureSize = m_targetSize;
        if (maxSize.isValid() &&
                (textureSize.width() > maxSize.width() ||
                textureSize.height() > maxSize.height())) {
            FVRectToRect scaler;
            scaler.scaleToFit(textureSize,maxSize);
            // The required size is larger than max texture size.
            qDebug() << "Downgrade target image from" << textureSize << scaler.transformedRect().toRect().size();
            textureSize = scaler.transformedRect().toRect().size();
        }
        */

        QSize expectedSize = textureSize();

        QSGContext *sg = QSGRenderContext::from(context)->sceneGraphContext();
        const QSize minSize = sg->minimumFBOSize();
        m_texture->setSize(QSize(qMax<int>(minSize.width(), expectedSize.width()),
                                  qMax<int>(minSize.height(), expectedSize.height())));
        m_texture->scheduleUpdate();
        m_texture->updateTexture();
        QImage image =  m_texture->toImage();
        setImage(image);

        delete m_texture;
        m_texture = 0;
    }

    disconnect(m_window.data(), SIGNAL(afterRendering()), this, SLOT(capture()));
    disconnect(m_window.data(), SIGNAL(beforeSynchronizing()), this, SLOT(ready()));

    setBusy(false);
    emit grabbed();
}
#endif

void QuickItemGrabber::setBusy(bool value)
{
    if (m_busy != value) {
        m_busy = value;
        emit busyChanged();
    }
}

void QuickItemGrabber::setImage(QImage value)
{
    m_image = value;
    emit imageChanged();
}

void QuickItemGrabber::clear()
{
    setImage(QImage());
}



================================================
FILE: src/quickitemgrabber.h
================================================
/** Author:  Ben Lau (https://github.com/benlau)
 */
#ifndef QUICKITEMGRABBER_H
#define QUICKITEMGRABBER_H

#include <QObject>
#include <QQuickItem>
#include <QImage>
#include <QPointer>

/// QuickItemGrabber grabs QQuickItem into QImage

class QuickItemGrabber : public QObject
{
    Q_OBJECT
    /// "Busy" flag. It is TRUE if the grabber is running. It won't accept another request when busy.
    Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)

    /// The grabbed image
    Q_PROPERTY(QImage image READ image NOTIFY imageChanged)

public:
    explicit QuickItemGrabber(QObject *parent = 0);

    bool busy() const;
    QImage image() const;

    /// Grab the target item and save to "image" property
    Q_INVOKABLE bool grab(QQuickItem* target,QSize targetSize = QSize());

    /// Save the grabbed image into file. It is a blocked call.
    Q_INVOKABLE bool save(QString filename);

    /// Clear the captured image.
    Q_INVOKABLE void clear();

signals:
    void busyChanged();
    void imageChanged();
    void grabbed();
    void maxTextureSizeChanged();

private:
    // Ready for capture
    Q_INVOKABLE void ready();

#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))
    Q_INVOKABLE void capture();
#else
    Q_INVOKABLE void onGrabResultReady();
    QSharedPointer<QQuickItemGrabResult> result;
#endif

    void setBusy(bool value);
    void setImage(QImage value);

    bool m_busy;
    bool m_ready;
    QSize m_targetSize;
    QPointer<QQuickItem> m_target;
    QPointer<QQuickWindow> m_window;
    QImage m_image;
};

#endif // QUICKITEMGRABBER_H


================================================
FILE: terrarium-app.pro
================================================
TEMPLATE = app
TARGET = Terrarium
QT += qml quick network sql
webengine {
    QT += webengine
    DEFINES += USE_WEBENGINE
}

SOURCES += src/main.cpp \
    src/qmlhighlighter.cpp \
    src/documenthandler.cpp \
    qhttpserver/src/qhttpconnection.cpp \
    qhttpserver/src/qhttprequest.cpp \
    qhttpserver/src/qhttpresponse.cpp \
    qhttpserver/src/qhttpserver.cpp \
    qhttpserver/http-parser/http_parser.c \
    src/quickitemgrabber.cpp

HEADERS += qhttpserver/src/qhttpserver.h \
    qhttpserver/src//qhttpresponse.h \
    qhttpserver/src//qhttprequest.h \
    src/qmlhighlighter.h \
    src/documenthandler.h \
    qhttpserver/src//qhttpconnection.h \ 
    src/quickitemgrabber.h

INCLUDEPATH += ./qhttpserver/http-parser/
RESOURCES += qml/assets.qrc

android {
    ANDROID_PACKAGE_SOURCE_DIR = ./platform/android
}

macx {
    QMAKE_MAC_SDK = macosx10.10
    QMAKE_INFO_PLIST = platform/mac/Info.plist
    ICON = platform/mac/icon.icns
    #QMAKE_POST_LINK += macdeployqt Terrarium.app/ -qmldir=qml/ -verbose=1 -dmg
}

ios {
    QMAKE_INFO_PLIST = platform/ios/Info.plist
}
Download .txt
gitextract_mb_qe0pv/

├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── patches/
│   └── expose_loader_errorstring_invokable.patch
├── platform/
│   ├── android/
│   │   └── AndroidManifest.xml
│   ├── arch/
│   │   └── terrarium.desktop
│   ├── ios/
│   │   ├── Images.xcassets/
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   └── LaunchImage.launchimage/
│   │   │       └── Contents.json
│   │   └── Info.plist
│   ├── mac/
│   │   ├── Info.plist
│   │   └── icon.icns
│   └── ubuntu/
│       ├── debian/
│       │   ├── changelog
│       │   ├── compat
│       │   ├── control
│       │   ├── copyright
│       │   ├── install
│       │   ├── rules
│       │   └── source/
│       │       └── format
│       ├── manifest.json
│       ├── terrarium.desktop
│       └── terrarium.json
├── qml/
│   ├── BottomBar.qml
│   ├── CustomButton.qml
│   ├── HttpServer.qml
│   ├── NaviBar.qml
│   ├── QtWebKit.qml
│   ├── QtWebView.qml
│   ├── assets.qrc
│   └── main.qml
├── src/
│   ├── documenthandler.cpp
│   ├── documenthandler.h
│   ├── main.cpp
│   ├── qmlhighlighter.cpp
│   ├── qmlhighlighter.h
│   ├── quickitemgrabber.cpp
│   └── quickitemgrabber.h
└── terrarium-app.pro
Download .txt
SYMBOL INDEX (7 symbols across 6 files)

FILE: src/documenthandler.cpp
  function QString (line 86) | QString DocumentHandler::text() const
  function QTextCursor (line 107) | QTextCursor DocumentHandler::textCursor() const

FILE: src/documenthandler.h
  function QQuickItem (line 71) | QQuickItem *target() { return m_target; }

FILE: src/main.cpp
  function main (line 17) | int main(int argc, char *argv[])

FILE: src/qmlhighlighter.h
  function class (line 3) | class QMLHighlighter : public QSyntaxHighlighter

FILE: src/quickitemgrabber.cpp
  function QImage (line 102) | QImage QuickItemGrabber::image() const

FILE: src/quickitemgrabber.h
  function class (line 13) | class QuickItemGrabber : public QObject
Condensed preview — 38 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (68K chars).
[
  {
    "path": ".gitignore",
    "chars": 393,
    "preview": "# C++ objects and libs\n\n*.slo\n*.lo\n*.o\n*.a\n*.la\n*.lai\n*.so\n*.dll\n*.dylib\n\n# Qt-es\n\n/.qmake.cache\n/.qmake.stash\n*.pro.use"
  },
  {
    "path": ".gitmodules",
    "chars": 120,
    "preview": "[submodule \"qhttpserver\"]\n\tpath = qhttpserver\n\turl = https://github.com/rschroll/qhttpserver.git\n        ignore = dirty\n"
  },
  {
    "path": "LICENSE",
    "chars": 1087,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014-2015 Chen, Ping-Hsun\n\nPermission is hereby granted, free of charge, to any per"
  },
  {
    "path": "README.md",
    "chars": 3892,
    "preview": "Terrarium - UI Prototyping Tool for Coders\n=========\n\n![Doge](http://i.imgur.com/Z0KMIaf.png)\n\nTerrarium is a cross plat"
  },
  {
    "path": "patches/expose_loader_errorstring_invokable.patch",
    "chars": 1178,
    "preview": "--- qtdeclarative-everywhere-src-5.11.1.orig/src/quick/items/qquickloader.cpp\n+++ qtdeclarative-everywhere-src-5.11.1/sr"
  },
  {
    "path": "platform/android/AndroidManifest.xml",
    "chars": 4412,
    "preview": "<?xml version='1.0' encoding='utf-8'?>\n<manifest package=\"com.terrariumapp.penk.Terrarium\" xmlns:android=\"http://schemas"
  },
  {
    "path": "platform/arch/terrarium.desktop",
    "chars": 290,
    "preview": "[Desktop Entry]\nVersion=1.5\nName=Terrarium\nGenericName=Terrarium\nComment=UI Prototyping Tool for Coders\nType=Application"
  },
  {
    "path": "platform/ios/Images.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 2113,
    "preview": "{\n  \"images\" : [\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon.png\",\n      \"scale\" : "
  },
  {
    "path": "platform/ios/Images.xcassets/LaunchImage.launchimage/Contents.json",
    "chars": 1937,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"1x\",\n      \"orientation\" : \"portrait\"\n    },\n    {\n   "
  },
  {
    "path": "platform/ios/Info.plist",
    "chars": 1566,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "platform/mac/Info.plist",
    "chars": 761,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "platform/ubuntu/debian/changelog",
    "chars": 275,
    "preview": "terrarium (1.5) trusty; urgency=medium\n\n  * Bump version\n\n -- Ping-Hsun Chen (penk) <penkia@gmail.com>  Mon, 16 Mar 2015"
  },
  {
    "path": "platform/ubuntu/debian/compat",
    "chars": 2,
    "preview": "8\n"
  },
  {
    "path": "platform/ubuntu/debian/control",
    "chars": 608,
    "preview": "Source: terrarium\nPriority: extra\nMaintainer: Ping-Hsun Chen (penk) <penkia@gmail.com>\nBuild-Depends: debhelper (>= 8.0."
  },
  {
    "path": "platform/ubuntu/debian/copyright",
    "chars": 1135,
    "preview": "Files: *\nCopyright: 2014 Ping-Hsun Chen (penk) <penkia@gmail.com>\nLicense: MIT\n\nLicense: MIT\n Permission is hereby grant"
  },
  {
    "path": "platform/ubuntu/debian/install",
    "chars": 102,
    "preview": "terrarium.desktop /usr/share/applications\nterrarium-app.png /usr/share/terrarium/\nTerrarium /usr/bin/\n"
  },
  {
    "path": "platform/ubuntu/debian/rules",
    "chars": 96,
    "preview": "#!/usr/bin/make -f\n\n# Uncomment this to turn on verbose mode.\n# #export DH_VERBOSE=1\n\n%:\n\tdh $@\n"
  },
  {
    "path": "platform/ubuntu/debian/source/format",
    "chars": 13,
    "preview": "3.0 (native)\n"
  },
  {
    "path": "platform/ubuntu/manifest.json",
    "chars": 335,
    "preview": "{\n\"description\": \"UI Prototyping Tool for Coders\",\n\"framework\": \"ubuntu-sdk-14.04\",\n\"architecture\": \"armhf\",\n\"hooks\": {\n"
  },
  {
    "path": "platform/ubuntu/terrarium.desktop",
    "chars": 294,
    "preview": "[Desktop Entry]\nVersion=1.5\nName=Terrarium\nGenericName=Terrarium\nComment=UI Prototyping Tool for Coders\nType=Application"
  },
  {
    "path": "platform/ubuntu/terrarium.json",
    "chars": 83,
    "preview": "{\n\"policy_groups\": [\n\"networking\",\n\"sensors\",\n\"webview\"\n],\n\"policy_version\": 1.1\n}\n"
  },
  {
    "path": "qml/BottomBar.qml",
    "chars": 1416,
    "preview": "import QtQuick 2.0\n\nRectangle {\n    anchors {\n        bottom: parent.bottom\n        left: background.left\n        margin"
  },
  {
    "path": "qml/CustomButton.qml",
    "chars": 568,
    "preview": "import QtQuick 2.0\n\nItem {\n    id: button\n    width: 30 * scaleRatio; height: 30 * scaleRatio; \n    property alias icon:"
  },
  {
    "path": "qml/HttpServer.qml",
    "chars": 728,
    "preview": "import QtQuick 2.0\nimport HttpServer 1.0\n\nHttpServer {\n    id: server\n    Component.onCompleted: listen(platformIP, 5000"
  },
  {
    "path": "qml/NaviBar.qml",
    "chars": 5227,
    "preview": "import QtQuick 2.0\nimport QtGraphicalEffects 1.0\n\nRectangle {\n    id: navigationBar\n    width: parent.width\n    height: "
  },
  {
    "path": "qml/QtWebKit.qml",
    "chars": 65,
    "preview": "import QtWebKit 3.0\nimport QtWebKit.experimental 1.0\n\nWebView {}\n"
  },
  {
    "path": "qml/QtWebView.qml",
    "chars": 33,
    "preview": "import QtWebView 1.0\n\nWebView {}\n"
  },
  {
    "path": "qml/assets.qrc",
    "chars": 360,
    "preview": "<!DOCTYPE RCC><RCC version=\"1.0\">\n<qresource prefix=\"/\"> \n    <file>main.qml</file>\n    <file>HttpServer.qml</file>\n    "
  },
  {
    "path": "qml/main.qml",
    "chars": 12787,
    "preview": "import QtQuick 2.0\nimport QtQuick.Window 2.0\n\nimport HttpServer 1.0\nimport QtQuick.LocalStorage 2.0\nimport DocumentHandl"
  },
  {
    "path": "src/documenthandler.cpp",
    "chars": 4043,
    "preview": "/****************************************************************************\n**\n** Copyright (C) 2013 Digia Plc and/or "
  },
  {
    "path": "src/documenthandler.h",
    "chars": 3820,
    "preview": "/****************************************************************************\n**\n** Copyright (C) 2013 Digia Plc and/or "
  },
  {
    "path": "src/main.cpp",
    "chars": 3015,
    "preview": "#include <QtQuick/QQuickView>\n#include <QtGui/QGuiApplication>\n#include <QtQml>\n#if QT_VERSION > QT_VERSION_CHECK(5, 1, "
  },
  {
    "path": "src/qmlhighlighter.cpp",
    "chars": 2112,
    "preview": "#include \"qmlhighlighter.h\"\n#include <QColor>\n\nvoid QMLHighlighter::highlightBlock(const QString &text)\n{\n    QTextCharF"
  },
  {
    "path": "src/qmlhighlighter.h",
    "chars": 490,
    "preview": "#include <QSyntaxHighlighter>\n\nclass QMLHighlighter : public QSyntaxHighlighter\n{\n    Q_OBJECT\npublic:\n        //BUG: QS"
  },
  {
    "path": "src/quickitemgrabber.cpp",
    "chars": 4809,
    "preview": "/** Author:  Ben Lau (https://github.com/benlau)\n */\n#include <QtGlobal>\n#include <QtCore>\n#include <QQuickWindow>\n#incl"
  },
  {
    "path": "src/quickitemgrabber.h",
    "chars": 1566,
    "preview": "/** Author:  Ben Lau (https://github.com/benlau)\n */\n#ifndef QUICKITEMGRABBER_H\n#define QUICKITEMGRABBER_H\n\n#include <QO"
  },
  {
    "path": "terrarium-app.pro",
    "chars": 1083,
    "preview": "TEMPLATE = app\nTARGET = Terrarium\nQT += qml quick network sql\nwebengine {\n    QT += webengine\n    DEFINES += USE_WEBENGI"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the penk/terrarium-app GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 38 files (61.3 KB), approximately 16.4k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!