[
  {
    "path": ".gitignore",
    "content": "# 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.user\n*.pro.user.*\n*.moc\nmoc_*.cpp\nqrc_*.cpp\nui_*.h\nMakefile*\n*-build-*\n\n# QtCreator\n\n*.autosave\n*.swp\n*.app\n*.dmg\n*deployment-settings.json\n\n# Project files\nTerrarium\nTerrarium.build\nTerrarium.xcodeproj\n.tmp\nterrarium_plugin_import.cpp\nterrarium_qml_plugin_import.cpp\nqt.conf\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"qhttpserver\"]\n\tpath = qhttpserver\n\turl = https://github.com/rschroll/qhttpserver.git\n        ignore = dirty\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014-2015 Chen, Ping-Hsun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "Terrarium - UI Prototyping Tool for Coders\n=========\n\n![Doge](http://i.imgur.com/Z0KMIaf.png)\n\nTerrarium 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!  \n\nIt 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).\n\n### More details on http://www.terrariumapp.com\n\n## Download\n\n* [iOS](https://itunes.apple.com/us/app/terrarium/id891232736?ls=1&mt=8)\n* [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)\n* [Mac OSX](https://github.com/penk/terrarium-app/releases/download/V1.5/Terrarium-1.5.dmg)\n* [Ubuntu Linux](https://github.com/penk/terrarium-app/releases/download/V1.5/terrarium_1.5_amd64.deb)\n* [Ubuntu Touch](https://github.com/penk/terrarium-app/releases/download/V1.5/com.ubuntu.developer.penk.terrarium_1.5_armhf.click)\n\n## Build Instructions\n\n    git clone https://github.com/penk/terrarium-app.git\n    cd terrarium-app && git submodule init && git submodule update\n    qmake && make\n\n## Platform Specific Instructions\n\n### For Arch-Linux\nJust go to AUR:\n`yaourt -S terrarium-git`\n\n### For Mac OSX/iOS\n\nTo 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`.\n\nAs for Mac OSX, refer to `macdeployqt` command in `terrarium-app.pro` file.\n\n### For Ubuntu Desktop/Phone\n\nIf you're using Qt packages from apt archive instead of [qt-project.org](http://download.qt-project.org/) releases, here's the dependencies:\n\n    sudo apt-get install qt5-qmake qt5-default qtbase5-dev qtdeclarative5-dev build-essential\n\nAll `debian/` package information can be found under `platform/ubuntu/` directory, copy it to current path and build the package by:\n\n    cp -r platform/ubuntu/debian .\n    cp platform/ubuntu/terrarium.desktop .\n    dpkg-buildpackage -b\n\nIf you're building click package, execute following command on device (for native compile):\n\n    cp platform/ubuntu/* .\n    click build .\n\nAnd install it\n\n    pkcon --allow-untrusted install-local com.ubuntu.developer.penk.terrarium_1.5_armhf.click\n\n### For Android\n\nFirst generate your keystore by `keytool`\n\n    keytool -genkey -v -keystore ../TerrariumApp.keystore -alias TerrariumApp -keyalg RSA -keysize 2048 -validity 10000\n\nthen\n\n    ~/Qt5.4.1/5.4/android_armv7/bin/qmake\n    make\n    make install INSTALL_ROOT=../android-terrarium\n\nBuild and sign apk by:\n\n    ~/Qt5.4.1/5.4/android_armv7/bin/androiddeployqt --input \\\n        android-libTerrarium.so-deployment-settings.json \\\n        --output ../android-terrarium --release --sign ../TerrariumApp.keystore TerrariumApp\n\n## Screenshots\n\n* [Android 5.0.0](http://i.imgur.com/0X6e6wK.png)\n* [iOS 8.2](http://i.imgur.com/n2EPoha.png)\n* [Mac OSX 10.10.2](http://i.imgur.com/Z0KMIaf.png)\n* [Ubuntu Touch](http://i.imgur.com/KShLea0.png)\n* [Ubuntu 14.10](http://i.imgur.com/TI2rLIX.png)\n\n## LICENSE\n\nCopyright © 2014-2015 Ping-Hsun (penk) Chen <penkia@gmail.com>  \nThe source code is, unless otherwise specified, distributed under the terms of the MIT License.\n\n## CREDITS\n\n* [DocumentHandler](https://github.com/khertan/ownNotes) by Benoît HERVIER\n* [QMLHighligher](https://gitorious.org/aalperts-automatons/bragi) by Alan Alpert\n* [QHttpServer](https://github.com/rschroll/qhttpserver) by Robert Schroll\n* [Font Awesome](http://fontawesome.io) by Dave Gandy\n"
  },
  {
    "path": "patches/expose_loader_errorstring_invokable.patch",
    "content": "--- qtdeclarative-everywhere-src-5.11.1.orig/src/quick/items/qquickloader.cpp\n+++ qtdeclarative-everywhere-src-5.11.1/src/quick/items/qquickloader.cpp\n@@ -629,6 +629,25 @@\n     }\n }\n \n+QString QQuickLoader::errorString() const\n+{\n+   Q_D(const QQuickLoader);\n+   QString ret;\n+   if(d->component->errors().isEmpty())\n+      return ret;\n+\n+   if (d->component && d->component->isError()) {\n+        const QList<QQmlError> errorList = d->component->errors();\n+        for (const QQmlError &e : errorList) {\n+            ret += e.url().toString() + QLatin1Char(':') +\n+              QString::number(e.line()) + QLatin1Char(' ') +\n+              e.description() + QLatin1Char('\\n');\n+        }\n+   }\n+ \n+   return ret;\n+}\n+\n void QQuickLoaderIncubator::setInitialState(QObject *o)\n {\n     loader->setInitialState(o);\n--- qtdeclarative-everywhere-src-5.11.1.orig/src/quick/items/qquickloader_p.h\n+++ qtdeclarative-everywhere-src-5.11.1/src/quick/items/qquickloader_p.h\n@@ -76,6 +76,7 @@\n     void setActive(bool newVal);\n \n     Q_INVOKABLE void setSource(QQmlV4Function *);\n+    Q_INVOKABLE QString errorString() const;\n \n     QUrl source() const;\n     void setSource(const QUrl &);\n"
  },
  {
    "path": "platform/android/AndroidManifest.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<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\">\n    <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\">\n        <activity android:configChanges=\"orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation\"\n                  android:name=\"org.qtproject.qt5.android.bindings.QtActivity\"\n                  android:label=\"@string/app_name\"\n                  android:screenOrientation=\"unspecified\"\n                  android:launchMode=\"singleTop\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n            <meta-data android:name=\"android.app.lib_name\" android:value=\"Terrarium\"/>\n            <meta-data android:name=\"android.app.qt_sources_resource_id\" android:resource=\"@array/qt_sources\"/>\n            <meta-data android:name=\"android.app.repository\" android:value=\"default\"/>\n            <meta-data android:name=\"android.app.qt_libs_resource_id\" android:resource=\"@array/qt_libs\"/>\n            <meta-data android:name=\"android.app.bundled_libs_resource_id\" android:resource=\"@array/bundled_libs\"/>\n            <!-- Deploy Qt libs as part of package -->\n            <meta-data android:name=\"android.app.bundle_local_qt_libs\" android:value=\"1\"/>\n            <meta-data android:name=\"android.app.bundled_in_lib_resource_id\" android:resource=\"@array/bundled_in_lib\"/>\n            <meta-data android:name=\"android.app.bundled_in_assets_resource_id\" android:resource=\"@array/bundled_in_assets\"/>\n            <!-- Run with local libs -->\n            <meta-data android:name=\"android.app.use_local_qt_libs\" android:value=\"1\"/>\n            <meta-data android:name=\"android.app.libs_prefix\" android:value=\"/data/local/tmp/qt/\"/>\n            <meta-data android:name=\"android.app.load_local_libs\" android:value=\"plugins/platforms/android/libqtforandroid.so:lib/libQt5QuickParticles.so\"/>\n            <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\"/>\n            <meta-data android:name=\"android.app.static_init_classes\" android:value=\"\"/>\n            <!--  Messages maps -->\n            <meta-data android:value=\"@string/ministro_not_found_msg\" android:name=\"android.app.ministro_not_found_msg\"/>\n            <meta-data android:value=\"@string/ministro_needed_msg\" android:name=\"android.app.ministro_needed_msg\"/>\n            <meta-data android:value=\"@string/fatal_error_msg\" android:name=\"android.app.fatal_error_msg\"/>\n            <!--  Messages maps -->\n\n            <!-- Splash screen -->\n            <!--\n            <meta-data android:name=\"android.app.splash_screen_drawable\" android:resource=\"@drawable/logo\"/>\n            -->\n            <!-- Splash screen -->\n        </activity>\n    </application>\n    <uses-sdk android:minSdkVersion=\"9\" android:targetSdkVersion=\"14\"/>\n    <supports-screens android:largeScreens=\"true\" android:normalScreens=\"true\" android:anyDensity=\"true\" android:smallScreens=\"true\"/>\n\n    <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.\n         Remove the comment if you do not require these default permissions. -->\n        <uses-permission android:name=\"android.permission.INTERNET\" />\n        <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n        <uses-permission android:name=\"android.permission.CAMERA\" />\n        <uses-feature android:name=\"android.hardware.camera\" />\n        <uses-feature android:name=\"android.hardware.camera.autofocus\" />\n\n    <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.\n         Remove the comment if you do not require these default features. -->\n        <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\" />\n\n</manifest>\n"
  },
  {
    "path": "platform/arch/terrarium.desktop",
    "content": "[Desktop Entry]\nVersion=1.5\nName=Terrarium\nGenericName=Terrarium\nComment=UI Prototyping Tool for Coders\nType=Application\nIcon=terrarium-app.png\nExec=Terrarium\nTerminal=false\nMimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;\nX-Ubuntu-Touch=true\n"
  },
  {
    "path": "platform/ios/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-1.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon@2x-1.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-60@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-60@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small-1.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small@2x-1.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-40.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-40@2x-1.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small-50.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small-50@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-72.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-72@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-76.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-76@2x.png\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "platform/ios/Images.xcassets/LaunchImage.launchimage/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"1x\",\n      \"orientation\" : \"portrait\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"orientation\" : \"portrait\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Default-568h@2x.png\",\n      \"subtype\" : \"retina4\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Default-568h@2x.png\",\n      \"minimum-system-version\" : \"7.0\",\n      \"subtype\" : \"retina4\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"minimum-system-version\" : \"7.0\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"minimum-system-version\" : \"7.0\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"minimum-system-version\" : \"7.0\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"minimum-system-version\" : \"7.0\",\n      \"extent\" : \"full-screen\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "platform/ios/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDisplayName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundleExecutable</key>\n\t<string>Terrarium</string>\n\t<key>CFBundleGetInfoString</key>\n\t<string>Created by Qt/QMake</string>\n\t<key>CFBundleIcons</key>\n\t<dict/>\n\t<key>CFBundleIcons~ipad</key>\n\t<dict/>\n\t<key>CFBundleIdentifier</key>\n\t<string>com.terrariumapp.${PRODUCT_NAME:rfc1034identifier}</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.5</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.5.1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NOTE</key>\n\t<string>This file was generated by Qt/QMake.</string>\n\t<key>UIStatusBarHidden</key>\n\t<true/>\n\t<key>UIStatusBarHidden~ipad</key>\n\t<true/>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "platform/mac/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>Terrarium</string>\n\t<key>CFBundleIconFile</key>\n\t<string>icon.icns</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>com.terrariumapp.terrarium</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>1.0</string>\n\t<key>CFBundleName</key>\n\t<string>Terrarium</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n        <key>NSPrincipalClass</key>\n        <string>NSApplication</string>\n        <key>NSHighResolutionCapable</key>\n        <string>True</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "platform/ubuntu/debian/changelog",
    "content": "terrarium (1.5) trusty; urgency=medium\n\n  * Bump version\n\n -- Ping-Hsun Chen (penk) <penkia@gmail.com>  Mon, 16 Mar 2015 11:10:32 +0800\n\nterrarium (0.1) trusty; urgency=medium\n\n  * Initial commit\n\n -- Ping-Hsun Chen (penk) <penkia@gmail.com>  Tue, 17 Jun 2014 10:19:26 +0000\n"
  },
  {
    "path": "platform/ubuntu/debian/compat",
    "content": "8\n"
  },
  {
    "path": "platform/ubuntu/debian/control",
    "content": "Source: terrarium\nPriority: extra\nMaintainer: Ping-Hsun Chen (penk) <penkia@gmail.com>\nBuild-Depends: debhelper (>= 8.0.0),\n        qt5-qmake,\n        qt5-default,\n        qtbase5-dev,\n        qtdeclarative5-dev\nStandards-Version: 3.9.4\nSection: misc\nHomepage: http://www.terrariumapp.com\n\nPackage: terrarium\nSection: misc\nArchitecture: i386 amd64 armhf\nDepends: ${misc:Depends},\n \t ${shlibs:Depends},\n \t qmlscene,\n         libqt5sql5-sqlite,\n         qtdeclarative5-qtquick2-plugin,\n         qtdeclarative5-window-plugin,\nDescription: Live QML Editor and Viewer\n Terrarium is an open source QML Playgrounds\n"
  },
  {
    "path": "platform/ubuntu/debian/copyright",
    "content": "Files: *\nCopyright: 2014 Ping-Hsun Chen (penk) <penkia@gmail.com>\nLicense: MIT\n\nLicense: MIT\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n .\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n .\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n"
  },
  {
    "path": "platform/ubuntu/debian/install",
    "content": "terrarium.desktop /usr/share/applications\nterrarium-app.png /usr/share/terrarium/\nTerrarium /usr/bin/\n"
  },
  {
    "path": "platform/ubuntu/debian/rules",
    "content": "#!/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",
    "content": "3.0 (native)\n"
  },
  {
    "path": "platform/ubuntu/manifest.json",
    "content": "{\n\"description\": \"UI Prototyping Tool for Coders\",\n\"framework\": \"ubuntu-sdk-14.04\",\n\"architecture\": \"armhf\",\n\"hooks\": {\n\"terrarium\": {\n\"apparmor\": \"terrarium.json\",\n\"desktop\": \"terrarium.desktop\"\n}\n},\n\"maintainer\": \"Penk Chen <penkia@gmail.com>\",\n\"name\": \"com.ubuntu.developer.penk.terrarium\",\n\"title\": \"Terrarium\",\n\"version\": \"1.5\"\n}\n"
  },
  {
    "path": "platform/ubuntu/terrarium.desktop",
    "content": "[Desktop Entry]\nVersion=1.5\nName=Terrarium\nGenericName=Terrarium\nComment=UI Prototyping Tool for Coders\nType=Application\nIcon=./terrarium-app.png\nExec=./Terrarium\nTerminal=false\nMimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;\nX-Ubuntu-Touch=true\n"
  },
  {
    "path": "platform/ubuntu/terrarium.json",
    "content": "{\n\"policy_groups\": [\n\"networking\",\n\"sensors\",\n\"webview\"\n],\n\"policy_version\": 1.1\n}\n"
  },
  {
    "path": "qml/BottomBar.qml",
    "content": "import QtQuick 2.0\n\nRectangle {\n    anchors {\n        bottom: parent.bottom\n        left: background.left\n        margins: 5 * scaleRatio \n    }\n    radius: 0.5 * height\n    height: 50 * scaleRatio\n    width: height \n    gradient: Gradient {\n        GradientStop { position: 0.0; color: \"#70787F\" }\n        GradientStop { position: 1.0; color: \"#383C40\" }\n    }\n    CustomButton {\n        id: viewSwitchButton\n        anchors.fill: parent\n        //anchors { top: parent.top; left: parent.left }\n        anchors.margins: -20 //os_type[platform] == 'ios' ? 12 : 0\n        // \"\\uf121\" : fa-code, to editor\n        // \"\\uf0db\" : fa-columns, to splitted view\n        // \"\\uf144\" : fa-play-circle, to viewer \n        icon.text: \n            if (splitState=='viewer' && root.width * scaleRatio > 600) { \"\\uf0db\" } \n            else if (splitState=='viewer') { \"\\uf121\" } \n            else if (splitState=='editor') { \"\\uf144\" } \n            else if (splitState=='splitted') { \"\\uf121\" }\n            else \"\\uf144\"\n        defaultColor: \"#CAD8E5\"\n        onClicked: {\n            // splitted -> editor -> viewer \n            if (splitState == 'editor')\n                splitState = 'viewer';\n            else if (splitState == 'viewer' && root.width * scaleRatio > 600)\n                splitState = 'splitted';\n            else \n                splitState = 'editor';\n\n            view.state = splitState;\n        }\n    }\n}\n"
  },
  {
    "path": "qml/CustomButton.qml",
    "content": "import QtQuick 2.0\n\nItem {\n    id: button\n    width: 30 * scaleRatio; height: 30 * scaleRatio; \n    property alias icon: buttonIcon\n    property variant defaultColor: \"#CAD8E5\"\n    signal clicked()\n    anchors { margins: 10 }\n    Text {\n        id: buttonIcon\n        anchors.centerIn: parent\n        font { family: fontAwesome.name; pointSize: os_type[platform] == 'ios' ? 32 : 26 }\n        color: defaultColor\n        MouseArea {\n            anchors.fill: parent\n            anchors.margins: -5 * scaleRatio\n            onPressed: button.clicked()\n        }\n    }\n}\n"
  },
  {
    "path": "qml/HttpServer.qml",
    "content": "import QtQuick 2.0\nimport HttpServer 1.0\n\nHttpServer {\n    id: server\n    Component.onCompleted: listen(platformIP, 5000)\n    onNewRequest: {\n        var route = /^\\/\\?/;\n        if (request.url.toString().match(/\\/update\\?/)) {\n            editor.text = decodeURI(request.url.toString().replace(/\\/update\\?/, \"\")).replace(/%23/g, '#');\n            console.log(editor.text)\n            response.writeHead(200)\n            response.end()\n            reloadView();\n        }\n        else if ( route.test(request.url) ) {\n            response.writeHead(200)\n            response.write(editor.text)\n            response.end()\n        }\n        else {\n            response.writeHead(404)\n            response.end()\n        }\n    }\n}\n"
  },
  {
    "path": "qml/NaviBar.qml",
    "content": "import QtQuick 2.0\nimport QtGraphicalEffects 1.0\n\nRectangle {\n    id: navigationBar\n    width: parent.width\n    height: 44 * scaleRatio\n    anchors {\n        bottom: parent.bottom\n        left: parent.left\n    }\n    color: \"white\"\n\n    Rectangle {\n        id: repeater\n        border.color: \"#007edf\"\n        width: 240 * scaleRatio\n        height: 29 * scaleRatio \n        anchors.centerIn: parent \n        radius: 5 \n        smooth: true\n        visible: false\n        Row {\n            Rectangle {\n                width: 80 *scaleRatio ; height: 29 * scaleRatio\n                color: splitState == 'editor' ? \"#007edf\" : \"transparent\"\n                Text {\n                    text: \"Editor\"\n                    color: splitState == 'editor' ? \"white\" : '#007edf'\n                    anchors.centerIn: parent\n                    font.pointSize: 15\n                }\n            }\n            Rectangle {\n                width: 80 * scaleRatio; height: 29 * scaleRatio\n                border.width: 1\n                border.color: \"#007edf\"\n                color: splitState == 'splitted' ? \"#007edf\" : \"transparent\"\n                Text {\n                    text: \"Split\"\n                    color: splitState == 'splitted' ? \"white\" : \"#007edf\"\n                    anchors.centerIn: parent\n                    font.pointSize: 15\n                }\n            }\n            Rectangle {\n                width: 80 * scaleRatio; height: 29 * scaleRatio\n                color: splitState == 'viewer' ? \"#007edf\" : \"transparent\"\n                Text {\n                    text: \"Viewer\"\n                    color: splitState == 'viewer' ? \"white\" : \"#007edf\"\n                    anchors.centerIn: parent\n                    font.pointSize: 15\n                }\n            }\n        }\n\n    }\n    Rectangle {\n        id: mask\n        width: repeater.width\n        height: repeater.height\n        anchors.fill: repeater\n        radius: 5\n    }\n    OpacityMask {\n        visible: (parent.state === 'view')\n        anchors.fill: repeater\n        source: repeater\n        maskSource: mask\n    }\n\n    Row {\n        anchors.centerIn: parent\n        visible: (parent.state === 'view')\n        MouseArea {\n            width: 80 * scaleRatio\n            height: 29 * scaleRatio\n            onPressed: splitState = 'editor'\n        }\n        MouseArea {\n            width: 80 * scaleRatio\n            height: 29 * scaleRatio\n            onPressed: splitState = 'splitted'\n        }\n        MouseArea {\n            width: 80 * scaleRatio\n            height: 29 * scaleRatio\n            onPressed: splitState = 'viewer'\n        }\n    }\n\n    Text {\n        visible: (parent.state == 'selection')\n        anchors {\n            left: parent.left\n            verticalCenter: parent.verticalCenter\n            margins: 10 * scaleRatio \n        }\n        font { family: fontAwesome.name; pointSize: 26 }\n        text: \"\\uf057\"\n        color: 'grey'\n        MouseArea {\n            anchors.fill: parent\n            anchors.margins: -5 * scaleRatio\n            onPressed: { \n                navigationBar.state = 'view'; \n                editor.deselect();\n            }\n        }\n    }\n\n    Row {\n        anchors.centerIn: parent\n        visible: (parent.state === 'selection')\n        spacing: 20 * scaleRatio\n        Text {\n            visible: (editor.selectionStart !== editor.selectionEnd)\n            color: \"#007edf\"\n            font.pointSize: 17\n            text: \"Cut\"\n            MouseArea {\n                anchors.fill: parent\n                anchors.margins: -5 * scaleRatio\n                onPressed: editor.cut()\n            }\n        }\n        Text {\n            visible: (editor.selectionStart !== editor.selectionEnd)\n            color: \"#007edf\"\n            font.pointSize: 17\n            text: \"Copy\"\n            MouseArea {\n                anchors.fill: parent\n                anchors.margins: -5 * scaleRatio\n                onPressed: { \n                    editor.copy()\n                    editor.deselect()\n                }\n            }\n        }\n        Text {\n            visible: (editor.selectionStart === editor.selectionEnd)\n            color: \"#007edf\"\n            font.pointSize: 17\n            text: \"Select\"\n            MouseArea {\n                anchors.fill: parent\n                anchors.margins: -5 * scaleRatio\n                onPressed: editor.selectWord()\n            }\n        }\n        Text {\n            visible: (editor.selectionStart === editor.selectionEnd)\n            color: \"#007edf\"\n            font.pointSize: 17\n            text: \"Select All\"\n            MouseArea {\n                anchors.fill: parent\n                anchors.margins: -5 * scaleRatio\n                onPressed: editor.selectAll()\n            }\n        }\n        Text {\n            visible: (editor.canPaste === true)\n            color: \"#007edf\"\n            font.pointSize: 17\n            text: \"Paste\"\n            MouseArea {\n                anchors.fill: parent\n                anchors.margins: -5 * scaleRatio\n                onPressed: editor.paste()\n            }\n        }\n    }\n\n    states: [\n        State { \n            name: \"view\"\n        },\n        State {\n            name: \"selection\"\n        }\n    ]\n}\n"
  },
  {
    "path": "qml/QtWebKit.qml",
    "content": "import QtWebKit 3.0\nimport QtWebKit.experimental 1.0\n\nWebView {}\n"
  },
  {
    "path": "qml/QtWebView.qml",
    "content": "import QtWebView 1.0\n\nWebView {}\n"
  },
  {
    "path": "qml/assets.qrc",
    "content": "<!DOCTYPE RCC><RCC version=\"1.0\">\n<qresource prefix=\"/\"> \n    <file>main.qml</file>\n    <file>HttpServer.qml</file>\n    <file>BottomBar.qml</file>\n    <file>NaviBar.qml</file>\n    <file>CustomButton.qml</file>\n    <file>fontawesome-webfont.ttf</file>\n    <file>shadow.png</file>\n    <file>QtWebKit.qml</file>\n    <file>QtWebView.qml</file>\n</qresource>\n</RCC>\n"
  },
  {
    "path": "qml/main.qml",
    "content": "import QtQuick 2.0\nimport QtQuick.Window 2.0\n\nimport HttpServer 1.0\nimport QtQuick.LocalStorage 2.0\nimport DocumentHandler 1.0\n\nWindow {\n    id: root\n    width: Screen.width\n    height: Screen.height\n    visible: true\n    title: \"Terrarium - UI Prototyping Tool for Coders\"\n\n    property variant httpServer: {}\n    property variant httpd: {}\n    property string splitState: (root.width * scaleRatio > 600) ? 'splitted' : 'editor'\n    property variant os_type: { '0': 'macx', '1': 'ios', '2': 'android', '3': 'linux', '4': 'default' }\n    property variant platformSetting: {\n        'ios': { 'lineNumberSpacing': -1, 'lineNumberPadding' : 20, 'defaultFont': 'Courier New' },\n        'macx': { 'lineNumberSpacing': -1, 'lineNumberPadding' : 20, 'defaultFont': 'Menlo' },\n        'android': { 'lineNumberSpacing': 0, 'lineNumberPadding' : 20, 'defaultFont': 'Droid Sans Mono' },\n        'linux': { 'lineNumberSpacing': 0, 'lineNumberPadding' : 20, 'defaultFont': 'Droid Sans Mono' },\n        'default': { 'lineNumberSpacing': 0, 'lineNumberPadding' : 20, 'defaultFont': 'Droid Sans Mono' },\n    }\n    property variant lineNumberPadding: platformSetting[os_type[platform]]['lineNumberPadding']\n    property variant lineNumberSpacing: platformSetting[os_type[platform]]['lineNumberSpacing']\n    property variant scaleRatio: Screen.pixelDensity.toFixed(0) / 5\n\n    FontLoader { id: fontAwesome; source: \"fontawesome-webfont.ttf\" }\n\n    Component.onCompleted: {\n\n        // FIXME: workaround for Ubuntu Phone\n        if ((scaleRatio < 1) && (os_type[platform]==='linux')) scaleRatio = 2;\n\n        httpServer = Qt.createComponent(\"HttpServer.qml\");\n        if (httpServer.status == Component.Ready) {\n            httpd = httpServer.createObject(root, {'id': 'httpd'});\n            timer.running = true;\n        } else {\n            console.log('error loading http server')\n        }\n        var db = getDatabase();\n        db.transaction(\n                function(tx) {\n                    var result = tx.executeSql(\"SELECT * FROM previous\");\n                    for (var i=0; i < result.rows.length; i++) {\n                        editor.text = result.rows.item(i).editor\n                    }\n                    tx.executeSql(\"DROP TABLE IF EXISTS previous\");\n                }\n        );\n    }\n\n    Component.onDestruction: {\n        saveContent();\n    }\n\n    function saveContent() {\n        var db = getDatabase();\n        db.transaction(\n            function(tx) { tx.executeSql('insert into previous values (?);', editor.text); }\n        );\n    }\n\n    function getDatabase() {\n        var db = LocalStorage.openDatabaseSync(\"terrarium\", \"1.0\", \"file saving db\", 100000);\n        db.transaction(function(tx) {tx.executeSql('CREATE TABLE IF NOT EXISTS previous (editor TEXT)'); });\n        return db;\n    }\n\n    Timer {\n        id: timer\n        interval: 500; running: false; repeat: false\n        onTriggered: reloadView()\n    }\n\n    function reloadView() {\n        viewLoader.setSource('http://'+platformIP+':5000/?'+Math.random()) // workaround for cache\n    }\n\n    NaviBar {\n        state: \"view\"\n        id: navibar\n        z: 2\n    }\n\n    Item {\n        id: view\n        state: root.splitState\n        width: root.width/2\n        height: root.height\n        anchors { top: parent.top; right: parent.right; bottom: navibar.top; }\n        visible: opacity > 0 ? true : false\n\n        Rectangle {\n            color: 'grey'\n            visible: errorMessage.text != \"\"\n            anchors.horizontalCenter: parent.horizontalCenter\n            anchors.bottom: Screen.top\n            anchors.bottomMargin: errorMessage.text == \"\" ? 0 : -height\n            width: parent.width\n            height: errorMessage.height\n\n            Behavior on anchors.bottomMargin {\n                NumberAnimation { duration: 150; easing.type: Easing.OutQuad }\n            }\n\n            Text {\n                id: errorMessage\n                anchors { left: parent.left; right: parent.right; top: parent.top; margins: 20; topMargin: 10 }\n                font.pointSize: 20\n                wrapMode: Text.WordWrap\n                text: \"\"\n            }\n        }\n\n        Loader {\n            id: viewLoader\n            anchors.fill: parent\n            property variant errorLineNumber: 0\n            onStatusChanged: {\n                if (viewLoader.status == Loader.Error) {\n                    errorMessage.text = viewLoader.errorString().replace(/http:\\/\\/.*:5000\\/\\?.*?:/g, \"Line: \");\n\n                    // restart http server when connection refused\n                    var connectionRefused = /Connection refused/;\n                    if (connectionRefused.test(errorMessage.text)) {\n                        httpd.destroy();\n                        httpd = httpServer.createObject(root, {'id': 'httpd'});\n                        saveContent();\n                        reloadView();\n                    }\n\n                    errorLineNumber = errorMessage.text.match(/^Line: (.*?) /)[1];\n                    lineNumberRepeater.itemAt(errorLineNumber - 1).bgcolor = 'red'\n                } else {\n                    errorMessage.text = \"\";\n                    if (errorLineNumber > 0)\n                        lineNumberRepeater.itemAt(errorLineNumber - 1).bgcolor = 'transparent'\n                }\n            }\n        }\n\n        states: [\n            State {\n                name: \"splitted\"\n                PropertyChanges { target: view; width: root.width/2 }\n                PropertyChanges { target: view; opacity: 1 }\n                PropertyChanges { target: background; width: root.width/2 }\n                PropertyChanges { target: background; opacity: 1 }\n            },\n            State {\n                name: \"editor\"\n                PropertyChanges { target: view; width: 0 }\n                PropertyChanges { target: view; opacity: 0 }\n                PropertyChanges { target: background; width: root.width }\n                PropertyChanges { target: background; opacity: 1 }\n            },\n            State {\n                name: \"viewer\"\n                PropertyChanges { target: view; width: root.width }\n                PropertyChanges { target: view; opacity: 1 }\n                PropertyChanges { target: background; width: 0 }\n                PropertyChanges { target: background; opacity: 0 }\n            }\n        ]\n        transitions: [\n            Transition {\n                to: \"*\"\n                NumberAnimation { target: view; properties: \"width\"; duration: 300; easing.type: Easing.InOutQuad; }\n                NumberAnimation { target: background; properties: \"width\"; duration: 300; easing.type: Easing.InOutQuad; }\n            }\n        ]\n    }\n\n    Rectangle {\n        id: background\n        width: root.width/2\n        height: root.height\n        anchors { top: parent.top; left: parent.left; bottom: navibar.top}\n        color: '#1d1f21'\n        visible: opacity > 0 ? true : false\n\n        Flickable {\n            id: flickable\n            anchors { fill: parent; }\n            flickableDirection: Flickable.VerticalFlick\n            boundsBehavior: Flickable.DragOverBounds\n            contentWidth: parent.width\n            contentHeight: editor.height\n            clip: true\n\n            Column {\n                id: lineNumber\n                anchors { margins: 20; left: parent.left; top: parent.top }\n                spacing: lineNumberSpacing\n                Repeater {\n                    id: lineNumberRepeater\n                    model: editor.lineCount\n                    Text {\n                        property alias bgcolor: rect.color\n                        width: 20\n                        text: index + 1\n                        color: 'lightgray'\n                        font.pointSize: editor.font.pointSize\n                        horizontalAlignment: TextEdit.AlignHCenter\n                        Rectangle {\n                            id: rect\n                            color: 'transparent'\n                            anchors.fill: parent\n                            opacity: 0.5\n                        }\n                    }\n                }\n            }\n\n            Rectangle {\n                id: editorCurrentLineHighlight\n                anchors {\n                    left: lineNumber.right\n                    margins: lineNumberPadding\n                }\n                visible: editor.focus\n                width: editor.width\n                height: editor.cursorRectangle.height\n                y: editor.cursorRectangle.y + lineNumberPadding\n                color: '#454545'\n            }\n\n            TextEdit {\n                id: editor\n                anchors {\n                    margins: lineNumberPadding\n                    left: lineNumber.right; right: parent.right; top: parent.top\n                }\n                wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere;\n                renderType: Text.NativeRendering\n                onTextChanged: timer.restart();\n\n                onSelectedTextChanged: {\n                    if (editor.selectedText === \"\") {\n                        navibar.state = 'view'\n                    }\n                }\n                // FIXME: stupid workaround for indent\n                Keys.onPressed: {\n                    if (event.key == Qt.Key_BraceRight) {\n                        editor.select(0, cursorPosition)\n                        var previousContent = editor.selectedText.split(/\\r\\n|\\r|\\n/)\n                        editor.deselect()\n                        var currentLine = previousContent[previousContent.length - 1]\n                        var leftBrace = /{/, rightBrace = /}/;\n                        if (!leftBrace.test(currentLine)) {\n                            editor.remove(cursorPosition, cursorPosition - currentLine.length);\n                            currentLine = currentLine.toString().replace(/ {1,4}$/, \"\");\n                            editor.insert(cursorPosition, currentLine);\n                        }\n                    }\n                }\n                Keys.onReturnPressed: {\n                    editor.select(0, cursorPosition)\n                    var previousContent = editor.selectedText.split(/\\r\\n|\\r|\\n/)\n                    editor.deselect()\n                    var currentLine = previousContent[previousContent.length - 1]\n                    var leftBrace = /{/, rightBrace = /}/;\n                    editor.insert(cursorPosition, \"\\n\")\n                    var whitespaceAppend = currentLine.match(new RegExp(/^[ \\t]*/))  // whitespace\n                    if (leftBrace.test(currentLine)) // indent\n                        whitespaceAppend += \"    \";\n                    editor.insert(cursorPosition, whitespaceAppend)\n                }\n\n                // style from Atom dark theme:\n                // https://github.com/atom/atom-dark-syntax/blob/master/stylesheets/syntax-variables.less\n                color: '#c5c8c6'\n                selectionColor: '#0C75BC'\n                selectByMouse: true\n                font { pointSize: 18; family: platformSetting[os_type[platform]]['defaultFont'] }\n\n                text: documentHandler.text\n                inputMethodHints: Qt.ImhNoPredictiveText\n\n                DocumentHandler {\n                    id: documentHandler\n                    target: editor\n                    Component.onCompleted: {\n                        documentHandler.text = \"import QtQuick 2.0\\n\\nRectangle { \\n    color: '#FEEB75'\" +\n                            \"\\n    Text { \\n        anchors.centerIn: parent\" +\n                            \"\\n        text: 'Hello, World!' \\n    } \\n}\"\n                    }\n                }\n\n                // FIXME: add selection / copy / paste popup\n                MouseArea {\n                    id: handler\n                    // FIXME: disable on desktop\n                    enabled: os_type[platform] != 'macx'\n                    anchors.fill: parent\n                    propagateComposedEvents: true\n                    onPressed: {\n                        editor.cursorPosition = parent.positionAt(mouse.x, mouse.y);\n                        editor.focus = true\n                        navibar.state = 'view'\n                        Qt.inputMethod.show();\n                    }\n                    onPressAndHold: {\n                        navibar.state = 'selection'\n                        Qt.inputMethod.hide();\n                    }\n                    onDoubleClicked: {\n                        editor.selectWord()\n                        navibar.state = 'selection'\n                    }\n                }\n            } // end of editor\n\n        }\n    }\n    Image {\n        fillMode: Image.TileHorizontally\n        source: \"shadow.png\"\n        width: navibar.width\n        anchors.bottom: navibar.top\n        height: 6\n    }\n}\n"
  },
  {
    "path": "src/documenthandler.cpp",
    "content": "/****************************************************************************\n**\n** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).\n** Contact: http://www.qt-project.org/legal\n**\n** This file is part of the Qt Quick Controls module of the Qt Toolkit.\n**\n** $QT_BEGIN_LICENSE:BSD$\n** You may use this file under the terms of the BSD license as follows:\n**\n** \"Redistribution and use in source and binary forms, with or without\n** modification, are permitted provided that the following conditions are\n** met:\n**   * Redistributions of source code must retain the above copyright\n**     notice, this list of conditions and the following disclaimer.\n**   * Redistributions in binary form must reproduce the above copyright\n**     notice, this list of conditions and the following disclaimer in\n**     the documentation and/or other materials provided with the\n**     distribution.\n**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names\n**     of its contributors may be used to endorse or promote products derived\n**     from this software without specific prior written permission.\n**\n**\n** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n** \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\"\n**\n** $QT_END_LICENSE$\n**\n****************************************************************************/\n\n#include \"documenthandler.h\"\n\n#include <QtGui/QTextDocument>\n#include <QtGui/QTextCursor>\n#include <QtGui/QFontDatabase>\n#include <QtCore/QFileInfo>\n\nDocumentHandler::DocumentHandler()\n    : m_target(0)\n    , m_doc(0)\n    , m_cursorPosition(-1)\n    , m_selectionStart(0)\n    , m_selectionEnd(0)\n    , m_highlighter(0)\n{\n}\n\nvoid DocumentHandler::setTarget(QQuickItem *target)\n{\n    m_doc = 0;\n    m_highlighter = 0;\n    m_target = target;\n    if (!m_target)\n        return;\n\n    QVariant doc = m_target->property(\"textDocument\");\n    if (doc.canConvert<QQuickTextDocument*>()) {\n        QQuickTextDocument *qqdoc = doc.value<QQuickTextDocument*>();\n        if (qqdoc) {\n            m_doc = qqdoc->textDocument();\n            m_highlighter = new QMLHighlighter(m_doc);\n            //m_highlighter = new Highlighter(m_doc);\n        }\n    }\n    emit targetChanged();\n}\n\nvoid DocumentHandler::setText(const QString &arg)\n{\n    if (m_text != arg) {\n        m_text = arg;\n        emit textChanged();\n    }\n}\n\nQString DocumentHandler::text() const\n{\n    return m_text;\n}\n\nvoid DocumentHandler::setCursorPosition(int position)\n{\n    if (position == m_cursorPosition)\n        return;\n\n    m_cursorPosition = position;\n\n    reset();\n}\n\nvoid DocumentHandler::reset()\n{\n\n}\n\n\nQTextCursor DocumentHandler::textCursor() const\n{\n    QTextCursor cursor = QTextCursor(m_doc);\n    if (m_selectionStart != m_selectionEnd) {\n        cursor.setPosition(m_selectionStart);\n        cursor.setPosition(m_selectionEnd, QTextCursor::KeepAnchor);\n    } else {\n        cursor.setPosition(m_cursorPosition);\n    }\n    return cursor;\n}\n\nvoid DocumentHandler::mergeFormatOnWordOrSelection(const QTextCharFormat &format)\n{\n    QTextCursor cursor = textCursor();\n    if (!cursor.hasSelection())\n        cursor.select(QTextCursor::WordUnderCursor);\n    cursor.mergeCharFormat(format);\n}\n\nvoid DocumentHandler::setSelectionStart(int position)\n{\n    m_selectionStart = position;\n}\n\nvoid DocumentHandler::setSelectionEnd(int position)\n{\n    m_selectionEnd = position;\n}\n\n"
  },
  {
    "path": "src/documenthandler.h",
    "content": "/****************************************************************************\n**\n** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).\n** Contact: http://www.qt-project.org/legal\n**\n** This file is part of the Qt Quick Controls module of the Qt Toolkit.\n**\n** $QT_BEGIN_LICENSE:BSD$\n** You may use this file under the terms of the BSD license as follows:\n**\n** \"Redistribution and use in source and binary forms, with or without\n** modification, are permitted provided that the following conditions are\n** met:\n**   * Redistributions of source code must retain the above copyright\n**     notice, this list of conditions and the following disclaimer.\n**   * Redistributions in binary form must reproduce the above copyright\n**     notice, this list of conditions and the following disclaimer in\n**     the documentation and/or other materials provided with the\n**     distribution.\n**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names\n**     of its contributors may be used to endorse or promote products derived\n**     from this software without specific prior written permission.\n**\n**\n** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n** \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\"\n**\n** $QT_END_LICENSE$\n**\n****************************************************************************/\n\n#ifndef DOCUMENTHANDLER_H\n#define DOCUMENTHANDLER_H\n\n#include <QQuickTextDocument>\n#include \"qmlhighlighter.h\"\n#include <QtGui/QTextCharFormat>\n#include <QtCore/QTextCodec>\n\n#include <qqmlfile.h>\n\nQT_BEGIN_NAMESPACE\nclass QTextDocument;\nQT_END_NAMESPACE\n\nclass DocumentHandler : public QObject\n{\n    Q_OBJECT\n\n    Q_ENUMS(HAlignment)\n\n    Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged)\n    Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)\n    Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged)\n    Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged)\n\n    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)\n\npublic:\n    DocumentHandler();\n\n    QQuickItem *target() { return m_target; }\n\n    void setTarget(QQuickItem *target);\n\n    void setCursorPosition(int position);\n    void setSelectionStart(int position);\n    void setSelectionEnd(int position);\n\n    int cursorPosition() const { return m_cursorPosition; }\n    int selectionStart() const { return m_selectionStart; }\n    int selectionEnd() const { return m_selectionEnd; }\n\n    QString text() const;\n\npublic Q_SLOTS:\n    void setText(const QString &arg);\n\nQ_SIGNALS:\n    void targetChanged();\n    void cursorPositionChanged();\n    void selectionStartChanged();\n    void selectionEndChanged();\n    void textChanged();\n\nprivate:\n    void reset();\n\n\n    QTextCursor textCursor() const;\n    void mergeFormatOnWordOrSelection(const QTextCharFormat &format);\n\n    QQuickItem *m_target;\n    QTextDocument *m_doc;\n\n    int m_cursorPosition;\n    int m_selectionStart;\n    int m_selectionEnd;\n\n    QMLHighlighter *m_highlighter;\n\n    QString m_text;\n\n};\n\n#endif\n"
  },
  {
    "path": "src/main.cpp",
    "content": "#include <QtQuick/QQuickView>\n#include <QtGui/QGuiApplication>\n#include <QtQml>\n#if QT_VERSION > QT_VERSION_CHECK(5, 1, 0)\n#include <QQmlApplicationEngine>\n#endif\n#include \"qhttpserver/src/qhttpserver.h\"\n#include \"qhttpserver/src/qhttprequest.h\"\n#include \"qhttpserver/src/qhttpresponse.h\"\n#include \"qhttpserver/src/qhttpconnection.h\"\n#include \"documenthandler.h\"\n#include \"quickitemgrabber.h\"\n#if USE_WEBENGINE\n#include <qtwebengineglobal.h>\n#endif\n\nint main(int argc, char *argv[])\n{\n    QStringList imports, plugins;\n\n    QGuiApplication app(argc, argv);\n    app.setApplicationName(\"Terrarium\");\n    app.setOrganizationName(\"terrariumapp\");\n    app.setOrganizationDomain(\"terrariumapp.com\");\n\n#if defined(Q_OS_MACX)\n    int platformId = 0;\n#elif defined(Q_OS_IOS)\n    int platformId = 1;\n#elif defined(Q_OS_ANDROID)\n    int platformId = 2;\n#elif defined(Q_OS_LINUX)\n    int platformId = 3;\n#else\n    int platformId = 4;\n#endif \n\n    qmlRegisterType<QHttpServer>(\"HttpServer\", 1, 0, \"HttpServer\");\n    qmlRegisterType<DocumentHandler>(\"DocumentHandler\", 1, 0, \"DocumentHandler\");\n    qmlRegisterUncreatableType<QHttpRequest>(\"HttpServer\", 1, 0, \"HttpRequest\", \"Do not create HttpRequest directly\");\n    qmlRegisterUncreatableType<QHttpResponse>(\"HttpServer\", 1, 0, \"HttpResponse\", \"Do not create HttpResponse directly\");\n\n    QString platformIP; \n    foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) {\n        if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost))\n             platformIP = address.toString();\n    }\n\n    // Handle command line arguments\n    const QStringList arguments = QCoreApplication::arguments();\n    for (int i = 1, size = arguments.size(); i < size; ++i) {\n      const QString lowerArgument = arguments.at(i).toLower();\n      if (lowerArgument == QLatin1String(\"-i\") && i + 1 < size) {\n        imports.append(arguments.at(++i));\n      } else if (lowerArgument == QLatin1String(\"-p\") && i + 1 < size) {\n        plugins.append(arguments.at(++i));\n      }\n    }\n\n#if USE_WEBENGINE\n    QtWebEngine::initialize();\n#endif\n\n#if QT_VERSION > QT_VERSION_CHECK(5, 1, 0)\n    QQmlApplicationEngine engine;\n\n    for(int i = 0; i < imports.size(); ++i) {\n      engine.addImportPath(imports[i]);\n    }\n    for(int i = 0; i < plugins.size(); ++i) {\n      engine.addPluginPath(plugins[i]);\n    }\n    engine.rootContext()->setContextProperty(\"platform\", QVariant::fromValue(platformId));\n    engine.rootContext()->setContextProperty(\"platformIP\", QVariant::fromValue(platformIP));\n    engine.rootContext()->setContextProperty(\"Grabber\",new QuickItemGrabber(&app));\n    engine.load(QUrl(\"qrc:///main.qml\"));\n#else\n    QQuickView view;\n    view.engine()->rootContext()->setContextProperty(\"platform\", QVariant::fromValue(platformId));\n    view.engine()->rootContext()->setContextProperty(\"platformIP\", QVariant::fromValue(platformIP));\n    view.setSource(QUrl(\"qrc:///main.qml\"));\n    view.show();\n#endif \n    return app.exec();\n}\n"
  },
  {
    "path": "src/qmlhighlighter.cpp",
    "content": "#include \"qmlhighlighter.h\"\n#include <QColor>\n\nvoid QMLHighlighter::highlightBlock(const QString &text)\n{\n    QTextCharFormat keywordFormat;\n    keywordFormat.setForeground(QColor(\"#d7ffaf\")); // Identifier\n    QTextCharFormat typeFormat;\n    typeFormat.setForeground(QColor(\"#afffff\")); // Type\n    QTextCharFormat commentFormat;\n    commentFormat.setForeground(QColor(\"#8a8a8a\")); // Comment \n    QTextCharFormat numericConstantFormat;\n    numericConstantFormat.setForeground(QColor(\"#ffffd7\")); // Constant \n    QTextCharFormat stringConstantFormat;\n    stringConstantFormat.setForeground(QColor(\"#ffffd7\")); \n\n    QRegExp type(\"\\\\b[A-Z][A-Za-z]+\\\\b\");\n    QRegExp numericConstant(\"[0-9]+\\\\.?[0-9]*\");\n    QRegExp stringConstant(\"['\\\"].*['\\\"]\");//Not multiline strings, but they're rare\n    QRegExp lineComment(\"//[^\\n]*\");\n    QRegExp startComment(\"/\\\\*\");\n    QRegExp endComment(\"\\\\*/\");\n\n    applyBasicHighlight(text, type, typeFormat);\n    applyBasicHighlight(text, numericConstant, numericConstantFormat);\n    applyBasicHighlight(text, stringConstant, stringConstantFormat);\n    applyBasicHighlight(text, lineComment, commentFormat);\n\n    setCurrentBlockState(0);\n\n    int startIndex = 0;\n    if (previousBlockState() != 1)\n        startIndex = text.indexOf(startComment);\n\n    while (startIndex >= 0) {\n        int endIndex = text.indexOf(endComment, startIndex);\n        int commentLength;\n        if (endIndex == -1) {\n            setCurrentBlockState(1);\n            commentLength = text.length() - startIndex;\n        } else {\n            commentLength = endIndex - startIndex\n                + endComment.matchedLength();\n        }\n        setFormat(startIndex, commentLength, commentFormat);\n        startIndex = text.indexOf(startComment,\n                startIndex + commentLength);\n    }\n\n}\n\nvoid QMLHighlighter::applyBasicHighlight(const QString &text, QRegExp &re, QTextCharFormat &format)\n{\n    int index = text.indexOf(re);\n    while (index >= 0) {\n        int length = re.matchedLength();\n        setFormat(index, length, format);\n        index = text.indexOf(re, index + length);\n    }\n}\n"
  },
  {
    "path": "src/qmlhighlighter.h",
    "content": "#include <QSyntaxHighlighter>\n\nclass QMLHighlighter : public QSyntaxHighlighter\n{\n    Q_OBJECT\npublic:\n        //BUG: QSyntaxHighlighter(0) crashes!\n    QMLHighlighter(QObject* parent=new QObject()) : QSyntaxHighlighter(parent)\n    {\n\n    }\n    QMLHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent)\n    {\n    }\nprotected:\n    virtual void highlightBlock(const QString &text);\nprivate:\n    void applyBasicHighlight(const QString &text, QRegExp &re, QTextCharFormat &format);\n};\n"
  },
  {
    "path": "src/quickitemgrabber.cpp",
    "content": "/** Author:  Ben Lau (https://github.com/benlau)\n */\n#include <QtGlobal>\n#include <QtCore>\n#include <QQuickWindow>\n#include <QOpenGLFunctions>\n#include \"quickitemgrabber.h\"\n\n#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))\n#include <private/qquickitem_p.h>\n#include <private/qquickshadereffectsource_p.h>\n#else\n// Added since Qt 5.4\n#include <QQuickItemGrabResult>\n#endif\n\n\nQuickItemGrabber::QuickItemGrabber(QObject *parent) :\n    QObject(parent)\n{\n    m_busy = false;\n    m_ready = false;\n}\n\nbool QuickItemGrabber::busy() const\n{\n    return m_busy;\n}\n\nbool QuickItemGrabber::grab(QQuickItem *target,QSize targetSize)\n{\n    if (m_busy ||\n        target == 0  ||\n        !target->window() ||\n        !target->window()->isVisible() ) {\n        return false;\n    }\n    m_ready = false;\n    m_targetSize = targetSize;\n    m_target = target;\n    m_window = target->window();\n\n    if (m_targetSize.isEmpty()) {\n        m_targetSize = QSize(m_target->width(),m_target->height());\n    }\n\n#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))\n\n    QQuickItemPrivate::get(m_target)->refFromEffectItem(false);\n\n    m_target->window()->update();\n\n    connect(m_window.data(),SIGNAL(beforeSynchronizing()),\n            this,SLOT(ready()),Qt::DirectConnection);\n\n    connect(m_window.data(),SIGNAL(afterRendering()),\n            this,SLOT(capture()),Qt::DirectConnection);\n#else\n\n    result = target->grabToImage(m_targetSize);\n\n    if (result.isNull()) {\n        qDebug() << \"Can't grab target item\";\n        return false;\n    }\n\n    connect(result.data(),SIGNAL(ready()),\n            this,SLOT(onGrabResultReady()));\n#endif\n\n    setBusy(true);\n\n    return true;\n}\n\nbool QuickItemGrabber::save(QString filename)\n{\n    if (m_image.isNull()) {\n        qWarning() << \"QuickItemGrabber::save() - The image is null\";\n        return false;\n    }\n    return m_image.save(filename);\n}\n\nvoid QuickItemGrabber::ready()\n{\n    m_ready = true;\n}\n\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))\nvoid QuickItemGrabber::onGrabResultReady()\n{\n    QImage image =  result->image();\n    setImage(image);\n\n    result.clear();\n    setBusy(false);\n    emit grabbed();\n}\n#endif\n\nQImage QuickItemGrabber::image() const\n{\n    return m_image;\n}\n\n#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))\n\nvoid QuickItemGrabber::capture()\n{\n    if (!m_ready) { // It is not ready yet\n        return;\n    }\n\n    if (m_target) { // Just in case the item is destroyed before rendering completed\n        QOpenGLContext* context = QOpenGLContext::currentContext();\n\n        QQuickShaderEffectTexture *m_texture = new QQuickShaderEffectTexture(m_target);\n        m_texture->setItem(QQuickItemPrivate::get(m_target)->itemNode());\n\n        // Set the source rectangle\n        QSize sourceSize;\n        sourceSize = QSize(m_target->width(),m_target->height());\n        m_texture->setRect(QRectF(0, sourceSize.height(), sourceSize.width(), -sourceSize.height()));\n\n        QSize maxSize = maxTextureSize();\n        /*\n        if (!maxSize.isValid()) {\n            GLint param;\n\n            QOpenGLFunctions glFuncs(context);\n            glFuncs.glGetIntegerv(GL_MAX_TEXTURE_SIZE,&param);\n\n            maxSize = QSize(param,param);\n            setMaxTextureSize(maxSize);\n        }\n\n        QSize textureSize = m_targetSize;\n        if (maxSize.isValid() &&\n                (textureSize.width() > maxSize.width() ||\n                textureSize.height() > maxSize.height())) {\n            FVRectToRect scaler;\n            scaler.scaleToFit(textureSize,maxSize);\n            // The required size is larger than max texture size.\n            qDebug() << \"Downgrade target image from\" << textureSize << scaler.transformedRect().toRect().size();\n            textureSize = scaler.transformedRect().toRect().size();\n        }\n        */\n\n        QSize expectedSize = textureSize();\n\n        QSGContext *sg = QSGRenderContext::from(context)->sceneGraphContext();\n        const QSize minSize = sg->minimumFBOSize();\n        m_texture->setSize(QSize(qMax<int>(minSize.width(), expectedSize.width()),\n                                  qMax<int>(minSize.height(), expectedSize.height())));\n        m_texture->scheduleUpdate();\n        m_texture->updateTexture();\n        QImage image =  m_texture->toImage();\n        setImage(image);\n\n        delete m_texture;\n        m_texture = 0;\n    }\n\n    disconnect(m_window.data(), SIGNAL(afterRendering()), this, SLOT(capture()));\n    disconnect(m_window.data(), SIGNAL(beforeSynchronizing()), this, SLOT(ready()));\n\n    setBusy(false);\n    emit grabbed();\n}\n#endif\n\nvoid QuickItemGrabber::setBusy(bool value)\n{\n    if (m_busy != value) {\n        m_busy = value;\n        emit busyChanged();\n    }\n}\n\nvoid QuickItemGrabber::setImage(QImage value)\n{\n    m_image = value;\n    emit imageChanged();\n}\n\nvoid QuickItemGrabber::clear()\n{\n    setImage(QImage());\n}\n\n"
  },
  {
    "path": "src/quickitemgrabber.h",
    "content": "/** Author:  Ben Lau (https://github.com/benlau)\n */\n#ifndef QUICKITEMGRABBER_H\n#define QUICKITEMGRABBER_H\n\n#include <QObject>\n#include <QQuickItem>\n#include <QImage>\n#include <QPointer>\n\n/// QuickItemGrabber grabs QQuickItem into QImage\n\nclass QuickItemGrabber : public QObject\n{\n    Q_OBJECT\n    /// \"Busy\" flag. It is TRUE if the grabber is running. It won't accept another request when busy.\n    Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)\n\n    /// The grabbed image\n    Q_PROPERTY(QImage image READ image NOTIFY imageChanged)\n\npublic:\n    explicit QuickItemGrabber(QObject *parent = 0);\n\n    bool busy() const;\n    QImage image() const;\n\n    /// Grab the target item and save to \"image\" property\n    Q_INVOKABLE bool grab(QQuickItem* target,QSize targetSize = QSize());\n\n    /// Save the grabbed image into file. It is a blocked call.\n    Q_INVOKABLE bool save(QString filename);\n\n    /// Clear the captured image.\n    Q_INVOKABLE void clear();\n\nsignals:\n    void busyChanged();\n    void imageChanged();\n    void grabbed();\n    void maxTextureSizeChanged();\n\nprivate:\n    // Ready for capture\n    Q_INVOKABLE void ready();\n\n#if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0))\n    Q_INVOKABLE void capture();\n#else\n    Q_INVOKABLE void onGrabResultReady();\n    QSharedPointer<QQuickItemGrabResult> result;\n#endif\n\n    void setBusy(bool value);\n    void setImage(QImage value);\n\n    bool m_busy;\n    bool m_ready;\n    QSize m_targetSize;\n    QPointer<QQuickItem> m_target;\n    QPointer<QQuickWindow> m_window;\n    QImage m_image;\n};\n\n#endif // QUICKITEMGRABBER_H\n"
  },
  {
    "path": "terrarium-app.pro",
    "content": "TEMPLATE = app\nTARGET = Terrarium\nQT += qml quick network sql\nwebengine {\n    QT += webengine\n    DEFINES += USE_WEBENGINE\n}\n\nSOURCES += src/main.cpp \\\n    src/qmlhighlighter.cpp \\\n    src/documenthandler.cpp \\\n    qhttpserver/src/qhttpconnection.cpp \\\n    qhttpserver/src/qhttprequest.cpp \\\n    qhttpserver/src/qhttpresponse.cpp \\\n    qhttpserver/src/qhttpserver.cpp \\\n    qhttpserver/http-parser/http_parser.c \\\n    src/quickitemgrabber.cpp\n\nHEADERS += qhttpserver/src/qhttpserver.h \\\n    qhttpserver/src//qhttpresponse.h \\\n    qhttpserver/src//qhttprequest.h \\\n    src/qmlhighlighter.h \\\n    src/documenthandler.h \\\n    qhttpserver/src//qhttpconnection.h \\ \n    src/quickitemgrabber.h\n\nINCLUDEPATH += ./qhttpserver/http-parser/\nRESOURCES += qml/assets.qrc\n\nandroid {\n    ANDROID_PACKAGE_SOURCE_DIR = ./platform/android\n}\n\nmacx {\n    QMAKE_MAC_SDK = macosx10.10\n    QMAKE_INFO_PLIST = platform/mac/Info.plist\n    ICON = platform/mac/icon.icns\n    #QMAKE_POST_LINK += macdeployqt Terrarium.app/ -qmldir=qml/ -verbose=1 -dmg\n}\n\nios {\n    QMAKE_INFO_PLIST = platform/ios/Info.plist\n}\n"
  }
]