aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE.GPLv3684
-rw-r--r--README.md54
-rw-r--r--base.pri3
-rw-r--r--doc/Doxyfile1846
-rw-r--r--doc/classes.qdoc98
-rw-r--r--doc/examples.qdoc40
-rw-r--r--doc/examples/contentplugin.qdoc110
-rw-r--r--doc/images/contentplugin-example.pngbin0 -> 89748 bytes
-rw-r--r--doc/index.qdoc59
-rw-r--r--doc/project.qdoc49
-rw-r--r--doc/qmllive.qdocconf84
-rw-r--r--doc/template/style/offline.css428
-rw-r--r--examples/contentplugin/contentplugin.pro13
-rw-r--r--examples/contentplugin/mycontentadapterplugin.cpp73
-rw-r--r--examples/contentplugin/mycontentadapterplugin.h54
-rw-r--r--examples/contentplugin/plugin.qml45
-rw-r--r--examples/contentplugin/res.qrc5
-rw-r--r--header.GPL3_PELAGICORE27
-rw-r--r--icons/appicon.icnsbin0 -> 84380 bytes
-rw-r--r--icons/appicon.icobin0 -> 1150 bytes
-rw-r--r--icons/appicon.rc1
-rw-r--r--qmllive.pri23
-rw-r--r--qmllive.pro39
-rw-r--r--src/bench/allhostswidget.cpp106
-rw-r--r--src/bench/allhostswidget.h66
-rw-r--r--src/bench/autodiscoveryhostsdialog.cpp72
-rw-r--r--src/bench/autodiscoveryhostsdialog.h61
-rw-r--r--src/bench/autodiscoveryhostsdialog.ui87
-rw-r--r--src/bench/bench.pro61
-rw-r--r--src/bench/benchlivenodeengine.cpp169
-rw-r--r--src/bench/benchlivenodeengine.h75
-rw-r--r--src/bench/benchquickview.cpp45
-rw-r--r--src/bench/benchquickview.h46
-rw-r--r--src/bench/directorypreviewadapter.cpp81
-rw-r--r--src/bench/directorypreviewadapter.h54
-rw-r--r--src/bench/dummydelegate.cpp51
-rw-r--r--src/bench/dummydelegate.h44
-rw-r--r--src/bench/host.cpp252
-rw-r--r--src/bench/host.h131
-rw-r--r--src/bench/hostdiscoverymanager.cpp123
-rw-r--r--src/bench/hostdiscoverymanager.h68
-rw-r--r--src/bench/hostmanager.cpp162
-rw-r--r--src/bench/hostmanager.h72
-rw-r--r--src/bench/hostmodel.cpp292
-rw-r--r--src/bench/hostmodel.h78
-rw-r--r--src/bench/hostsoptionpage.cpp273
-rw-r--r--src/bench/hostsoptionpage.h83
-rw-r--r--src/bench/hostsoptionpage.ui276
-rw-r--r--src/bench/hostwidget.cpp431
-rw-r--r--src/bench/hostwidget.h128
-rw-r--r--src/bench/httpproxyoptionpage.cpp78
-rw-r--r--src/bench/httpproxyoptionpage.h53
-rw-r--r--src/bench/httpproxyoptionpage.ui86
-rw-r--r--src/bench/importpathoptionpage.cpp99
-rw-r--r--src/bench/importpathoptionpage.h56
-rw-r--r--src/bench/importpathoptionpage.ui66
-rw-r--r--src/bench/main.cpp153
-rw-r--r--src/bench/mainwindow.cpp455
-rw-r--r--src/bench/mainwindow.h119
-rw-r--r--src/bench/optionsdialog.cpp106
-rw-r--r--src/bench/optionsdialog.h69
-rw-r--r--src/bench/optionsdialog.ui96
-rw-r--r--src/bench/previewimageprovider.cpp131
-rw-r--r--src/bench/previewimageprovider.h58
-rw-r--r--src/bench/qmlpreviewadapter.cpp176
-rw-r--r--src/bench/qmlpreviewadapter.h61
-rw-r--r--src/bench/reload.pro33
-rw-r--r--src/bench/reload.qrc8
-rw-r--r--src/concept.dox10
-rw-r--r--src/contentadapterinterface.h71
-rw-r--r--src/contentpluginfactory.cpp91
-rw-r--r--src/contentpluginfactory.h56
-rw-r--r--src/fontadapter.cpp121
-rw-r--r--src/fontadapter.h60
-rw-r--r--src/imageadapter.cpp77
-rw-r--r--src/imageadapter.h50
-rw-r--r--src/images/client.pngbin0 -> 60531 bytes
-rw-r--r--src/images/concept.pngbin0 -> 68871 bytes
-rw-r--r--src/images/creator_result.pngbin0 -> 153682 bytes
-rw-r--r--src/images/creator_shortcut.pngbin0 -> 52276 bytes
-rw-r--r--src/images/creator_tool.pngbin0 -> 96025 bytes
-rw-r--r--src/images/favicon.pngbin0 -> 439 bytes
-rw-r--r--src/images/graphics_sheets.pngbin0 -> 61039 bytes
-rw-r--r--src/images/icon_failover.pngbin0 -> 757 bytes
-rw-r--r--src/images/icon_offline.pngbin0 -> 682 bytes
-rw-r--r--src/images/icon_online.pngbin0 -> 879 bytes
-rw-r--r--src/images/qml_sheets.pngbin0 -> 100303 bytes
-rw-r--r--src/images/remote.pngbin0 -> 81971 bytes
-rw-r--r--src/images/runtime.pngbin0 -> 193192 bytes
-rw-r--r--src/images/server.pngbin0 -> 35739 bytes
-rw-r--r--src/images/workbench.pngbin0 -> 335948 bytes
-rw-r--r--src/ipc/ipc.dox14
-rw-r--r--src/ipc/ipc.pri11
-rw-r--r--src/ipc/ipcclient.cpp384
-rw-r--r--src/ipc/ipcclient.h86
-rw-r--r--src/ipc/ipcconnection.cpp157
-rw-r--r--src/ipc/ipcconnection.h60
-rw-r--r--src/ipc/ipcserver.cpp127
-rw-r--r--src/ipc/ipcserver.h58
-rw-r--r--src/lib/lib.pro14
-rw-r--r--src/lib/qmllive.cpp35
-rw-r--r--src/lib/qmllive.h42
-rw-r--r--src/lib/qmllive_global.h42
-rw-r--r--src/livehubengine.cpp160
-rw-r--r--src/livehubengine.h65
-rw-r--r--src/livenodeengine.cpp477
-rw-r--r--src/livenodeengine.h134
-rw-r--r--src/livert.qrc18
-rw-r--r--src/livert/error_qt5.qml55
-rw-r--r--src/livert/error_qt5_controls.qml59
-rw-r--r--src/livert/folderview_qt5.qml324
-rw-r--r--src/livert/folderview_qt5_controls.qml205
-rw-r--r--src/livert/fontviewer_qt5.qml387
-rw-r--r--src/livert/fontviewer_qt5_controls.qml350
-rw-r--r--src/livert/imageviewer_qt5.qml52
-rw-r--r--src/livert/imageviewer_qt5_controls.qml52
-rw-r--r--src/livert/logo.pngbin0 -> 13470 bytes
-rw-r--r--src/livert/no.pngbin0 -> 154749 bytes
-rw-r--r--src/liveruntime.cpp77
-rw-r--r--src/liveruntime.h61
-rw-r--r--src/logger.cpp119
-rw-r--r--src/logger.h57
-rw-r--r--src/logreceiver.cpp102
-rw-r--r--src/logreceiver.h62
-rw-r--r--src/mainpage.dox16
-rw-r--r--src/previewGenerator/main.cpp164
-rw-r--r--src/previewGenerator/previewGenerator.pro13
-rw-r--r--src/qmlhelper.cpp88
-rw-r--r--src/qmlhelper.h50
-rw-r--r--src/remotelogger.cpp99
-rw-r--r--src/remotelogger.h56
-rw-r--r--src/remotepublisher.cpp243
-rw-r--r--src/remotepublisher.h82
-rw-r--r--src/remotereceiver.cpp226
-rw-r--r--src/remotereceiver.h87
-rw-r--r--src/runtime/main.cpp180
-rw-r--r--src/runtime/qml.qrc6
-rw-r--r--src/runtime/qmlsplash/pelagicore-symbol-white-rgb.pngbin0 -> 18683 bytes
-rw-r--r--src/runtime/qmlsplash/splash-qt4.qml94
-rw-r--r--src/runtime/qmlsplash/splash-qt5.qml95
-rw-r--r--src/runtime/runtime.pro19
-rw-r--r--src/src.pri54
-rw-r--r--src/src.pro9
-rw-r--r--src/usage.dox122
-rw-r--r--src/usage.qdoc155
-rw-r--r--src/watcher.cpp174
-rw-r--r--src/watcher.h56
-rw-r--r--src/widgets/filesystemmodel.cpp80
-rw-r--r--src/widgets/filesystemmodel.h53
-rw-r--r--src/widgets/logview.cpp130
-rw-r--r--src/widgets/logview.h62
-rw-r--r--src/widgets/widgets.pri15
-rw-r--r--src/widgets/windowwidget.cpp279
-rw-r--r--src/widgets/windowwidget.h69
-rw-r--r--src/widgets/workspacedelegate.cpp68
-rw-r--r--src/widgets/workspacedelegate.h48
-rw-r--r--src/widgets/workspaceview.cpp156
-rw-r--r--src/widgets/workspaceview.h66
-rw-r--r--testData/mixed/radio_0.pngbin0 -> 402 bytes
-rw-r--r--testData/mixed/radio_0_ro.pngbin0 -> 451 bytes
-rw-r--r--testData/mixed/radio_1.pngbin0 -> 447 bytes
-rw-r--r--testData/mixed/radio_2.pngbin0 -> 477 bytes
-rw-r--r--testData/mixed/radio_3.pngbin0 -> 515 bytes
-rw-r--r--testData/mixed/radio_disabled.pngbin0 -> 438 bytes
-rw-r--r--testData/mixed/radio_disabled_ro.pngbin0 -> 456 bytes
-rw-r--r--testData/mixed/radio_nav_active.pngbin0 -> 552 bytes
-rw-r--r--testData/mixed/radio_nav_inactive.pngbin0 -> 467 bytes
-rw-r--r--testData/mixed/radio_selected.pngbin0 -> 466 bytes
-rw-r--r--testData/qml/explicit-size.qml36
-rw-r--r--testData/qml/no-explicit-size.qml36
-rw-r--r--testData/qml/two-windows.qml58
-rw-r--r--tests/manual_tests/javascript/lib.js1
-rw-r--r--tests/manual_tests/javascript/pragma_main.qml45
-rw-r--r--tests/manual_tests/javascript/pragmalib.js3
-rw-r--r--tests/testipc/testipc.pro19
-rw-r--r--tests/testipc/tst_testipc.cpp97
-rw-r--r--tests/tests.pro7
-rw-r--r--tests/testsync/testsync.pro17
-rw-r--r--tests/testsync/tst_testsync.cpp56
179 files changed, 16896 insertions, 0 deletions
diff --git a/LICENSE.GPLv3 b/LICENSE.GPLv3
new file mode 100644
index 0000000..3281f07
--- /dev/null
+++ b/LICENSE.GPLv3
@@ -0,0 +1,684 @@
+ GNU GENERAL PUBLIC LICENSE
+
+ Qt IVI is Copyright (C) 2015 Pelagicore AG
+ Contact: http://www.pelagicore.com/
+
+ You may use, distribute and copy Qt IVI under the terms of the
+ GNU General Public License version 3, which is displayed below.
+
+-------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5afbfaa
--- /dev/null
+++ b/README.md
@@ -0,0 +1,54 @@
+# QmlLive
+
+A live coding environment for QML.
+
+Allows to reload your qml scene when a file in your workspace changes. This can be done on the same host using the QmlLiveBench or on a remote device using the QmlLiveRuntime using the QmlLiveBench as server.
+
+## Sub Projects
+
+- qmllivebench - the qml-live workbench. All inclusive
+- qmllivert - a default qml-live runtime for easy use
+- src - common source code shared by all projects
+
+## Desktop
+
+For desktop usage just compile livebench.
+
+ $ qmake
+ $ make
+ $ ./bin/qmllivebench
+
+The project files will automatically detect the qt version and enables
+or disables some features based on that.
+
+
+## Using QmlLiveBench
+
+Open QmlLiveBench on your host system and use File->Open Workspace to open your workspace. QmlLiveBench will observe all file changes in the directory and all sub-directories. Now you need to select a QML file in the workspace file viewer to start the rendering.
+
+When you now edit and save a file. The the changes wil be applied and the rendering reloaded. This goes in a fraction of a second.
+
+If you scene needs additional imports you can specify them under the settings dialog. Here you will also find the proxy information and the configurations for the target devices.
+
+## Running a remote session
+
+Configuring the target:
+
+Make sure you have any required imports available, which are either not in the workspace or are native pulgins. The qml files will be
+provided by the remote client using a synchronization protocol. Create a clean directory and start qmlliveruntime from there, passing any required imports using -importpath.
+
+Connecting with the client:
+
+Start qmlliveremote on your host machine. Open the qml workspace and connect to
+the target. Enable Publish changes and press Publish all to transfer the entire
+workspace to the target. Click on the qml file you want to run, it should start
+on the target. Edit using your favorite tools on the host and instantly get the
+changes on the target when saving.
+
+# Contributions
+
+* Dominik Holland - Thank you for shouldering most of the work and to ensure the IPC code is rock-solid.
+* Robert Griebl - Thank you for knowing so many details on Qt and helping with the internals.
+* Juergen Bocklage-Ryannel - For providing the initial idea and believing into the product.
+
+Copyright (C) 2015 Pelagicore
diff --git a/base.pri b/base.pri
new file mode 100644
index 0000000..0bb418b
--- /dev/null
+++ b/base.pri
@@ -0,0 +1,3 @@
+#TEMP_DIR = _build
+#OBJECTS_DIR = $$TEMP_DIR/obj
+#MOC_DIR = $$TEMP_DIR/moc
diff --git a/doc/Doxyfile b/doc/Doxyfile
new file mode 100644
index 0000000..1ca50ed
--- /dev/null
+++ b/doc/Doxyfile
@@ -0,0 +1,1846 @@
+# Doxyfile 1.8.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = QmlLive
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = /Users/jryannel/repos/qml-live/doc/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behavior.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behavior instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = /Users/jryannel/repos/qml-live/src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.vhd \
+ *.vhdl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = ../src
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax. However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# manageable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/doc/classes.qdoc b/doc/classes.qdoc
new file mode 100644
index 0000000..86844e4
--- /dev/null
+++ b/doc/classes.qdoc
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+/*!
+ \group classlists
+ \title Class and Function Documentation
+ \brief Lists and Indexes of classes, functions, and types.
+
+ Links to indexes and lists for finding class and function
+ reference documentation.
+
+ \section2 Class Lists
+
+ \annotatedlist classlists
+
+ \section2 Function Lists
+
+ \annotatedlist funclists
+
+*/
+
+/*!
+ \page classes.html
+ \title All Classes
+ \ingroup classlists
+
+ \brief If you know the name of the class you want, find it here.
+
+ This is a list of all Qt classes.
+
+ \generatelist classes
+*/
+
+/*!
+ \page hierarchy.html
+
+ \title Inheritance Hierarchy
+ \ingroup classlists
+
+ \brief The C++ class inheritance hierarchy for all classes in the
+ Qt API.
+
+ \generatelist classhierarchy
+*/
+
+/*!
+ \page functions.html
+ \title All Functions
+ \ingroup funclists
+
+ \brief All documented Qt functions listed alphabetically with a
+ link to where each one is declared.
+
+ This is the list of all documented member functions and global
+ functions in the Qt API. Each function has a link to the class or
+ header file where it is declared and documented.
+
+ \generatelist functionindex
+*/
+
+
+/*!
+ \page namespaces.html
+ \title All Namespaces
+ \ingroup classlists
+
+ \brief A Qt namespace contains enum types, functions, and sometimes classes.
+
+ This is a list of the main namespaces in Qt.
+
+ \generatelist{namespaces}
+*/
diff --git a/doc/examples.qdoc b/doc/examples.qdoc
new file mode 100644
index 0000000..e5a4191
--- /dev/null
+++ b/doc/examples.qdoc
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+/*!
+ \group qmllive-examples
+ \ingroup all-examples
+ \title QmlLive Examples
+ \brief Examples how to extend the functionality of QmlLive.
+
+ \list
+ \o \l{contentplugin}{Content Plugin}
+ \endlist
+
+*/
diff --git a/doc/examples/contentplugin.qdoc b/doc/examples/contentplugin.qdoc
new file mode 100644
index 0000000..3671309
--- /dev/null
+++ b/doc/examples/contentplugin.qdoc
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+/*!
+ \example contentplugin
+ \title ContentPlugin Example
+
+ \brief The ContentPlugin example demonstrates how to write a
+ Content Plugin for QmlLive
+
+ \image contentplugin-example.png Screenshot of the Plugin in Action
+
+ The Plugin written in this example displays Images like the
+ builtin Imageviewer in QmlLive, but it shows the content rotated
+ only works on *.png files.
+
+ We will start by reviewing the interface defined in \c
+ contentadapterinterface.h in the QmlLive source code. This
+ interface can be used to add a new ContentAdapter to QmlLive.
+ The ContentAdapter will be used to display any content you want
+ to be handled not directly by the LiveRuntime like displaying a image.
+
+ \snippet contentadapterinterface.h 0
+
+ The \c ContentAdapterInterface class declares four functions. The first
+ function \c canAdapt(const QUrl&) returns whether the plugin can display the
+ given file or directory.
+
+ The second function \c adapt(const QUrl& url, QDeclarativeContext* context)
+ returns a custom QUrl which will be used by QmlLive to display the given QUrl.
+ The returned QUrl always has to point to a qml file used to display the content.
+ To be able to control the returned qml File \c context can be used to set custom
+ Properties which will be exported to the qml File.
+
+ canPreview() and preview() are used for generating preview thumbnails.
+ We use the easiest implementation for this two methods.
+
+ \section1 MyContentAdapterPlugin
+
+ \snippet contentplugin/mycontentadapterplugin.h 0
+
+ The MyContentAdapterPlugin implements the interface to QmlLive. It subclasses
+ QObject and the needed \c ContentAdapterInterface.
+
+ \snippet contentplugin/mycontentadapterplugin.h 1
+
+ The \c Q_INTERFACES macro will be used to register the Plugin to Qt's Plugin
+ System.
+
+
+ To be called only for the right file type we have to overload the
+ \c canAdapt(const QUrl&) function. We only want to be loaded for *.png files.
+ That's why we check the file ending on the given url and return true when it's
+ an png file.
+
+ \snippet contentplugin/mycontentadapterplugin.cpp 0
+
+ If the plugin accepts the file \c adapt(const QUrl& url, QDeclarativeContext* context)
+ will be called. Here we export the path to the image to a special property in the
+ context to be able to access the fileName from within our qml File.
+ Afterwards we return a QUrl pointing to our qml File which is inside a ResourceFile.
+
+ \snippet contentplugin/mycontentadapterplugin.cpp 1
+
+ Now only the implementation of canPreview() and preview() are missing. Here we just
+ add some dummy implementation because we don't want to add this functionality.
+
+ \snippet contentplugin/mycontentadapterplugin.cpp 2
+
+ \section1 plugin.qml
+
+ The plugin.qml file is our ImageViewer. In it we create a \c Image Element and
+ set the source to our exported Property \c imageSource. The rotation Property
+ will be set to 180 to rotate the Image 180 degrees.
+
+ \snippet contentplugin/plugin.qml 0
+
+ \section1 The Resource File
+
+ Because we don't want to fiddle around with paths we include our qml File into
+ a Resource File. The most important thing in the Resource File is to use an
+ unused Prefix. Otherwise our file can't be found because QmlLive also uses
+ Resource Files. The best approach is to use the plugin name as prefix.
+*/
diff --git a/doc/images/contentplugin-example.png b/doc/images/contentplugin-example.png
new file mode 100644
index 0000000..e298c59
--- /dev/null
+++ b/doc/images/contentplugin-example.png
Binary files differ
diff --git a/doc/index.qdoc b/doc/index.qdoc
new file mode 100644
index 0000000..d5d350b
--- /dev/null
+++ b/doc/index.qdoc
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+/*!
+\page index.html
+\keyword Pelagicore QML Live Reference Documentation
+
+\div {class="indexbox tools"}
+ \div {class="indexboxcont indexboxbar"}
+ \div {class="sectionlist normallist"}
+ \enddiv
+ \enddiv
+\enddiv
+\div {class="indexbox tools"}
+ \div {class="heading"}
+ Reference
+ \enddiv
+ \div {class="indexboxcont indexboxbar"}
+ \div {class="sectionlist normallist"}
+ \list
+ \o \l{All Classes}{All Classes}
+ \o \l{All Functions}{All Functions}
+ \endlist
+ \enddiv
+ \div {class="sectionlist normallist"}
+ \list
+ \o \l{QML Elements}
+ \o \l{QmlLive Examples}
+ \endlist
+ \enddiv
+ \enddiv
+\enddiv
+*/
diff --git a/doc/project.qdoc b/doc/project.qdoc
new file mode 100644
index 0000000..6134891
--- /dev/null
+++ b/doc/project.qdoc
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+/*!
+
+\page qml-live.html
+\keyword QML Live
+\title QML Live
+
+During a typical user interface design phase, designers create many graphics documents
+envisioning the desired user interface. Transferring such graphical visions into
+programmer’s code is difficult. Not only is it a tedious process, it often comes with great
+compromises on both sides.
+
+Many time-consuming iterations are needed to finally reach a compromise that satisfies
+the designer’s vision and is also technically feasible. However, each iteration also brings a
+small change towards the goal. Qt, with the Qt Quick technology, already shortens the
+gap between vision and product by introducing a more design oriented language (QML).
+But there still is room for improvement...
+
+See also \l {usage.html} {Usage} for how to work with the QMLLiveBench
+
+*/
diff --git a/doc/qmllive.qdocconf b/doc/qmllive.qdocconf
new file mode 100644
index 0000000..22bc41f
--- /dev/null
+++ b/doc/qmllive.qdocconf
@@ -0,0 +1,84 @@
+
+sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
+headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
+examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml"
+examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
+
+headerdirs = ../src
+sourcedirs = . ../src examples
+
+exampledirs = ../examples \
+ examples \
+ ../src
+
+imagedirs = ../src/images \
+ images
+
+
+sourceencoding = UTF-8
+outputencoding = UTF-8
+naturallanguage = en_US
+
+outputdir = html
+
+indexes = $QTDIR/doc/html/qt.index
+
+project = qmllive
+description = Pelagicore QML Live Reference Documentation
+
+
+# Define the location of the templates to use. Style sheets and scripts are
+# specified relative to the template directory and will be copied into
+# subdirectories of the output directory.
+
+HTML.templatedir = template
+
+HTML.stylesheets = style/offline.css \
+
+# Adding jquery and functions - providing online tools and search features
+HTML.scripts =
+
+
+# Files not referenced in any qdoc file.
+# See also qhp.Qt.extraFiles
+extraimages.HTML = images/qt-logo.png \
+ images/bg_l.png \
+ images/bg_l_blank.png \
+ images/bg_ll_blank.png \
+ images/bg_ul_blank.png \
+ images/btn_next_green.png \
+ images/btn_prev_green.png \
+ images/header_bg.png \
+ images/bg_r.png \
+ images/box_bg.png \
+ images/breadcrumb.png \
+ images/bullet_gt.png \
+ images/bullet_dn.png \
+ images/bullet_sq.png \
+ images/bullet_up.png \
+ images/arrow_down.png \
+ images/feedbackground.png \
+ images/horBar.png \
+ images/page.png \
+ images/page_bg.png \
+ images/sprites-combined.png \
+ images/spinner.gif
+
+# Include the style sheets and scripts used.
+
+HTML.headerstyles = \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"
+
+
+qhp.projects = qmllive
+
+qhp.qmllive.file = qmllive.qhp
+qhp.qmllive.namespace = net.pelagicore.qmllive.100
+qhp.qmllive.virtualFolder = qdoc
+qhp.qmllive.indexTitle = Pelagicore QML Live Reference Documentation
+qhp.qmllive.indexRoot =
+qhp.qmllive.extraFiles = style/offline.css
+qhp.qmllive.filterAttributes = nal network abstraction layer
+
+
+
diff --git a/doc/template/style/offline.css b/doc/template/style/offline.css
new file mode 100644
index 0000000..08bfce6
--- /dev/null
+++ b/doc/template/style/offline.css
@@ -0,0 +1,428 @@
+
+body {
+ color: #313131;
+ font: 400 14px/1.2 Arial,Helvetica;
+ margin-left: 5px;
+ margin-right: 5px;
+ margin-top: 85px;
+ text-align: justify;
+}
+img {
+ border: 2px solid #8E8D8D;
+ box-shadow: 3px 3px 3px #CCCCCC;
+ height: auto;
+ margin-left: 0;
+ max-width: 800px;
+}
+b {
+ font-weight: 600;
+}
+.content {
+}
+.descr {
+ margin-left: 5px;
+ margin-top: 35px;
+ min-height: 700px;
+ text-align: justify;
+ vertical-align: top;
+}
+.name {
+ font-weight: 100;
+ max-width: 75%;
+}
+tt {
+ text-align: left;
+}
+a:link {
+ color: #F57900;
+ text-align: left;
+ text-decoration: none;
+}
+a:hover {
+ color: #D36800;
+ text-align: left;
+ text-decoration: underline;
+}
+a:visited {
+ color: #D36800;
+ text-align: left;
+ text-decoration: none;
+}
+a:visited:hover {
+ text-align: left;
+ text-decoration: underline;
+}
+a[href*="http://"], a[href*="ftp://"], a[href*="https://"] {
+ background-image: url("../images/ico_out.png");
+ background-position: left center;
+ background-repeat: no-repeat;
+ text-align: left;
+ text-decoration: none;
+}
+.flags {
+ text-decoration: none;
+}
+.notetitle, .tiptitle, .fastpathtitle {
+ font-weight: bold;
+}
+.attentiontitle, .cautiontitle, .dangertitle, .importanttitle, .remembertitle, .restrictiontitle {
+ font-weight: bold;
+}
+.note, .tip, .fastpath {
+ background: url("../images/ico_note.png") no-repeat scroll left top #F2F2F2;
+ border: 1px dotted #999999;
+ color: #666666;
+ margin: 5px;
+ padding: 5px 5px 10px 40px;
+}
+.attention, .caution, .danger, .important, .remember, .restriction {
+ background: url("../images/ico_note_attention.png") no-repeat scroll left top #F2F2F2;
+ border: 1px dotted #999999;
+ color: #666666;
+ margin: 5px;
+ padding: 5px 5px 10px 40px;
+}
+.header {
+ height: 1px;
+ margin: 0;
+ padding: 0;
+}
+.qtref {
+ display: block;
+ float: right;
+ font-size: 11px;
+ height: 15px;
+ padding-right: 10px;
+ position: relative;
+ top: -76px;
+ z-index: 1;
+}
+.naviNextPrevious {
+ display: block;
+ float: right;
+ height: 20px;
+ margin: 0;
+ padding-right: 10px;
+ padding-top: 2px;
+ position: relative;
+ text-align: right;
+ top: -53px;
+ vertical-align: top;
+ z-index: 1;
+}
+.naviNextPrevious > a.prevPage {
+ background-image: url("../images/btn_prev.png");
+ background-position: left center;
+ background-repeat: no-repeat;
+ height: 20px;
+ padding-left: 20px;
+}
+.naviNextPrevious > a.nextPage {
+ background-image: url("../images/btn_next.png");
+ background-position: right center;
+ background-repeat: no-repeat;
+ height: 20px;
+ margin-left: 30px;
+ padding-right: 20px;
+}
+.breadcrumb {
+ background-color: #F2F2F2;
+ border-bottom: 1px solid #CECECE;
+ display: block;
+ height: 20px;
+ margin: 0 -5px;
+ padding: 2px 0 0 10px;
+ position: relative;
+ top: -20px;
+ z-index: 1;
+}
+.breadcrumb ul {
+ margin: 0;
+ padding: 0;
+}
+.breadcrumb ul li {
+ background-color: #F2F2F2;
+ height: 20px;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+.breadcrumb li {
+ float: left;
+}
+.breadcrumb .first {
+ background: url("../images/home.png") no-repeat scroll left center transparent;
+ padding-left: 20px;
+}
+.breadcrumb li a {
+ background: url("../images/arrow.png") no-repeat scroll right center transparent;
+ color: #F57900;
+ display: block;
+ padding-left: 10px;
+ padding-right: 25px;
+ text-decoration: none;
+}
+.breadcrumb li a:hover {
+ background: url("../images/arrow.png") no-repeat scroll right center transparent;
+ color: #909090;
+ display: block;
+ padding-left: 10px;
+ padding-right: 20px;
+ text-decoration: none;
+}
+.title {
+ background-color: #E6E6E6;
+ border-bottom: 1px solid #CCCCCC;
+ border-top: 2px solid #CCCCCC;
+ color: #313131;
+ font-size: 18px;
+ font-weight: bold;
+ left: 0;
+ margin-left: 0;
+ margin-right: 0;
+ padding-bottom: 20px;
+ padding-left: 10px;
+ padding-top: 20px;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+h1 {
+ margin: 0;
+}
+h2, p.h2 {
+ background-color: #F2F3F4;
+ border-bottom: 1px solid #E0E0DE;
+ border-top: 1px solid #E0E0DE;
+ font: 100 16px/1.2 Arial;
+ margin: 30px -5px 30px -10px;
+ padding: 4px 4px 4px 14px;
+}
+h3 {
+ font: 100 14px/1.2 Arial;
+ margin-bottom: 30px;
+ margin-top: 30px;
+ text-decoration: underline;
+}
+h3.fn, span.fn {
+ background-color: #F6F6F6;
+ border-color: #E6E6E6;
+ border-radius: 7px 7px 7px 7px;
+ border-style: solid;
+ border-width: 1px;
+ font-size: 14px;
+ font-weight: bold;
+ margin: 30px 0 0;
+ max-width: 75%;
+ padding: 5px;
+ text-decoration: none;
+ word-spacing: 3px;
+}
+.name {
+ color: #1A1A1A;
+}
+.type {
+ color: #808080;
+}
+.title {
+ color: #F57900;
+ font-family: Arial,Helvetica;
+ font-size: 32px;
+ font-weight: normal;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+.table img {
+ border: medium none;
+ box-shadow: 0 0 0 #FFFFFF;
+ margin-left: 0;
+}
+table, pre {
+ background-color: #F6F6F6;
+ border: 1px solid #E6E6E6;
+ border-collapse: separate;
+ border-radius: 7px 7px 7px 7px;
+ font-size: 12px;
+ line-height: 1.2;
+ margin-bottom: 25px;
+ margin-left: 15px;
+}
+table th {
+ padding-left: 20px;
+ text-align: left;
+}
+table td {
+ border-bottom: 1px dotted #CCCCCC;
+ padding: 3px 15px 3px 20px;
+}
+table p {
+ margin: 0;
+}
+table tr.even {
+ background-color: white;
+ color: #66666E;
+}
+table tr.odd {
+ background-color: #F6F6F6;
+ color: #66666E;
+}
+table thead {
+ background-color: #E1E0E0;
+ border-left: medium none;
+ border-right: medium none;
+ padding-left: 20px;
+ text-align: left;
+}
+table thead th {
+ border-bottom: 2px solid #D1D1D1;
+ padding: 5px 10px;
+}
+.borderless {
+ background-color: #FFFFFF;
+ border: 1px solid #FFFFFF;
+ border-radius: 0 0 0 0;
+}
+.borderless tr {
+ background-color: #FFFFFF;
+ color: #66666E;
+}
+.borderless td {
+ -moz-border-bottom-colors: none;
+ -moz-border-left-colors: none;
+ -moz-border-right-colors: none;
+ -moz-border-top-colors: none;
+ border-color: -moz-use-text-color -moz-use-text-color #FFFFFF;
+ border-image: none;
+ border-style: none none dotted;
+ border-width: medium medium 1px;
+}
+ul {
+ padding-bottom: 2px;
+}
+li {
+ list-style: square outside none;
+ margin-bottom: 10px;
+ padding-left: 8px;
+ text-align: left;
+}
+ol {
+ margin: 10px;
+ padding: 0;
+}
+ol > li {
+ list-style: decimal outside none;
+ margin-left: 30px;
+ padding-left: 8px;
+}
+.centerAlign {
+ text-align: left;
+}
+.cpp {
+ display: block;
+ overflow: hidden;
+ padding: 20px 0;
+}
+.footer {
+ border-top: 1px solid #999999;
+ font-size: 10px;
+ margin-bottom: 10px;
+ margin-top: 50px;
+ padding-left: 5px;
+ padding-top: 11px;
+}
+.footerNavi {
+ margin-top: 50px;
+ text-align: right;
+ width: auto;
+ z-index: 1;
+}
+.memItemLeft {
+ padding-right: 3px;
+}
+.memItemRight {
+ padding: 3px 15px 3px 0;
+}
+.qml {
+ display: block;
+ overflow: hidden;
+ padding: 20px 0;
+}
+.qmldefault {
+ color: red;
+ float: right;
+ padding-left: 5px;
+}
+.qmlreadonly {
+ color: #254117;
+ float: right;
+ padding-left: 5px;
+}
+.rightAlign {
+ padding: 3px 5px 3px 10px;
+ text-align: right;
+}
+.toc {
+ background-image: url("../images/bgrContent.png");
+ background-position: center top;
+ background-repeat: no-repeat;
+ float: right;
+ padding-bottom: 10px;
+ padding-top: 50px;
+ width: 100%;
+}
+.toc {
+ background: url("../images/bgrContent.png") repeat-x scroll center top #FFFFFF;
+ border: 1px solid #E6E6E6;
+ border-radius: 7px 7px 7px 7px;
+ clear: both;
+ float: right;
+ height: auto;
+ margin-left: 20px;
+ margin-right: 20px;
+ margin-top: 0;
+ padding-bottom: 10px;
+ padding-left: 5px;
+ padding-top: 0;
+ text-align: left;
+ vertical-align: top;
+ width: 200px;
+ z-index: 2;
+}
+.toc h3 {
+ text-decoration: none;
+}
+.toc h3 {
+ font: 100 14px/1.2 Arial;
+ margin: 0;
+ padding: 5px 0 0 5px;
+}
+.toc ul {
+ padding-left: 10px;
+ padding-right: 5px;
+ padding-top: 10px;
+ width: 160px;
+}
+.toc ul li {
+ list-style: disc outside none;
+ margin-left: 20px;
+}
+.toc ul li a:link {
+ color: #F57900;
+ text-decoration: none;
+}
+.toc ul li a:hover {
+ color: #D36800;
+ text-decoration: underline;
+}
+.toc ul li a:visited {
+ color: #D36800;
+ font-weight: bold;
+}
+.level1 {
+ border: medium none;
+}
+.clearfix {
+ clear: both;
+}
diff --git a/examples/contentplugin/contentplugin.pro b/examples/contentplugin/contentplugin.pro
new file mode 100644
index 0000000..c142b07
--- /dev/null
+++ b/examples/contentplugin/contentplugin.pro
@@ -0,0 +1,13 @@
+TEMPLATE = lib
+CONFIG += plugin
+INCLUDEPATH += ../../src
+HEADERS = mycontentadapterplugin.h
+SOURCES = mycontentadapterplugin.cpp
+TARGET = myContentAdapterPlugin
+DESTDIR = ../../bin/plugins
+
+RESOURCES += res.qrc \
+ res.qrc
+
+OTHER_FILES += \
+ plugin.qml
diff --git a/examples/contentplugin/mycontentadapterplugin.cpp b/examples/contentplugin/mycontentadapterplugin.cpp
new file mode 100644
index 0000000..ab1a6ba
--- /dev/null
+++ b/examples/contentplugin/mycontentadapterplugin.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+#include "mycontentadapterplugin.h"
+
+#include <QtCore/QtPlugin>
+#include <QtDeclarative/QDeclarativeContext>
+
+MyContentAdapterPlugin::MyContentAdapterPlugin(QObject *parent) :
+ QObject(parent)
+{
+}
+
+//! [2]
+bool MyContentAdapterPlugin::canPreview(const QString &path) const
+{
+ Q_UNUSED(path)
+
+ return false;
+}
+
+QImage MyContentAdapterPlugin::preview(const QString &path, const QSize &requestedSize)
+{
+ Q_UNUSED(path);
+ Q_UNUSED(requestedSize);
+
+ return QImage();
+}
+//! [2]
+
+//! [0]
+bool MyContentAdapterPlugin::canAdapt(const QUrl &url) const
+{
+ return url.toLocalFile().endsWith(".png");
+}
+//! [0]
+
+//! [1]
+QUrl MyContentAdapterPlugin::adapt(const QUrl &url, QDeclarativeContext *context)
+{
+ context->setContextProperty("imageSource", url);
+
+ return QString("qrc:/mycontentadatperplugin/plugin.qml");
+}
+//! [1]
+
+Q_EXPORT_PLUGIN2(myContentAdapterPlugin, MyContentAdapterPlugin)
diff --git a/examples/contentplugin/mycontentadapterplugin.h b/examples/contentplugin/mycontentadapterplugin.h
new file mode 100644
index 0000000..2d21565
--- /dev/null
+++ b/examples/contentplugin/mycontentadapterplugin.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+#ifndef MYCONTENTADAPTERPLUGIN_H
+#define MYCONTENTADAPTERPLUGIN_H
+
+#include <contentadapterinterface.h>
+
+//! [0]
+class MyContentAdapterPlugin : public QObject, public ContentAdapterInterface
+{
+ Q_OBJECT
+//! [1]
+ Q_INTERFACES(ContentAdapterInterface)
+//! [1]
+public:
+ explicit MyContentAdapterPlugin(QObject *parent = 0);
+
+ bool canPreview(const QString& path) const;
+ QImage preview(const QString& path, const QSize &requestedSize);
+
+ bool canAdapt(const QUrl& url) const;
+ QUrl adapt(const QUrl& url, QDeclarativeContext* context);
+
+};
+//! [0]
+
+#endif // MYCONTENTADAPTERPLUGIN_H
diff --git a/examples/contentplugin/plugin.qml b/examples/contentplugin/plugin.qml
new file mode 100644
index 0000000..20b6afe
--- /dev/null
+++ b/examples/contentplugin/plugin.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+//! [0]
+import QtQuick 1.1
+
+Rectangle {
+ width: 300
+ height: 300
+
+ Image {
+ anchors.centerIn: parent
+
+ rotation: 180
+ source: imageSource
+ }
+}
+//! [0]
diff --git a/examples/contentplugin/res.qrc b/examples/contentplugin/res.qrc
new file mode 100644
index 0000000..4ff52f2
--- /dev/null
+++ b/examples/contentplugin/res.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/mycontentadatperplugin">
+ <file>plugin.qml</file>
+ </qresource>
+</RCC>
diff --git a/header.GPL3_PELAGICORE b/header.GPL3_PELAGICORE
new file mode 100644
index 0000000..392b1c0
--- /dev/null
+++ b/header.GPL3_PELAGICORE
@@ -0,0 +1,27 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.pelagicore.com/
+**
+** This file is part of Qt IVI.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt IVI licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Pelagicore. For licensing terms
+** and conditions see http://www.pelagicore.com.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
diff --git a/icons/appicon.icns b/icons/appicon.icns
new file mode 100644
index 0000000..036ad2e
--- /dev/null
+++ b/icons/appicon.icns
Binary files differ
diff --git a/icons/appicon.ico b/icons/appicon.ico
new file mode 100644
index 0000000..9c6a591
--- /dev/null
+++ b/icons/appicon.ico
Binary files differ
diff --git a/icons/appicon.rc b/icons/appicon.rc
new file mode 100644
index 0000000..7675baa
--- /dev/null
+++ b/icons/appicon.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "appicon.ico"
diff --git a/qmllive.pri b/qmllive.pri
new file mode 100644
index 0000000..e0cc675
--- /dev/null
+++ b/qmllive.pri
@@ -0,0 +1,23 @@
+# from qtcreator.pri
+defineTest(minQtVersion) {
+ maj = $$1
+ min = $$2
+ patch = $$3
+ isEqual(QT_MAJOR_VERSION, $$maj) {
+ isEqual(QT_MINOR_VERSION, $$min) {
+ isEqual(QT_PATCH_VERSION, $$patch) {
+ return(true)
+ }
+ greaterThan(QT_PATCH_VERSION, $$patch) {
+ return(true)
+ }
+ }
+ greaterThan(QT_MINOR_VERSION, $$min) {
+ return(true)
+ }
+ }
+ greaterThan(QT_MAJOR_VERSION, $$maj) {
+ return(true)
+ }
+ return(false)
+}
diff --git a/qmllive.pro b/qmllive.pro
new file mode 100644
index 0000000..bf51bb7
--- /dev/null
+++ b/qmllive.pro
@@ -0,0 +1,39 @@
+include(qmllive.pri)
+
+!minQtVersion(5, 1, 1):error("You need at least Qt 5.1.1 to build this application")
+
+TEMPLATE = subdirs
+
+
+SUBDIRS += \
+ src \
+ # tests
+
+exists($(QTDIR)/bin/qdoc3) {
+ exists($(QTDIR)/bin/qhelpgenerator) {
+ message ("Using qdoc/qhelpgenerator in QTDIR for generating docs")
+ QDOC = $(QTDIR)/bin/qdoc3
+ QHELPGENERATOR = $(QTDIR)/bin/qhelpgenerator
+ } else {
+ message ("Trying to use system qdoc/qhelpgenerator for generating docs")
+ QDOC = qdoc3
+ QHELPGENERATOR = qhelpgenerator
+ }
+} else {
+ message ("Trying to use system qdoc/qhelpgenerator for generating docs")
+ QDOC = qdoc3
+ QHELPGENERATOR = qhelpgenerator
+}
+
+html-docs.files = $$PWD/doc/html
+
+html-docs.commands = $$QDOC $$PWD/doc/qmllive.qdocconf
+html-docs.files = $$PWD/doc/html
+
+qch-docs.commands = $$QHELPGENERATOR $$PWD/doc/html/qmllive.qhp -o $$PWD/doc/html/qmllive.qch
+qch-docs.files = $$PWD/docs/qch
+qch-docs.CONFIG += no_check_exist directory
+
+docs.depends = html-docs qch-docs
+
+QMAKE_EXTRA_TARGETS += html-docs qch-docs docs
diff --git a/src/bench/allhostswidget.cpp b/src/bench/allhostswidget.cpp
new file mode 100644
index 0000000..8ae2315
--- /dev/null
+++ b/src/bench/allhostswidget.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "allhostswidget.h"
+
+#include <QGroupBox>
+#include <QPushButton>
+#include <QLabel>
+#include <QMenu>
+#include <QGridLayout>
+#include <QDragEnterEvent>
+#include <QDropEvent>
+#include <QMimeData>
+#include <QUrl>
+#include <QMessageBox>
+
+AllHostsWidget::AllHostsWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ setAcceptDrops(true);
+
+ setFixedHeight(155);
+
+ QGridLayout* layout = new QGridLayout(this);
+ m_groupBox = new QGroupBox("All Hosts");
+ layout->addWidget(m_groupBox);
+
+ m_menuButton = new QPushButton("...", m_groupBox);
+ m_menuButton->setMaximumWidth(30);
+ m_menuButton->setCheckable(true);
+ connect(m_menuButton, SIGNAL(clicked()), this, SLOT(showMenu()));
+
+ QVBoxLayout* hbox = new QVBoxLayout(m_groupBox);
+ hbox->addWidget(new QLabel("Drop File"));
+ hbox->addWidget(m_menuButton);
+
+ m_menu = new QMenu(this);
+ m_publishAction = m_menu->addAction("Publish All", this, SLOT(onPublishTriggered()));
+ connect(m_menu, SIGNAL(aboutToHide()), m_menuButton, SLOT(toggle()));
+
+ m_refreshAction = m_menu->addAction("Refresh All", this, SIGNAL(refreshAll()));
+}
+
+void AllHostsWidget::setWorkspace(const QString &workspace)
+{
+ m_workspace.setPath(workspace);
+}
+
+void AllHostsWidget::showMenu()
+{
+ QPoint p = mapToGlobal(m_menuButton->pos());
+ p.ry() += m_menuButton->height() + 5;
+ p.rx() += 5;
+ m_menu->exec(p);
+}
+
+void AllHostsWidget::onPublishTriggered()
+{
+ if (QMessageBox::question(this, QString("Publish %1").arg(m_workspace.path()),
+ QString("Do you really want to publish the content of %1").arg(m_workspace.path())) == QMessageBox::Yes) {
+ emit publishAll();
+ }
+}
+
+void AllHostsWidget::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasFormat("text/uri-list")) {
+ event->acceptProposedAction();
+ }
+}
+
+void AllHostsWidget::dropEvent(QDropEvent *event)
+{
+ QUrl url(event->mimeData()->text());
+
+ if (url.isLocalFile())
+ emit currentFileChanged(url.toLocalFile());
+ event->acceptProposedAction();
+}
diff --git a/src/bench/allhostswidget.h b/src/bench/allhostswidget.h
new file mode 100644
index 0000000..bd55db8
--- /dev/null
+++ b/src/bench/allhostswidget.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QWidget>
+#include <QDir>
+
+class QGroupBox;
+class QPushButton;
+class QMenu;
+class AllHostsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit AllHostsWidget(QWidget *parent = 0);
+
+ void setWorkspace(const QString& workspace);
+
+signals:
+ void refreshAll();
+ void publishAll();
+ void currentFileChanged(const QString file);
+
+protected:
+ void dropEvent(QDropEvent *event);
+ void dragEnterEvent(QDragEnterEvent *event);
+private slots:
+ void showMenu();
+ void onPublishTriggered();
+private:
+ QDir m_workspace;
+ QGroupBox* m_groupBox;
+ QPushButton* m_menuButton;
+ QMenu* m_menu;
+ QAction* m_publishAction;
+ QAction* m_refreshAction;
+};
+
diff --git a/src/bench/autodiscoveryhostsdialog.cpp b/src/bench/autodiscoveryhostsdialog.cpp
new file mode 100644
index 0000000..1d1998a
--- /dev/null
+++ b/src/bench/autodiscoveryhostsdialog.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "autodiscoveryhostsdialog.h"
+#include "ui_autodiscoveryhostsdialog.h"
+#include "hostmodel.h"
+
+AutoDiscoveryHostsDialog::AutoDiscoveryHostsDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AutoDiscoveryHostsDialog),
+ m_model(0)
+{
+ ui->setupUi(this);
+}
+
+AutoDiscoveryHostsDialog::~AutoDiscoveryHostsDialog()
+{
+ delete ui;
+}
+
+QList<QPointer<Host> > AutoDiscoveryHostsDialog::selectedHosts() const
+{
+ QList<QPointer<Host> > hostList;
+
+ QModelIndexList selectedRows = ui->hostView->selectionModel()->selectedRows();
+ foreach (QModelIndex index, selectedRows) {
+ Host* host = m_model->hostAt(index.row());
+ hostList.append(QPointer<Host>(host));
+ }
+
+ return hostList;
+}
+
+void AutoDiscoveryHostsDialog::clearSelection()
+{
+ ui->hostView->clearSelection();
+}
+
+void AutoDiscoveryHostsDialog::setDiscoveredHostsModel(HostModel *model)
+{
+ m_model = model;
+
+ ui->hostView->setModel(model);
+ ui->hostView->hideColumn(0);
+}
diff --git a/src/bench/autodiscoveryhostsdialog.h b/src/bench/autodiscoveryhostsdialog.h
new file mode 100644
index 0000000..7eed8cf
--- /dev/null
+++ b/src/bench/autodiscoveryhostsdialog.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QDialog>
+#include <QPointer>
+
+namespace Ui {
+class AutoDiscoveryHostsDialog;
+}
+
+class HostModel;
+class Host;
+
+class AutoDiscoveryHostsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AutoDiscoveryHostsDialog(QWidget *parent = 0);
+ ~AutoDiscoveryHostsDialog();
+
+ QList<QPointer<Host> > selectedHosts() const;
+
+ void clearSelection();
+
+ void setDiscoveredHostsModel(HostModel* model);
+
+private:
+ Ui::AutoDiscoveryHostsDialog *ui;
+ HostModel* m_model;
+};
+
diff --git a/src/bench/autodiscoveryhostsdialog.ui b/src/bench/autodiscoveryhostsdialog.ui
new file mode 100644
index 0000000..58f2a4f
--- /dev/null
+++ b/src/bench/autodiscoveryhostsdialog.ui
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AutoDiscoveryHostsDialog</class>
+ <widget class="QDialog" name="AutoDiscoveryHostsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>549</width>
+ <height>284</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Select the Hosts you want to add:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableView" name="hostView">
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>AutoDiscoveryHostsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>AutoDiscoveryHostsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/bench/bench.pro b/src/bench/bench.pro
new file mode 100644
index 0000000..ee1ef67
--- /dev/null
+++ b/src/bench/bench.pro
@@ -0,0 +1,61 @@
+TEMPLATE = app
+TARGET = qmllivebench
+DESTDIR = ../../bin
+
+QT *= gui core quick widgets core-private
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ optionsdialog.cpp \
+ benchlivenodeengine.cpp \
+ previewimageprovider.cpp \
+ directorypreviewadapter.cpp \
+ qmlpreviewadapter.cpp \
+ benchquickview.cpp \
+ host.cpp \
+ hostmodel.cpp \
+ hostwidget.cpp \
+ dummydelegate.cpp \
+ allhostswidget.cpp \
+ hostmanager.cpp \
+ hostsoptionpage.cpp \
+ httpproxyoptionpage.cpp \
+ importpathoptionpage.cpp \
+ hostdiscoverymanager.cpp \
+ autodiscoveryhostsdialog.cpp
+
+HEADERS += \
+ mainwindow.h \
+ optionsdialog.h \
+ benchlivenodeengine.h \
+ previewimageprovider.h \
+ directorypreviewadapter.h \
+ qmlpreviewadapter.h \
+ benchquickview.h \
+ host.h \
+ hostmodel.h \
+ hostwidget.h \
+ dummydelegate.h \
+ allhostswidget.h \
+ hostmanager.h \
+ hostsoptionpage.h \
+ importpathoptionpage.h \
+ httpproxyoptionpage.h \
+ hostdiscoverymanager.h \
+ autodiscoveryhostsdialog.h
+
+
+FORMS += \
+ optionsdialog.ui \
+ hostsoptionpage.ui \
+ httpproxyoptionpage.ui \
+ importpathoptionpage.ui \
+ autodiscoveryhostsdialog.ui
+
+# include(../base.pri)
+include(../widgets/widgets.pri)
+include(../src.pri)
+
+win32: RC_FILE = ../../icons/appicon.rc
+osx: ICON = ../../icons/appicon.icns
diff --git a/src/bench/benchlivenodeengine.cpp b/src/bench/benchlivenodeengine.cpp
new file mode 100644
index 0000000..ca82016
--- /dev/null
+++ b/src/bench/benchlivenodeengine.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "benchlivenodeengine.h"
+#include "directorypreviewadapter.h"
+#include "previewimageprovider.h"
+#include "qmlpreviewadapter.h"
+#include "widgets/windowwidget.h"
+#include "liveruntime.h"
+#include "widgets/workspaceview.h"
+#include "benchquickview.h"
+
+#include <QFileIconProvider>
+#include <QQmlImageProviderBase>
+
+BenchLiveNodeEngine::BenchLiveNodeEngine(QObject *parent)
+ : LiveNodeEngine(parent),
+ m_view(0),
+ m_ww(0),
+ m_workspaceView(0),
+ m_ignoreCache(false),
+ m_clipToRootObject(false)
+{
+ setUpdateMode(LiveNodeEngine::RecreateView);
+}
+
+void BenchLiveNodeEngine::setWindowWidget(WindowWidget* widget)
+{
+ m_ww = widget;
+}
+
+QQuickView* BenchLiveNodeEngine::initView()
+{
+ m_view = new BenchQuickView();
+ connect(m_view, SIGNAL(sizeChanged(QSize)), this, SLOT(onSizeChanged(QSize)));
+
+ if (!m_imageProvider) {
+ m_imageProvider = new PreviewImageProvider(this);
+ }
+
+ m_imageProvider->setIgnoreCache(m_ignoreCache);
+
+ m_view->engine()->addImageProvider("qmlLiveDirectoryPreview", m_imageProvider);
+
+ emit viewChanged(m_view);
+
+ return m_view;
+}
+
+void BenchLiveNodeEngine::setWorkspaceView(WorkspaceView *view)
+{
+ m_workspaceView = view;
+}
+
+//If a refresh is done we want to reload everything
+void BenchLiveNodeEngine::refresh()
+{
+ m_ignoreCache = true;
+ reloadHelper();
+}
+
+//A normal reload should use the cache
+void BenchLiveNodeEngine::reloadDocument()
+{
+ m_ignoreCache = false;
+ reloadHelper();
+}
+
+/*!
+ * Loads the fileIcon for the file provided by \a info and returns a QImage.
+ *
+ * It tries to resize the Icon to the \a requestedSize, but the content may be smaller.
+ *
+ * This function is used by the previewimageprovide and has to run in the mainthread.
+ * That's why it lives in the LiveNodeEngine
+ */
+QImage BenchLiveNodeEngine::convertIconToImage(const QFileInfo &info, const QSize &requestedSize)
+{
+ QFileIconProvider iconProvider;
+ QIcon icon = iconProvider.icon(info);
+ QImage img(requestedSize, QImage::Format_ARGB32);
+ img.fill(Qt::transparent);
+ QPainter painter(&img);
+ icon.paint(&painter, QRect(QPoint(0,0), requestedSize));
+ return img;
+}
+
+void BenchLiveNodeEngine::onSizeChanged(const QSize &size)
+{
+ m_runtime->setScreenWidth(size.width());
+ m_runtime->setScreenHeight(size.height());
+}
+
+void BenchLiveNodeEngine::onWidthChanged(int width)
+{
+ m_runtime->setScreenWidth(width);
+}
+
+void BenchLiveNodeEngine::onHeightChanged(int height)
+{
+ m_runtime->setScreenHeight(height);
+}
+
+void BenchLiveNodeEngine::initPlugins()
+{
+ LiveNodeEngine::initPlugins();
+
+ DirectoryPreviewAdapter* adapter = new DirectoryPreviewAdapter(this);
+ if (m_workspaceView) {
+ //This needs to be QueuedConnection because Qt5 doesn't like it to destruct it's object while it is in a signalHandler
+ connect(adapter, SIGNAL(loadDocument(QString)), m_workspaceView, SLOT(activateDocument(QString)), Qt::QueuedConnection);
+ }
+
+ QmlPreviewAdapter* previewAdapter = new QmlPreviewAdapter(this);
+
+ previewAdapter->setImportPaths(importPaths());
+
+ m_plugins.append(adapter);
+ m_plugins.append(previewAdapter);
+
+ if (m_imageProvider)
+ m_imageProvider->setPlugins(m_plugins);
+}
+
+void BenchLiveNodeEngine::reloadHelper()
+{
+ LiveNodeEngine::reloadDocument();
+
+ QAbstractScrollArea* scroller = m_ww;
+
+ ContentAdapterInterface *adapter = activePlugin();
+ if (adapter && adapter->isFullScreen()) {
+ m_ww->setCenteringEnabled(false);
+ scroller->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ } else {
+ m_ww->setCenteringEnabled(true);
+ scroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ scroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ }
+ m_ww->forceInitialResize();
+}
diff --git a/src/bench/benchlivenodeengine.h b/src/bench/benchlivenodeengine.h
new file mode 100644
index 0000000..9c19df2
--- /dev/null
+++ b/src/bench/benchlivenodeengine.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include "livenodeengine.h"
+
+class BenchQuickView;
+class WindowWidget;
+class PreviewImageProvider;
+class WorkspaceView;
+class BenchLiveNodeEngine : public LiveNodeEngine
+{
+ Q_OBJECT
+
+public:
+ BenchLiveNodeEngine(QObject* parent = 0);
+
+ void setWorkspaceView(WorkspaceView* view);
+ void setWindowWidget(WindowWidget *widget);
+
+public slots:
+ void refresh();
+ void reloadDocument();
+
+signals:
+ void viewChanged(BenchQuickView *view);
+
+protected:
+ void initPlugins();
+ void reloadHelper();
+
+ virtual QQuickView* initView();
+
+private Q_SLOTS:
+ QImage convertIconToImage(const QFileInfo& info, const QSize& requestedSize);
+ void onHeightChanged(int height);
+ void onWidthChanged(int width);
+ void onSizeChanged(const QSize& size);
+
+private:
+ BenchQuickView *m_view;
+ WindowWidget* m_ww;
+ QPointer<PreviewImageProvider> m_imageProvider;
+ WorkspaceView* m_workspaceView;
+ bool m_ignoreCache;
+ bool m_clipToRootObject;
+};
diff --git a/src/bench/benchquickview.cpp b/src/bench/benchquickview.cpp
new file mode 100644
index 0000000..afcfcef
--- /dev/null
+++ b/src/bench/benchquickview.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "benchquickview.h"
+#include "QDebug"
+#include "QGraphicsObject"
+
+BenchQuickView::BenchQuickView(QWindow *parent) :
+ QQuickView(parent)
+{
+}
+
+void BenchQuickView::resizeEvent(QResizeEvent *event)
+{
+ emit sizeChanged(size());
+
+ QQuickView::resizeEvent(event);
+}
diff --git a/src/bench/benchquickview.h b/src/bench/benchquickview.h
new file mode 100644
index 0000000..9bb9737
--- /dev/null
+++ b/src/bench/benchquickview.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QQuickView>
+
+class BenchQuickView : public QQuickView
+{
+ Q_OBJECT
+public:
+ explicit BenchQuickView(QWindow *parent = 0);
+
+signals:
+ void sizeChanged(const QSize &size);
+protected:
+ void resizeEvent(QResizeEvent * event);
+
+};
diff --git a/src/bench/directorypreviewadapter.cpp b/src/bench/directorypreviewadapter.cpp
new file mode 100644
index 0000000..c879308
--- /dev/null
+++ b/src/bench/directorypreviewadapter.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "directorypreviewadapter.h"
+#include <QFileInfo>
+#include <QDir>
+#include <QQmlContext>
+#include <QQmlEngine>
+
+DirectoryPreviewAdapter::DirectoryPreviewAdapter(QObject *parent) :
+ QObject(parent)
+{
+}
+
+bool DirectoryPreviewAdapter::canPreview(const QString &path) const
+{
+ Q_UNUSED(path);
+
+ return false;
+}
+
+QImage DirectoryPreviewAdapter::preview(const QString &path, const QSize &requestedSize)
+{
+ Q_UNUSED(path);
+ Q_UNUSED(requestedSize);
+
+ return QImage();
+}
+
+
+bool DirectoryPreviewAdapter::isFullScreen() const
+{
+ return true;
+}
+
+bool DirectoryPreviewAdapter::canAdapt(const QUrl &url) const
+{
+ QFileInfo info(url.toLocalFile());
+ return info.isDir();
+}
+QUrl DirectoryPreviewAdapter::adapt(const QUrl &url, QQmlContext *context)
+{
+ QDir dir(url.toLocalFile());
+
+ context->setContextProperty("files", dir.entryList(QDir::Files | QDir::NoDotDot | QDir::NoDot | QDir::NoSymLinks));
+ context->setContextProperty("path", url.toLocalFile());
+ context->setContextProperty("adapter", this);
+
+ if (availableFeatures().testFlag(QtQuickControls))
+ return QUrl("qrc:/livert/folderview_qt5_controls.qml");
+
+ return QUrl("qrc:/livert/folderview_qt5.qml");
+}
+
diff --git a/src/bench/directorypreviewadapter.h b/src/bench/directorypreviewadapter.h
new file mode 100644
index 0000000..fe926c8
--- /dev/null
+++ b/src/bench/directorypreviewadapter.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include "contentadapterinterface.h"
+
+class QDeclarativeContext;
+class DirectoryPreviewAdapter : public QObject, public ContentAdapterInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(ContentAdapterInterface)
+public:
+ explicit DirectoryPreviewAdapter(QObject *parent = 0);
+
+ bool canPreview(const QString& path) const;
+ QImage preview(const QString& path, const QSize &requestedSize);
+
+ bool isFullScreen() const;
+
+ bool canAdapt(const QUrl& url) const;
+ virtual QUrl adapt(const QUrl& url, QQmlContext* context);
+
+Q_SIGNALS:
+
+ void loadDocument(const QString& path);
+};
diff --git a/src/bench/dummydelegate.cpp b/src/bench/dummydelegate.cpp
new file mode 100644
index 0000000..ac7bc43
--- /dev/null
+++ b/src/bench/dummydelegate.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "dummydelegate.h"
+
+DummyDelegate::DummyDelegate(QObject *parent) :
+ QItemDelegate(parent)
+{
+}
+
+QSize DummyDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ Q_UNUSED(option)
+ Q_UNUSED(index)
+
+ return QSize(280, 100);
+}
+
+void DummyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ Q_UNUSED(painter)
+ Q_UNUSED(option)
+ Q_UNUSED(index)
+}
diff --git a/src/bench/dummydelegate.h b/src/bench/dummydelegate.h
new file mode 100644
index 0000000..3fae85f
--- /dev/null
+++ b/src/bench/dummydelegate.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QItemDelegate>
+
+class DummyDelegate : public QItemDelegate
+{
+ Q_OBJECT
+public:
+ explicit DummyDelegate(QObject *parent = 0);
+
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
diff --git a/src/bench/host.cpp b/src/bench/host.cpp
new file mode 100644
index 0000000..d97fd74
--- /dev/null
+++ b/src/bench/host.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "host.h"
+#include <QDebug>
+#include <QSettings>
+
+Host::Host(Type type, QObject *parent) :
+ QObject(parent),
+ m_port(10234),
+ m_xOffset(0),
+ m_yOffset(0),
+ m_rotation(0),
+ m_type(type),
+ m_online(false),
+ m_followTreeSelection(false)
+{
+}
+
+Host::Host(const Host &host, QObject *parent) :
+ QObject(parent),
+ m_name(host.name()),
+ m_address(host.address()),
+ m_port(host.port()),
+ m_currentFile(host.currentFile()),
+ m_xOffset(host.xOffset()),
+ m_yOffset(host.yOffset()),
+ m_rotation(host.rotation()),
+ m_type(host.type()),
+ m_online(host.online()),
+ m_followTreeSelection(host.followTreeSelection()),
+ m_autoDiscoveryId(host.autoDiscoveryId()),
+ m_productVersion(host.productVersion()),
+ m_systemName(host.systemName())
+{
+}
+
+QString Host::name() const
+{
+ return m_name;
+}
+
+QString Host::address() const
+{
+ return m_address;
+}
+
+QString Host::currentFile() const
+{
+ return m_currentFile;
+}
+
+int Host::xOffset() const
+{
+ return m_xOffset;
+}
+
+int Host::yOffset() const
+{
+ return m_yOffset;
+}
+
+int Host::rotation() const
+{
+ return m_rotation;
+}
+
+void Host::setName(QString arg)
+{
+ if (m_name != arg) {
+ m_name = arg;
+ emit nameChanged(arg);
+ }
+}
+
+void Host::setAddress(QString arg)
+{
+ if (m_address != arg) {
+ m_address = arg;
+ emit addressChanged(arg);
+ }
+}
+
+void Host::setCurrentFile(QString arg)
+{
+ m_currentFile = arg;
+ emit currentFileChanged(arg);
+}
+
+void Host::setXOffset(int arg)
+{
+ if (m_xOffset != arg) {
+ m_xOffset = arg;
+ emit xOffsetChanged(arg);
+ }
+}
+
+void Host::setYOffset(int arg)
+{
+ if (m_yOffset != arg) {
+ m_yOffset = arg;
+ emit yOffsetChanged(arg);
+ }
+}
+
+void Host::setRotation(int arg)
+{
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+}
+
+void Host::setOnline(bool arg)
+{
+ if (m_online != arg) {
+ m_online = arg;
+ emit onlineChanged(arg);
+ }
+}
+
+void Host::setFollowTreeSelection(bool arg)
+{
+ if (m_followTreeSelection != arg) {
+ m_followTreeSelection = arg;
+ emit followTreeSelectionChanged(arg);
+ }
+}
+
+void Host::setAutoDiscoveryId(QUuid arg)
+{
+ if (m_autoDiscoveryId != arg) {
+ m_autoDiscoveryId = arg;
+ emit autoDiscoveryIdChanged(arg);
+ }
+}
+
+void Host::setProductVersion(QString arg)
+{
+ m_productVersion = arg;
+}
+
+void Host::setSystemName(QString arg)
+{
+ m_systemName = arg;
+}
+
+void Host::setPort(int arg)
+{
+ if (m_port != arg) {
+ m_port = arg;
+ emit portChanged(arg);
+ }
+}
+
+Host::Type Host::type() const
+{
+ return m_type;
+}
+
+bool Host::online() const
+{
+ return m_online;
+}
+
+bool Host::followTreeSelection() const
+{
+ return m_followTreeSelection;
+}
+
+void Host::saveToSettings(QSettings *s)
+{
+ Q_ASSERT(s);
+
+ s->setValue("name", name());
+ s->setValue("address", address());
+ s->setValue("port", port());
+ s->setValue("type", type());
+ s->setValue("followTreeSelection", followTreeSelection());
+ s->setValue("xOffset", xOffset());
+ s->setValue("yOffset", yOffset());
+ s->setValue("rotation", rotation());
+ s->setValue("currentFile", currentFile());
+ s->setValue("autoDiscoveryId", autoDiscoveryId().toString());
+ s->setValue("systemName", systemName());
+ s->setValue("productVersion", productVersion());
+}
+
+void Host::restoreFromSettings(QSettings *s)
+{
+ Q_ASSERT(s);
+
+ setName(s->value("name").toString());
+ setAddress(s->value("address").toString());
+ setPort(s->value("port").toInt());
+ m_type = static_cast<Host::Type>(s->value("type").toInt());
+ setFollowTreeSelection(s->value("followTreeSelection").toBool());
+ setXOffset(s->value("xOffset").toInt());
+ setYOffset(s->value("yOffset").toInt());
+ setRotation(s->value("rotation").toInt());
+ setCurrentFile(s->value("currentFile").toString());
+ setAutoDiscoveryId(QUuid(s->value("autoDiscoveryId").toString()));
+ setSystemName(s->value("systemName").toString());
+ setProductVersion(s->value("productVersion").toString());
+}
+
+QString Host::productVersion() const
+{
+ return m_productVersion;
+}
+
+QString Host::systemName() const
+{
+ return m_systemName;
+}
+
+QUuid Host::autoDiscoveryId() const
+{
+ return m_autoDiscoveryId;
+}
+
+int Host::port() const
+{
+ return m_port;
+}
diff --git a/src/bench/host.h b/src/bench/host.h
new file mode 100644
index 0000000..9db349e
--- /dev/null
+++ b/src/bench/host.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QUuid>
+#include <QMetaType>
+
+class QSettings;
+class Host : public QObject
+{
+ Q_OBJECT
+public:
+ enum Type {
+ AutoDiscovery,
+ Manual
+ };
+
+ //If you add properties here, you maybe also have to change the hostform.ui and the hostform.h (HostChanges)
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged)
+ Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged)
+ Q_PROPERTY(QString currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged)
+ Q_PROPERTY(int xOffset READ xOffset WRITE setXOffset NOTIFY xOffsetChanged)
+ Q_PROPERTY(int yOffset READ yOffset WRITE setYOffset NOTIFY yOffsetChanged)
+ Q_PROPERTY(int rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(bool online READ online WRITE setOnline NOTIFY onlineChanged)
+ Q_PROPERTY(bool followTreeSelection READ followTreeSelection WRITE setFollowTreeSelection NOTIFY followTreeSelectionChanged)
+ Q_PROPERTY(QUuid autoDiscoveryId READ autoDiscoveryId WRITE setAutoDiscoveryId NOTIFY autoDiscoveryIdChanged)
+ Q_PROPERTY(QString productVersion READ productVersion WRITE setProductVersion)
+ Q_PROPERTY(QString systemName READ systemName WRITE setSystemName)
+
+ explicit Host(Type type = Manual, QObject *parent = 0);
+ Host(const Host& host, QObject *parent = 0);
+
+ QString name() const;
+ QString address() const;
+ int port() const;
+ QString currentFile() const;
+ int xOffset() const;
+ int yOffset() const;
+ int rotation() const;
+ Type type() const;
+
+ bool online() const;
+ bool followTreeSelection() const;
+ QUuid autoDiscoveryId() const;
+ QString productVersion() const;
+ QString systemName() const;
+
+
+ void saveToSettings(QSettings *s);
+ void restoreFromSettings(QSettings *s);
+
+signals:
+
+ void nameChanged(QString arg);
+ void addressChanged(QString arg);
+ void portChanged(int arg);
+ void currentFileChanged(QString arg);
+ void xOffsetChanged(int arg);
+ void yOffsetChanged(int arg);
+ void rotationChanged(int arg);
+ void onlineChanged(bool arg);
+ void followTreeSelectionChanged(bool arg);
+ void autoDiscoveryIdChanged(QUuid arg);
+
+
+public slots:
+
+ void setName(QString arg);
+ void setAddress(QString arg);
+ void setPort(int arg);
+ void setCurrentFile(QString arg);
+ void setXOffset(int arg);
+ void setYOffset(int arg);
+ void setRotation(int arg);
+ void setOnline(bool arg);
+ void setFollowTreeSelection(bool arg);
+ void setAutoDiscoveryId(QUuid arg);
+ void setProductVersion(QString arg);
+ void setSystemName(QString arg);
+
+private:
+
+ QString m_name;
+ QString m_address;
+ int m_port;
+ QString m_currentFile;
+ int m_xOffset;
+ int m_yOffset;
+ int m_rotation;
+ Type m_type;
+ bool m_online;
+ bool m_followTreeSelection;
+ QUuid m_autoDiscoveryId;
+ QString m_productVersion;
+ QString m_systemName;
+};
+
+Q_DECLARE_METATYPE( Host* )
+
diff --git a/src/bench/hostdiscoverymanager.cpp b/src/bench/hostdiscoverymanager.cpp
new file mode 100644
index 0000000..db37de4
--- /dev/null
+++ b/src/bench/hostdiscoverymanager.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "hostdiscoverymanager.h"
+#include "hostmodel.h"
+
+HostDiscoveryManager::HostDiscoveryManager(QObject *parent) :
+ QObject(parent) ,
+ m_discoverymodel(new HostModel(this)),
+ m_knownhostsmodel(0)
+{
+}
+
+void HostDiscoveryManager::rescan()
+{
+}
+
+void HostDiscoveryManager::setKnownHostsModel(HostModel *model)
+{
+ m_knownhostsmodel = model;
+}
+
+HostModel *HostDiscoveryManager::knownHostsModel() const
+{
+ return m_knownhostsmodel;
+}
+
+HostModel *HostDiscoveryManager::discoveredHostsModel() const
+{
+ return m_discoverymodel;
+}
+
+void HostDiscoveryManager::deviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(type);
+ Q_UNUSED(version);
+ Q_UNUSED(domain);
+}
+
+void HostDiscoveryManager::deviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(type);
+ Q_UNUSED(version);
+ Q_UNUSED(domain);
+}
+
+void HostDiscoveryManager::deviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(type);
+ Q_UNUSED(version);
+ Q_UNUSED(domain);
+}
+
+void HostDiscoveryManager::serviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(type);
+ Q_UNUSED(version);
+ Q_UNUSED(domain);}
+
+void HostDiscoveryManager::serviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(type);
+ Q_UNUSED(version);
+ Q_UNUSED(domain);}
+
+void HostDiscoveryManager::serviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(type);
+ Q_UNUSED(version);
+ Q_UNUSED(domain);}
+
+void HostDiscoveryManager::updateHostFromExtraValues(Host* host, QMap<QString, QStringList> extraValues)
+{
+ Q_UNUSED(host);
+ Q_UNUSED(extraValues);
+}
+
+bool HostDiscoveryManager::checkExtraValues(QMap<QString, QStringList> extraValues)
+{
+ Q_UNUSED(extraValues);
+ return true;
+}
+
+void HostDiscoveryManager::serviceAlive(const QUuid &uuid, const QString &type, int version, const QString &domain)
+{
+ Q_UNUSED(uuid);
+ Q_UNUSED(type);
+ Q_UNUSED(version);
+ Q_UNUSED(domain);
+}
diff --git a/src/bench/hostdiscoverymanager.h b/src/bench/hostdiscoverymanager.h
new file mode 100644
index 0000000..38b23d0
--- /dev/null
+++ b/src/bench/hostdiscoverymanager.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QtCore>
+
+class HostModel;
+class Host;
+class HostDiscoveryManager : public QObject
+{
+ Q_OBJECT
+public:
+ explicit HostDiscoveryManager(QObject *parent = 0);
+
+ void rescan();
+
+ void setKnownHostsModel(HostModel* model);
+ HostModel *knownHostsModel() const;
+
+ HostModel *discoveredHostsModel() const;
+
+private slots:
+ void deviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain);
+ void deviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain);
+ void deviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain);
+
+ void serviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain);
+ void serviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain);
+ void serviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain);
+ void serviceAlive(const QUuid &uuid, const QString &type, int version, const QString &domain);
+
+ void updateHostFromExtraValues(Host *host, QMap<QString, QStringList> extraValues);
+ bool checkExtraValues(QMap<QString, QStringList> extraValues);
+
+private:
+ HostModel* m_discoverymodel;
+ HostModel* m_knownhostsmodel;
+};
+
diff --git a/src/bench/hostmanager.cpp b/src/bench/hostmanager.cpp
new file mode 100644
index 0000000..678b7ec
--- /dev/null
+++ b/src/bench/hostmanager.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "hostmanager.h"
+#include "hostmodel.h"
+#include "hostwidget.h"
+#include "dummydelegate.h"
+#include "livehubengine.h"
+#include "logreceiver.h"
+#include "widgets/logview.h"
+#include <QDockWidget>
+
+#include <QDebug>
+
+HostManager::HostManager(QWidget *parent) :
+ QListView(parent)
+{
+ setItemDelegate(new DummyDelegate(this));
+ setFlow(QListView::LeftToRight);
+ setUniformItemSizes(true);
+ setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ setSelectionMode(QAbstractItemView::SingleSelection);
+ setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+ setDragEnabled(true);
+ setDefaultDropAction(Qt::MoveAction);
+ setDragDropMode(QAbstractItemView::InternalMove);
+ viewport()->setAcceptDrops(true);
+ setAcceptDrops(true);
+ setDropIndicatorShown(true);
+
+ viewport()->setAutoFillBackground(false);
+}
+
+void HostManager::setModel(HostModel *model)
+{
+ m_model = model;
+ QListView::setModel(model);
+
+ connect(model, SIGNAL(modelReset()), this, SLOT(modelReseted()));
+}
+
+void HostManager::setLiveHubEngine(LiveHubEngine *engine)
+{
+ m_engine = engine;
+
+ for (int i=0; i < m_model->rowCount(); i++) {
+ HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0)));
+ if (widget)
+ widget->setLiveHubEngine(engine);
+ }
+}
+
+void HostManager::followTreeSelection(const QString &currentFile)
+{
+ for (int i=0; i < m_model->rowCount(); i++) {
+ HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0)));
+ if (widget && widget->followTreeSelection())
+ widget->setCurrentFile(currentFile);
+ }
+}
+
+void HostManager::setCurrentFile(const QString &currentFile)
+{
+ for (int i=0; i < m_model->rowCount(); i++) {
+ HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0)));
+ if (widget)
+ widget->setCurrentFile(currentFile);
+ }
+}
+
+void HostManager::publishAll()
+{
+ for (int i=0; i < m_model->rowCount(); i++) {
+ HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0)));
+ if (widget)
+ widget->publishWorkspace();
+ }
+}
+
+void HostManager::refreshAll()
+{
+ for (int i=0; i < m_model->rowCount(); i++) {
+ HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0)));
+ if (widget)
+ widget->refresh();
+ }
+}
+
+void HostManager::rowsInserted(const QModelIndex &parent, int start, int end)
+{
+ if (parent.isValid())
+ return;
+
+ for (int i=start; i<= end; i++) {
+ addHost(i);
+ }
+}
+
+void HostManager::addHost(int index)
+{
+ HostWidget* widget = new HostWidget();
+ Host* host = m_model->hostAt(index);
+ widget->setLiveHubEngine(m_engine.data());
+ widget->setHost(host);
+ setIndexWidget(m_model->index(index,0), widget);
+ connect(widget, SIGNAL(openHostConfig(Host*)), this, SIGNAL(openHostConfig(Host*)));
+
+ QDockWidget* dock = new QDockWidget(host->name());
+ dock->setObjectName(host->name() + "LogDock");
+ connect(host, SIGNAL(nameChanged(QString)), dock, SLOT(setWindowTitle(QString)));
+ LogView* view = new LogView(false, dock);
+ connect(widget, SIGNAL(remoteLog(int,QString,QUrl,int,int)), view, SLOT(appendToLog(int,QString,QUrl,int,int)));
+ dock->setWidget(view);
+ m_logList.append(dock);
+ emit logWidgetAdded(dock);
+}
+
+void HostManager::rowsAboutToBeRemoved(const QModelIndex & parent, int start, int end)
+{
+ if (parent.isValid())
+ return;
+
+ for (int i=start; i<= end; i++) {
+ QDockWidget* dock = m_logList.takeAt(i);
+ delete dock;
+ }
+}
+
+void HostManager::modelReseted()
+{
+ for (int i=0; i < m_model->rowCount(); i++) {
+ addHost(i);
+ }
+}
diff --git a/src/bench/hostmanager.h b/src/bench/hostmanager.h
new file mode 100644
index 0000000..4b6f7bb
--- /dev/null
+++ b/src/bench/hostmanager.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QListView>
+#include <QPointer>
+
+class LiveHubEngine;
+class HostModel;
+
+class QDockWidget;
+class Host;
+class HostManager : public QListView
+{
+ Q_OBJECT
+public:
+ explicit HostManager(QWidget *parent = 0);
+
+ void setModel(HostModel* model);
+ void setLiveHubEngine(LiveHubEngine* engine);
+
+signals:
+ void logWidgetAdded(QDockWidget* log);
+ void openHostConfig(Host* host);
+
+public slots:
+ void followTreeSelection(const QString& currentFile);
+ void setCurrentFile(const QString& currentFile);
+ void publishAll();
+ void refreshAll();
+
+private slots:
+ void rowsInserted(const QModelIndex& parent, int start, int end);\
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void modelReseted();
+ void addHost(int index);
+
+private:
+ QPointer<LiveHubEngine> m_engine;
+
+ HostModel* m_model;
+ QList<QDockWidget*> m_logList;
+};
+
diff --git a/src/bench/hostmodel.cpp b/src/bench/hostmodel.cpp
new file mode 100644
index 0000000..aa2cbb4
--- /dev/null
+++ b/src/bench/hostmodel.cpp
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "hostmodel.h"
+#include <QDebug>
+#include <QIcon>
+#include <QSettings>
+#include <QMimeData>
+
+HostModel::HostModel(QObject *parent) :
+ QAbstractListModel(parent)
+{
+}
+
+int HostModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return m_hosts.count();
+}
+
+int HostModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+
+ return 5;
+}
+
+QVariant HostModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() < 0 || index.row() >= m_hosts.count())
+ return QVariant();
+
+ Host* host = m_hosts.at(index.row());
+
+ switch (index.column()) {
+ case 0: {
+ switch (role) {
+ case NameRole: return host->name();
+ case AddressRole: return host->address();
+ }
+ break;
+ }
+ case 1: if (role == Qt::DisplayRole) return host->name(); break;
+ case 2: if (role == Qt::DisplayRole) return host->productVersion(); break;
+ case 3: if (role == Qt::DisplayRole) return host->systemName(); break;
+ case 4: if (role == Qt::DisplayRole) return QString("%1:%2").arg(host->address()).arg(host->port()); break;
+ }
+
+ return QVariant();
+}
+
+QVariant HostModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Vertical)
+ return QVariant();
+
+ switch (section) {
+ case 0: if (role == Qt::DisplayRole) return QVariant();
+ case 1: if (role == Qt::DisplayRole) return QString("Name");
+ case 2: if (role == Qt::DisplayRole) return QString("Version");
+ case 3: if (role == Qt::DisplayRole) return QString("System");
+ case 4: if (role == Qt::DisplayRole) return QString("Ip");
+ }
+
+ return QVariant();
+}
+
+void HostModel::addHost(Host *host)
+{
+ Q_ASSERT(host);
+
+ beginInsertRows(QModelIndex(), m_hosts.count(), m_hosts.count());
+ m_hosts.append(host);
+ connect(host, SIGNAL(nameChanged(QString)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(addressChanged(QString)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(portChanged(int)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(followTreeSelectionChanged(bool)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(currentFileChanged(QString)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(xOffsetChanged(int)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(yOffsetChanged(int)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(rotationChanged(int)), this, SLOT(onHostChanged()));
+ connect(host, SIGNAL(onlineChanged(bool)), this, SLOT(onHostChanged()));
+
+ endInsertRows();
+}
+
+void HostModel::removeHost(Host *host)
+{
+ int idx = m_hosts.indexOf(host);
+
+ if (idx == -1)
+ return;
+
+ beginRemoveRows(QModelIndex(), idx, idx);
+ Host *item = m_hosts.takeAt(idx);
+ delete item;
+ endRemoveRows();
+}
+
+void HostModel::removeHost(int index)
+{
+ if (index < 0 || index >= m_hosts.count())
+ return;
+
+ beginRemoveRows(QModelIndex(), index, index);
+ Host *item = m_hosts.takeAt(index);
+ delete item;
+ endRemoveRows();
+}
+
+int HostModel::indexOf(Host *host)
+{
+ return m_hosts.indexOf(host);
+}
+
+void HostModel::clear()
+{
+ beginResetModel();
+ qDeleteAll(m_hosts);
+ m_hosts.clear();
+ endResetModel();
+}
+
+QList<Host *> HostModel::findByAutoDiscoveryId(QUuid id) const
+{
+ QList<Host* > hosts;
+ foreach (Host* host, m_hosts) {
+ if (host->autoDiscoveryId() == id)
+ hosts.append(host);
+ }
+
+ return hosts;
+}
+
+Host *HostModel::hostAt(int index) const
+{
+ if (index < 0 || index >= m_hosts.count())
+ return 0;
+
+ return m_hosts.at(index);
+}
+
+void HostModel::onHostChanged()
+{
+ Host* host = qobject_cast<Host*>(sender());
+
+ if (host) {
+ int idx = m_hosts.indexOf(host);
+ if (idx != -1) {
+ emit dataChanged(index(idx, 0), index(idx, 3));
+ }
+ }
+}
+
+void HostModel::restoreFromSettings(QSettings *s)
+{
+ Q_ASSERT(s);
+
+ beginResetModel();
+ qDeleteAll(m_hosts);
+ m_hosts.clear();
+
+ s->beginGroup("AllHosts");
+ int size = s->beginReadArray("host");
+
+ for (int i=0; i < size; i++) {
+ s->setArrayIndex(i);
+ Host* host = new Host(Host::AutoDiscovery, this);
+ host->restoreFromSettings(s);
+ m_hosts.append(host);
+ }
+
+ s->endArray();
+ s->endGroup();
+
+ endResetModel();
+}
+
+void HostModel::saveToSettings(QSettings *s)
+{
+ Q_ASSERT(s);
+
+ s->beginGroup("AllHosts");
+ s->beginWriteArray("host", m_hosts.size());
+
+ int i=0;
+ foreach (Host* host, m_hosts) {
+ s->setArrayIndex(i++);
+ host->saveToSettings(s);
+ }
+
+ s->endArray();
+ s->endGroup();
+}
+
+bool HostModel::removeRows ( int row, int count, const QModelIndex & parent)
+{
+ if (row < 0 || row >= m_hosts.count() || parent.isValid())
+ return false;
+
+ beginRemoveRows(QModelIndex(), row, row + count -1);
+ for (int i=0; i<count; i++) {
+ Host *item = m_hosts.takeAt(row + i);
+ delete item;
+ }
+ endRemoveRows();
+
+ return true;
+}
+
+bool HostModel::dropMimeData(const QMimeData *data,
+ Qt::DropAction action, int row, int column, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction)
+ return true;
+
+ if (!data->hasFormat("application/x-qabstractitemmodeldatalist"))
+ return false;
+
+ if (column > 0)
+ return false;
+
+ if (row < 0)
+ return false;
+
+ if (parent.isValid())
+ return false;
+
+ QByteArray encoded = data->data("application/x-qabstractitemmodeldatalist");
+ QDataStream stream(&encoded, QIODevice::ReadOnly);
+
+ while (!stream.atEnd())
+ {
+ int sourceRow, sourceCol;
+ QMap<int, QVariant> roleDataMap;
+ stream >> sourceRow >> sourceCol >> roleDataMap;
+
+ if (sourceRow == row -1 || sourceRow == row)
+ return false;
+
+ beginMoveRows(QModelIndex(), sourceRow, sourceRow, QModelIndex(), row);
+ m_hosts.move(sourceRow, (row - sourceRow) > 0 ? row - 1 : row);
+ endMoveRows();
+
+ return true;
+ }
+
+ return false;
+}
+
+Qt::DropActions HostModel::supportedDropActions() const
+{
+ return Qt::MoveAction;
+}
+
+Qt::ItemFlags HostModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
+
+ if (index.isValid())
+ return Qt::ItemIsDragEnabled | defaultFlags;
+ else
+ return Qt::ItemIsDropEnabled | defaultFlags;
+}
diff --git a/src/bench/hostmodel.h b/src/bench/hostmodel.h
new file mode 100644
index 0000000..6b22a62
--- /dev/null
+++ b/src/bench/hostmodel.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QAbstractListModel>
+#include "host.h"
+
+class QSettings;
+class HostModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+
+ enum HostRoles {
+ NameRole = Qt::UserRole,
+ AddressRole
+ };
+
+ explicit HostModel(QObject *parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ void addHost(Host* host);
+ void removeHost(Host* host);
+ void removeHost(int index);
+ int indexOf(Host* host);
+ void clear();
+
+ QList<Host*> findByAutoDiscoveryId(QUuid id) const;
+
+ Host* hostAt(int index) const;
+
+ void restoreFromSettings(QSettings* s);
+ void saveToSettings(QSettings* s);
+
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+protected:
+ Qt::DropActions supportedDropActions() const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+
+private slots:
+ void onHostChanged();
+private:
+ QList<Host*> m_hosts;
+};
+
diff --git a/src/bench/hostsoptionpage.cpp b/src/bench/hostsoptionpage.cpp
new file mode 100644
index 0000000..17e4a7c
--- /dev/null
+++ b/src/bench/hostsoptionpage.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "hostsoptionpage.h"
+#include "ui_hostsoptionpage.h"
+#include "hostmodel.h"
+#include "autodiscoveryhostsdialog.h"
+
+#include <QMenu>
+#include <QDebug>
+
+HostsOptionsPage::HostsOptionsPage(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::HostsOptionPage),
+ m_currentIndex(-1),
+ m_model(0),
+ m_autoDiscoveryDialog(new AutoDiscoveryHostsDialog(this))
+{
+ ui->setupUi(this);
+
+ ui->hostUI->setVisible(false);
+
+ connect(ui->nameField, SIGNAL(textEdited(QString)), this, SLOT(updateName(QString)));
+ connect(ui->ipField, SIGNAL(textEdited(QString)), this, SLOT(updateAddress(QString)));
+ connect(ui->portField, SIGNAL(valueChanged(int)), this, SLOT(updatePort(int)));
+ connect(ui->followTreeSelectionField, SIGNAL(clicked(bool)), this, SLOT(updateFollowTreeSelection(bool)));
+ connect(ui->xField, SIGNAL(valueChanged(int)), this, SLOT(updateXOffset(int)));
+ connect(ui->yField, SIGNAL(valueChanged(int)), this, SLOT(updateYOffset(int)));
+ connect(ui->rotationField, SIGNAL(valueChanged(int)), this, SLOT(updateRotation(int)));
+
+ QMenu* menu = new QMenu(ui->addHostButton);
+ menu->addAction("Auto Discovery...", this, SLOT(showAutoDiscoveryDialog()));
+ menu->addAction("Manual", this, SLOT(addHost()));
+ ui->addHostButton->setMenu(menu);
+
+ connect(ui->removeHostButton, SIGNAL(clicked()), this, SLOT(removeHost()));
+}
+
+HostsOptionsPage::~HostsOptionsPage()
+{
+ delete ui;
+}
+
+void HostsOptionsPage::setHostModel(HostModel *model)
+{
+ m_model = model;
+ m_currentIndex = -1;
+
+ connect(ui->hostsWidget->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+ this, SLOT(onCurrentRowChanged(QModelIndex,QModelIndex)));
+
+ for (int i=0; i< m_model->rowCount(); i++) {
+ Host* host = m_model->hostAt(i);
+ addHost(host);
+ }
+}
+
+void HostsOptionsPage::setDiscoveredHostsModel(HostModel *model)
+{
+ m_autoDiscoveryDialog->setDiscoveredHostsModel(model);
+}
+
+void HostsOptionsPage::apply()
+{
+ for (int i=0; i < ui->hostsWidget->rowCount(); i++) {
+ QTableWidgetItem* item = ui->hostsWidget->item(i, 0);
+ Host* host = item->data(Qt::UserRole).value<Host*>();
+ if (ui->hostsWidget->isRowHidden(i)) {
+ if (host)
+ m_model->removeHost(host);
+ continue;
+ }
+
+ host->setName(item->text());
+ host->setAddress(item->data(Qt::UserRole + 1).toString());
+ host->setPort(item->data(Qt::UserRole + 2).toInt());
+ host->setFollowTreeSelection(item->data(Qt::UserRole + 4).toBool());
+ host->setXOffset(item->data(Qt::UserRole + 5).toInt());
+ host->setYOffset(item->data(Qt::UserRole + 6).toInt());
+ host->setRotation(item->data(Qt::UserRole + 7).toInt());
+
+ if (m_model->indexOf(host) == -1)
+ m_model->addHost(host);
+ }
+
+ m_currentIndex = -1;
+}
+
+void HostsOptionsPage::setHostSelected(Host *host)
+{
+ ui->hostsWidget->selectRow(m_model->indexOf(host));
+}
+
+void HostsOptionsPage::onCurrentRowChanged ( const QModelIndex & current, const QModelIndex & previous )
+{
+ Q_UNUSED(previous);
+
+ if (!current.isValid()) {
+ ui->hostUI->setVisible(false);
+ m_currentIndex = -1;
+ }
+
+ ui->removeHostButton->setEnabled(true);
+
+ m_currentIndex = current.row();
+
+ QTableWidgetItem* typeItem = ui->hostsWidget->item(m_currentIndex, 1);
+
+ QString type = typeItem->text();
+ bool autoDiscovery = (type == "Auto");
+
+ QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0);
+
+ ui->nameField->setText(item->text());
+ ui->typeField->setText(type);
+
+ ui->ipField->setText(item->data(Qt::UserRole + 1).toString());
+ ui->portField->setValue(item->data(Qt::UserRole + 2).toInt());
+ ui->ipLabel->setDisabled(autoDiscovery);
+ ui->ipField->setDisabled(autoDiscovery);
+ ui->portLabel->setDisabled(autoDiscovery);
+ ui->portField->setDisabled(autoDiscovery);
+
+ ui->followTreeSelectionField->setChecked(item->data(Qt::UserRole + 4).toBool());
+
+ ui->xField->setValue(item->data(Qt::UserRole + 5).toInt());
+ ui->yField->setValue(item->data(Qt::UserRole + 6).toInt());
+ ui->rotationField->setValue(item->data(Qt::UserRole + 7).toInt());
+
+ ui->hostUI->setVisible(true);
+}
+
+void HostsOptionsPage::updateName(const QString &name)
+{
+ Q_ASSERT(m_currentIndex != -1);
+
+ ui->hostsWidget->item(m_currentIndex, 0)->setText(name);
+}
+
+void HostsOptionsPage::updateAddress(const QString &address)
+{
+ Q_ASSERT(m_currentIndex != -1);
+
+ QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0);
+
+ ui->hostsWidget->item(m_currentIndex, 2)->setText(QString("%1:%2").arg(address).arg(item->data(Qt::UserRole + 2).toInt()));
+
+ item->setData(Qt::UserRole + 1, address);
+}
+
+void HostsOptionsPage::updatePort(int port)
+{
+ Q_ASSERT(m_currentIndex != -1);
+
+ QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0);
+
+ ui->hostsWidget->item(m_currentIndex, 2)->setText(QString("%1:%2").arg(item->data(Qt::UserRole + 1).toString()).arg(port));
+
+ item->setData(Qt::UserRole + 2, port);
+}
+
+void HostsOptionsPage::updateFollowTreeSelection(bool enabled)
+{
+ Q_ASSERT(m_currentIndex != -1);
+
+ QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0);
+
+ item->setData(Qt::UserRole + 4, enabled);
+}
+
+void HostsOptionsPage::updateXOffset(int offset)
+{
+ Q_ASSERT(m_currentIndex != -1);
+
+ QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0);
+
+ item->setData(Qt::UserRole + 5, offset);
+}
+
+void HostsOptionsPage::updateYOffset(int offset)
+{
+ Q_ASSERT(m_currentIndex != -1);
+
+ QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0);
+
+ item->setData(Qt::UserRole + 6, offset);
+}
+
+void HostsOptionsPage::updateRotation(int rotation)
+{
+ Q_ASSERT(m_currentIndex != -1);
+
+ QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0);
+
+ item->setData(Qt::UserRole + 7, rotation);
+}
+
+void HostsOptionsPage::addHost(Host *host)
+{
+ if (!host)
+ host = new Host(Host::Manual, m_model);
+
+ int count = ui->hostsWidget->rowCount();
+ ui->hostsWidget->setRowCount(count + 1);
+
+ QTableWidgetItem* item = new QTableWidgetItem(host->name());
+ ui->hostsWidget->setItem(count, 0, item);
+
+ item->setData(Qt::UserRole, QVariant::fromValue(host));
+ item->setData(Qt::UserRole + 1, host->address());
+ item->setData(Qt::UserRole + 2, host->port());
+ item->setData(Qt::UserRole + 4, host->followTreeSelection());
+ item->setData(Qt::UserRole + 5, host->xOffset());
+ item->setData(Qt::UserRole + 6, host->yOffset());
+ item->setData(Qt::UserRole + 7, host->rotation());
+
+ ui->hostsWidget->setItem(count, 1, new QTableWidgetItem(host->type() == Host::AutoDiscovery ? "Auto" : "Manual"));
+ ui->hostsWidget->setItem(count, 2, new QTableWidgetItem(QString("%1:%2").arg(host->address()).arg(host->port())));
+}
+
+void HostsOptionsPage::removeHost()
+{
+ if (m_currentIndex == -1)
+ return;
+
+ ui->hostsWidget->hideRow(m_currentIndex);
+
+ ui->hostsWidget->clearSelection();
+ ui->hostUI->setVisible(false);
+ ui->removeHostButton->setEnabled(false);
+ m_currentIndex = -1;
+}
+
+void HostsOptionsPage::showAutoDiscoveryDialog()
+{
+ m_autoDiscoveryDialog->clearSelection();
+ if (m_autoDiscoveryDialog->exec()) {
+ QList<QPointer<Host> > hostList = m_autoDiscoveryDialog->selectedHosts();
+ foreach (QPointer<Host> host, hostList) {
+ if (!host)
+ continue;
+
+ addHost(new Host(*host, m_model));
+ }
+ }
+}
diff --git a/src/bench/hostsoptionpage.h b/src/bench/hostsoptionpage.h
new file mode 100644
index 0000000..c4a1b2e
--- /dev/null
+++ b/src/bench/hostsoptionpage.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QWidget>
+#include <QModelIndex>
+
+namespace Ui {
+class HostsOptionPage;
+}
+
+class Host;
+class HostModel;
+class QMenu;
+class AutoDiscoveryHostsDialog;
+
+class HostsOptionsPage : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit HostsOptionsPage(QWidget *parent = 0);
+ ~HostsOptionsPage();
+
+ void setHostModel(HostModel* model);
+ void setDiscoveredHostsModel(HostModel* model);
+
+ void apply();
+
+ void setHostSelected(Host* host);
+
+private slots:
+ void onCurrentRowChanged(const QModelIndex &current, const QModelIndex &previous);
+
+ void updateName(const QString& name);
+ void updateAddress(const QString& address);
+ void updatePort(int port);
+ void updateFollowTreeSelection(bool enabled);
+ void updateXOffset(int offset);
+ void updateYOffset(int offset);
+ void updateRotation(int rotation);
+
+ void addHost(Host* host = 0);
+ void removeHost();
+
+ void showAutoDiscoveryDialog();
+
+private:
+ Ui::HostsOptionPage *ui;
+
+ int m_currentIndex;
+ HostModel* m_model;
+ AutoDiscoveryHostsDialog* m_autoDiscoveryDialog;
+};
+
diff --git a/src/bench/hostsoptionpage.ui b/src/bench/hostsoptionpage.ui
new file mode 100644
index 0000000..dc77d21
--- /dev/null
+++ b/src/bench/hostsoptionpage.ui
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HostsOptionPage</class>
+ <widget class="QWidget" name="HostsOptionPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>390</width>
+ <height>546</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTableWidget" name="hostsWidget">
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="columnCount">
+ <number>3</number>
+ </property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>IP</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QToolButton" name="addHostButton">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::NoArrow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeHostButton">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QFrame" name="hostUI">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameField"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="typeLabel">
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="typeField">
+ <property name="text">
+ <string>Auto</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="ipLabel">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>IP:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLineEdit" name="ipField"/>
+ </item>
+ <item>
+ <widget class="QLabel" name="portLabel">
+ <property name="text">
+ <string>Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="portField">
+ <property name="maximum">
+ <number>99999</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QCheckBox" name="followTreeSelectionField">
+ <property name="text">
+ <string>Follow Tree Selection</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Remote Setup</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="2" column="0">
+ <widget class="QLabel" name="xLabel">
+ <property name="text">
+ <string>X:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QSpinBox" name="xField">
+ <property name="maximum">
+ <number>99999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="yLabel">
+ <property name="text">
+ <string>Y:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="yField">
+ <property name="maximum">
+ <number>99999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="rotationLabel">
+ <property name="text">
+ <string>Rotation:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QSpinBox" name="rotationField">
+ <property name="minimum">
+ <number>-360</number>
+ </property>
+ <property name="maximum">
+ <number>360</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/bench/hostwidget.cpp b/src/bench/hostwidget.cpp
new file mode 100644
index 0000000..2c41373
--- /dev/null
+++ b/src/bench/hostwidget.cpp
@@ -0,0 +1,431 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "hostwidget.h"
+
+#include <QGroupBox>
+#include <QLabel>
+#include <QFormLayout>
+#include <QGridLayout>
+#include <QPushButton>
+#include <QDropEvent>
+#include <QDragEnterEvent>
+#include <QMimeData>
+#include <QProgressBar>
+#include <QMenu>
+#include <QMessageBox>
+#include <QInputDialog>
+#include <QToolButton>
+#include <QDebug>
+
+#include "host.h"
+#include "livehubengine.h"
+
+HostWidget::HostWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ setAcceptDrops(true);
+
+ setFixedHeight(155);
+
+ QGridLayout* layout = new QGridLayout(this);
+ m_groupBox = new QGroupBox();
+ layout->addWidget(m_groupBox);
+
+ QVBoxLayout* vbox = new QVBoxLayout(m_groupBox);
+ QFormLayout* formLayout = new QFormLayout();
+ formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+ m_ipLabel = new QLabel(m_groupBox);
+ m_fileLabel = new QLabel(m_groupBox);
+ m_statusLabel = new QLabel(m_groupBox);
+
+ formLayout->addRow("IP:", m_ipLabel);
+ formLayout->addRow("File:", m_fileLabel);
+ formLayout->addRow("Status:",m_statusLabel);
+
+ m_groupBox->installEventFilter(this);
+
+ vbox->addLayout(formLayout);
+
+ m_sendProgress = new QProgressBar(m_groupBox);
+ m_sendProgress->setMaximum(1);
+ m_sendProgress->setValue(1);
+ m_menuButton = new QToolButton(m_groupBox);
+ m_menuButton->setText("...");
+ m_menuButton->setMinimumWidth(35);
+ m_menuButton->setPopupMode(QToolButton::InstantPopup);
+ m_menuButton->setCheckable(true);
+
+ QHBoxLayout* hbox = new QHBoxLayout();
+ hbox->addWidget(m_sendProgress);
+ hbox->addWidget(m_menuButton);
+
+ vbox->addLayout(hbox);
+
+
+ m_menu = new QMenu(this);
+ m_connectDisconnectAction = m_menu->addAction("Connect", this, SLOT(connectAndSendFile()));
+ m_refreshAction = m_menu->addAction("Refresh", this, SLOT(refresh()));
+ m_publishAction = m_menu->addAction("Publish All", this, SLOT(publishAll()));
+ m_followTreeSelectionAction = m_menu->addAction("Follow Tree Selection");
+ m_followTreeSelectionAction->setCheckable(true);
+ m_editHostAction = m_menu->addAction("Edit Host", this, SLOT(onEditHost()));
+
+ m_menuButton->setMenu(m_menu);
+
+ connect(&m_publisher, SIGNAL(connected()), this, SIGNAL(connected()));
+ connect(&m_publisher, SIGNAL(connected()), this, SLOT(onConnected()));
+ connect(&m_publisher, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
+ connect(&m_publisher, SIGNAL(connectionError(QAbstractSocket::SocketError)),
+ this, SLOT(onConnectionError(QAbstractSocket::SocketError)));
+ connect(&m_publisher, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)),
+ this, SLOT(onSendingError(QUuid,QAbstractSocket::SocketError)));
+ connect(&m_publisher, SIGNAL(sentSuccessfully(QUuid)),
+ this, SLOT(onSentSuccessfully(QUuid)));
+ connect(&m_publisher, SIGNAL(needsPinAuthentication()), this, SLOT(showPinDialog()));
+ connect(&m_publisher, SIGNAL(pinOk(bool)), this, SLOT(onPinOk(bool)));
+ connect(&m_publisher, SIGNAL(remoteLog(int,QString,QUrl,int,int)),
+ this, SIGNAL(remoteLog(int,QString,QUrl,int,int)));
+
+ onDisconnected();
+}
+
+void HostWidget::setHost(Host *host)
+{
+ m_host = host;
+
+ updateName(m_host->name());
+ updateIp(m_host->address());
+ updateFile(m_host->currentFile());
+ updateOnlineState(m_host->online());
+ m_followTreeSelectionAction->setChecked(m_host->followTreeSelection());
+
+ connect(host, SIGNAL(addressChanged(QString)), this, SLOT(updateIp(QString)));
+ connect(host, SIGNAL(portChanged(int)), this, SLOT(updatePort(int)));
+ connect(host, SIGNAL(onlineChanged(bool)), this, SLOT(updateOnlineState(bool)));
+ connect(host, SIGNAL(currentFileChanged(QString)), this, SLOT(updateFile(QString)));
+ connect(host, SIGNAL(nameChanged(QString)), this, SLOT(updateName(QString)));
+ connect(host, SIGNAL(xOffsetChanged(int)), this, SLOT(sendXOffset(int)));
+ connect(host, SIGNAL(yOffsetChanged(int)), this, SLOT(sendYOffset(int)));
+ connect(host, SIGNAL(rotationChanged(int)), this, SLOT(sendRotation(int)));
+ connect(host, SIGNAL(followTreeSelectionChanged(bool)),
+ m_followTreeSelectionAction, SLOT(setChecked(bool)));
+
+ connect(m_followTreeSelectionAction, SIGNAL(triggered(bool)), host, SLOT(setFollowTreeSelection(bool)));
+}
+
+void HostWidget::setLiveHubEngine(LiveHubEngine *engine)
+{
+ m_engine = engine;
+
+ m_publisher.setWorkspace(m_engine->workspace());
+
+ connect(m_engine.data(), SIGNAL(workspaceChanged(QString)), &m_publisher, SLOT(setWorkspace(QString)));
+ connect(m_engine.data(), SIGNAL(fileChanged(QString)), this, SLOT(sendDocument(QString)));
+}
+
+void HostWidget::setCurrentFile(const QString currentFile)
+{
+ m_host->setCurrentFile(currentFile);
+}
+
+bool HostWidget::followTreeSelection() const
+{
+ return m_followTreeSelectionAction->isChecked();
+}
+
+void HostWidget::updateName(const QString &name)
+{
+ m_groupBox->setTitle(name);
+}
+
+void HostWidget::updateIp(const QString &ip)
+{
+ m_ipLabel->setText(QString("%1:%2").arg(ip).arg(m_host->port()));
+
+ QTimer::singleShot(0, this, SLOT(connectToServer()));
+}
+
+void HostWidget::updatePort(int port)
+{
+ m_ipLabel->setText(QString("%1:%2").arg(m_host->address()).arg(port));
+
+ QTimer::singleShot(0, this, SLOT(connectToServer()));
+}
+
+void HostWidget::updateFile(const QString &file)
+{
+ QString relFile = QDir(m_engine->workspace()).relativeFilePath(file);
+ setUpdateFile(relFile);
+ m_fileLabel->setToolTip(relFile);
+
+ connectAndSendFile();
+}
+
+void HostWidget::setUpdateFile(const QString &file)
+{
+ QFontMetrics metrics(font());
+ m_fileLabel->setText(metrics.elidedText(file, Qt::ElideLeft, m_fileLabel->width()));
+}
+
+void HostWidget::updateOnlineState(bool online)
+{
+ qDebug() << "updateOnline";
+
+ bool available = online || m_host->type() == Host::Manual;
+
+ if (available)
+ QTimer::singleShot(0, this, SLOT(connectToServer()));
+ else
+ onDisconnected();
+}
+
+void HostWidget::connectToServer()
+{
+ qDebug() << "connectToServer";
+
+ if (m_publisher.state() == QAbstractSocket::ConnectedState || m_publisher.state() == QAbstractSocket::ConnectingState) {
+ return;
+ }
+
+ if (m_host->online() || m_host->type() == Host::Manual) {
+ m_publisher.connectToServer(m_host->address(), m_host->port());
+ m_activateId = QUuid();
+ m_rotationId = QUuid();
+ m_xOffsetId = QUuid();
+ m_yOffsetId = QUuid();
+ m_changeIds.clear();
+ }
+}
+
+void HostWidget::connectAndSendFile()
+{
+ connectToServer();
+ m_activateId = m_publisher.activateDocument(QDir(m_engine->workspace()).relativeFilePath(m_host->currentFile()));
+}
+
+void HostWidget::onConnected()
+{
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png"));
+ m_statusLabel->setToolTip("Host online");
+
+ sendXOffset(m_host->xOffset());
+ sendYOffset(m_host->yOffset());
+ sendRotation(m_host->rotation());
+
+ m_connectDisconnectAction->setText("Disconnect");
+ disconnect(m_connectDisconnectAction, SIGNAL(triggered()), 0, 0);
+ connect(m_connectDisconnectAction, SIGNAL(triggered()), &m_publisher, SLOT(disconnectFromServer()));
+}
+
+void HostWidget::onDisconnected()
+{
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_offline.png"));
+ m_statusLabel->setToolTip("Host offline");
+
+ m_connectDisconnectAction->setText("Connect");
+ disconnect(m_connectDisconnectAction, SIGNAL(triggered()), 0, 0);
+ connect(m_connectDisconnectAction, SIGNAL(triggered()), this, SLOT(connectToServer()));
+}
+
+void HostWidget::onConnectionError(QAbstractSocket::SocketError error)
+{
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png"));
+ m_statusLabel->setToolTip(m_publisher.errorToString(error));
+
+ if (error == QAbstractSocket::RemoteHostClosedError)
+ m_host->setOnline(false);
+
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ onDisconnected();
+}
+
+void HostWidget::refresh()
+{
+ connectAndSendFile();
+}
+
+void HostWidget::publishWorkspace()
+{
+ connectToServer();
+ connect(m_engine.data(), SIGNAL(publishFile(QString)), this, SLOT(sendDocument(QString)));
+ m_engine->publishWorkspace();
+ disconnect(m_engine.data(), SIGNAL(publishFile(QString)), this, SLOT(sendDocument(QString)));
+}
+
+void HostWidget::sendDocument(const QString& document)
+{
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ return;
+
+ m_changeIds.append(m_publisher.sendDocument(document));
+ m_sendProgress->setMaximum(m_sendProgress->maximum() + 1);
+}
+
+void HostWidget::sendXOffset(int offset)
+{
+ m_xOffsetId = m_publisher.setXOffset(offset);
+}
+
+void HostWidget::sendYOffset(int offset)
+{
+ m_yOffsetId = m_publisher.setYOffset(offset);
+}
+
+void HostWidget::sendRotation(int rotation)
+{
+ m_rotationId = m_publisher.setRotation(rotation);
+}
+
+void HostWidget::onSendingError(const QUuid &uuid, QAbstractSocket::SocketError socketError)
+{
+ if (uuid == m_activateId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png"));
+ m_statusLabel->setToolTip(QString("Activating file failed: %1").arg(m_publisher.errorToString(socketError)));
+ m_activateId = QUuid();
+ } else if (uuid == m_xOffsetId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png"));
+ m_statusLabel->setToolTip(QString("Setting the X Offset failed: %1").arg(m_publisher.errorToString(socketError)));
+ m_xOffsetId = QUuid();
+ } else if (uuid == m_yOffsetId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png"));
+ m_statusLabel->setToolTip(QString("Setting the Y Offset failed: %1").arg(m_publisher.errorToString(socketError)));
+ m_yOffsetId = QUuid();
+ } else if (uuid == m_rotationId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png"));
+ m_statusLabel->setToolTip(QString("Setting the Rotation failed: %1").arg(m_publisher.errorToString(socketError)));
+ m_rotationId = QUuid();
+ }else if (m_changeIds.contains(uuid)) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png"));
+ m_statusLabel->setToolTip(QString("Not all files were synced successfully: %1").arg(m_publisher.errorToString(socketError)));
+ m_changeIds.removeAll(uuid);
+ resetProgressBar();
+ }
+}
+
+void HostWidget::onSentSuccessfully(const QUuid &uuid)
+{
+ if (uuid == m_activateId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png"));
+ m_activateId = QUuid();
+ } else if (uuid == m_xOffsetId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png"));
+ m_xOffsetId = QUuid();
+ } else if (uuid == m_yOffsetId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png"));
+ m_yOffsetId = QUuid();
+ } else if (uuid == m_rotationId) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png"));
+ m_rotationId = QUuid();
+ } else if (m_changeIds.contains(uuid)) {
+ m_changeIds.removeAll(uuid);
+ m_sendProgress->setValue(m_sendProgress->value() + 1);
+ if (m_changeIds.isEmpty()) {
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png"));
+ resetProgressBar();
+ }
+ }
+}
+
+void HostWidget::resetProgressBar()
+{
+ m_sendProgress->setValue(1);
+ m_sendProgress->setMaximum(1);
+}
+
+void HostWidget::onPinOk(bool ok)
+{
+ if (!ok) {
+ m_publisher.disconnectFromServer();
+ m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png"));
+ m_statusLabel->setToolTip("The Host didn't accept your pin");
+ QMessageBox::warning(this, "Pin not accepted", "The Host didn't accept your pin");
+ }
+}
+
+void HostWidget::publishAll()
+{
+ if (QMessageBox::question(this, QString("Publish %1").arg(m_engine->workspace()),
+ QString("Do you really want to publish the content of %1").arg(m_engine->workspace())) == QMessageBox::Yes) {
+ publishWorkspace();
+ }
+}
+
+void HostWidget::onEditHost()
+{
+ emit openHostConfig(m_host);
+}
+
+void HostWidget::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+
+ setUpdateFile(m_fileLabel->toolTip());
+}
+
+void HostWidget::showPinDialog()
+{
+ bool ok = false;
+ int pin = QInputDialog::getInt(this, "The Host needs a Pin Authentication", "Pin", 0, 0, 9999, 1, &ok);
+
+ if (!ok)
+ m_publisher.disconnectFromServer();
+
+ m_publisher.checkPin(QString::number(pin));
+}
+
+void HostWidget::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasFormat("text/uri-list") && (m_host->online() || m_host->type() == Host::Manual)) {
+
+ event->acceptProposedAction();
+ }
+}
+
+void HostWidget::dropEvent(QDropEvent *event)
+{
+ QUrl url(event->mimeData()->text());
+
+ if (url.isLocalFile())
+ m_host->setCurrentFile(url.toLocalFile());
+ event->acceptProposedAction();
+}
+
+bool HostWidget::eventFilter(QObject *object, QEvent *event)
+{
+ if ((event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress) && object == m_groupBox) {
+
+ event->ignore();
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/bench/hostwidget.h b/src/bench/hostwidget.h
new file mode 100644
index 0000000..1725eb1
--- /dev/null
+++ b/src/bench/hostwidget.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QWidget>
+#include <QPointer>
+#include <remotepublisher.h>
+
+class QLabel;
+class QGroupBox;
+class QProgressBar;
+class QPushButton;
+class QToolButton;
+class QMenu;
+class Host;
+class HostWidget : public QWidget
+{
+ Q_OBJECT
+public:
+
+ explicit HostWidget(QWidget *parent = 0);
+
+ void setHost(Host* host);
+ void setLiveHubEngine(LiveHubEngine* engine);
+ void setCurrentFile(const QString currentFile);
+ bool followTreeSelection() const;
+
+signals:
+ void connected();
+ void openHostConfig(Host*);
+ void remoteLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
+
+public slots:
+ void publishWorkspace();
+ void refresh();
+
+protected:
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dropEvent(QDropEvent *event);
+ bool eventFilter(QObject *, QEvent *);
+
+private slots:
+ void updateName(const QString& name);
+ void updateIp(const QString& ip);
+ void updatePort(int port);
+ void updateFile(const QString& file);
+ void setUpdateFile(const QString& file);
+ void updateOnlineState(bool online);
+
+ void connectToServer();
+ void connectAndSendFile();
+
+ void onConnected();
+ void onDisconnected();
+ void onConnectionError(QAbstractSocket::SocketError error);
+
+ void sendDocument(const QString &document);
+
+ void sendXOffset(int offset);
+ void sendYOffset(int offset);
+ void sendRotation(int rotation);
+
+ void onSentSuccessfully(const QUuid &uuid);
+ void onSendingError(const QUuid &uuid, QAbstractSocket::SocketError socketError);
+ void resetProgressBar();
+
+ void showPinDialog();
+ void onPinOk(bool ok);
+
+ void publishAll();
+ void onEditHost();
+
+ void resizeEvent( QResizeEvent * event );
+private:
+
+ QGroupBox* m_groupBox;
+ QLabel* m_ipLabel;
+ QLabel* m_fileLabel;
+ QLabel* m_statusLabel;
+ QProgressBar* m_sendProgress;
+ QToolButton* m_menuButton;
+ QMenu* m_menu;
+ QAction* m_publishAction;
+ QAction* m_followTreeSelectionAction;
+ QAction* m_refreshAction;
+ QAction* m_connectDisconnectAction;
+ QAction* m_editHostAction;
+
+ QPointer<Host> m_host;
+
+ RemotePublisher m_publisher;
+ QPointer<LiveHubEngine> m_engine;
+
+ QUuid m_activateId;
+ QList<QUuid> m_changeIds;
+ QUuid m_xOffsetId;
+ QUuid m_yOffsetId;
+ QUuid m_rotationId;
+};
+
diff --git a/src/bench/httpproxyoptionpage.cpp b/src/bench/httpproxyoptionpage.cpp
new file mode 100644
index 0000000..e9acc65
--- /dev/null
+++ b/src/bench/httpproxyoptionpage.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "httpproxyoptionpage.h"
+#include "ui_httpproxyoptionpage.h"
+#include <QtNetwork>
+
+HttpProxyOptionPage::HttpProxyOptionPage(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::HttpProxyOptionPage)
+{
+ ui->setupUi(this);
+ QSettings s;
+ ui->proxyGroup->setChecked(s.value("http_proxy/enabled").toBool());
+ ui->serverField->setText(s.value("http_proxy/hostname").toString());
+ ui->portField->setText(s.value("http_proxy/port").toString());
+ ui->userField->setText(s.value("http_proxy/username").toString());
+ ui->passwordField->setText(s.value("http_proxy/password").toString());
+}
+
+HttpProxyOptionPage::~HttpProxyOptionPage()
+{
+ delete ui;
+}
+
+void HttpProxyOptionPage::apply()
+{
+ bool enabled = ui->proxyGroup->isChecked();
+ QString hostname = ui->serverField->text();
+ int port = ui->portField->text().toInt();
+ QString username = ui->userField->text();
+ QString password = ui->passwordField->text();
+ if (enabled) {
+ QNetworkProxy proxy;
+ proxy.setType(QNetworkProxy::HttpProxy);
+ proxy.setHostName(hostname);
+ proxy.setPort(port);
+ proxy.setUser(username);
+ proxy.setPassword(password);
+ QNetworkProxy::setApplicationProxy(proxy);
+ } else {
+ QNetworkProxy::setApplicationProxy(QNetworkProxy());
+ }
+ QSettings s;
+ s.setValue("http_proxy/enabled", enabled);
+ s.setValue("http_proxy/hostname", hostname);
+ s.setValue("http_proxy/port", port);
+ s.setValue("http_proxy/username", username);
+ s.setValue("http_proxy/password", password);
+
+}
diff --git a/src/bench/httpproxyoptionpage.h b/src/bench/httpproxyoptionpage.h
new file mode 100644
index 0000000..8ff0db8
--- /dev/null
+++ b/src/bench/httpproxyoptionpage.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtGui>
+
+#include <QtWidgets>
+
+
+namespace Ui {
+class HttpProxyOptionPage;
+}
+
+class HttpProxyOptionPage : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit HttpProxyOptionPage(QWidget *parent = 0);
+ ~HttpProxyOptionPage();
+ void apply();
+private:
+ Ui::HttpProxyOptionPage *ui;
+};
diff --git a/src/bench/httpproxyoptionpage.ui b/src/bench/httpproxyoptionpage.ui
new file mode 100644
index 0000000..f0c0b04
--- /dev/null
+++ b/src/bench/httpproxyoptionpage.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HttpProxyOptionPage</class>
+ <widget class="QWidget" name="HttpProxyOptionPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="proxyGroup">
+ <property name="title">
+ <string>HTTP Proxy</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Server Address:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="serverField"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="portField"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="userField"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="passwordField"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>98</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/bench/importpathoptionpage.cpp b/src/bench/importpathoptionpage.cpp
new file mode 100644
index 0000000..fd95a3e
--- /dev/null
+++ b/src/bench/importpathoptionpage.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "importpathoptionpage.h"
+#include "ui_importpathoptionpage.h"
+
+ImportPathOptionPage::ImportPathOptionPage(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::ImportPathOptionPage)
+{
+ ui->setupUi(this);
+ QSettings s;
+ int count = s.beginReadArray("imports");
+ QListWidgetItem* item;
+ for (int i=0; i<count; i++) {
+ s.setArrayIndex(i);
+ item = new QListWidgetItem(s.value("path").toString());
+ item->setFlags(item->flags () | Qt::ItemIsEditable);
+ ui->importList->addItem(item);
+ }
+ s.endArray();
+
+ connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addItem()));
+ connect(ui->removeButton, SIGNAL(clicked()), this, SLOT(removeItem()));
+ connect(ui->editButton, SIGNAL(clicked()), this, SLOT(editItem()));
+}
+
+ImportPathOptionPage::~ImportPathOptionPage()
+{
+ delete ui;
+}
+
+void ImportPathOptionPage::apply()
+{
+ QStringList paths;
+ QSettings s;
+ s.beginWriteArray("imports");
+ for (int i=0; i<ui->importList->count(); i++) {
+ QString path(ui->importList->item(i)->text());
+ paths << path;
+ s.setArrayIndex(i);
+ s.setValue("path", path);
+ }
+ s.endArray();
+}
+
+void ImportPathOptionPage::addItem()
+{
+ QString path = QFileDialog::getExistingDirectory(this, "Add Import Path");
+ if (path.isEmpty()) {
+ return;
+ }
+ QListWidgetItem* item = new QListWidgetItem(path);
+ item->setFlags(item->flags () | Qt::ItemIsEditable);
+ ui->importList->addItem(item);
+}
+
+void ImportPathOptionPage::removeItem()
+{
+ QListWidgetItem *item = ui->importList->currentItem();
+ if (item) {
+ delete item;
+ }
+}
+
+void ImportPathOptionPage::editItem()
+{
+ QListWidgetItem *item = ui->importList->currentItem();
+ if (item) {
+ ui->importList->editItem(item);
+ }
+}
diff --git a/src/bench/importpathoptionpage.h b/src/bench/importpathoptionpage.h
new file mode 100644
index 0000000..0ee307e
--- /dev/null
+++ b/src/bench/importpathoptionpage.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWidgets>
+
+namespace Ui {
+class ImportPathOptionPage;
+}
+
+class ImportPathOptionPage : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ImportPathOptionPage(QWidget *parent = 0);
+ ~ImportPathOptionPage();
+ void apply();
+private slots:
+ void addItem();
+ void removeItem();
+ void editItem();
+
+private:
+ Ui::ImportPathOptionPage *ui;
+};
diff --git a/src/bench/importpathoptionpage.ui b/src/bench/importpathoptionpage.ui
new file mode 100644
index 0000000..d5ec42f
--- /dev/null
+++ b/src/bench/importpathoptionpage.ui
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ImportPathOptionPage</class>
+ <widget class="QWidget" name="ImportPathOptionPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QListWidget" name="importList"/>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="editButton">
+ <property name="text">
+ <string>Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/bench/main.cpp b/src/bench/main.cpp
new file mode 100644
index 0000000..7eeddcc
--- /dev/null
+++ b/src/bench/main.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QtWidgets>
+
+#include "mainwindow.h"
+
+
+struct Options
+{
+ Options()
+ : stayontop(false)
+ {}
+
+ QString activeDocument;
+ QString workspace;
+ QString pluginPath;
+ QStringList importPaths;
+ bool stayontop;
+};
+
+static Options options;
+
+static void usage()
+{
+ qWarning("Usage qmllivebench [options] <workspace> <file.qml>");
+ qWarning("Usage qmllivebench [options] <workspace/file.qml>");
+ qWarning(" ");
+ qWarning(" options:");
+ qWarning(" -pluginpath ........................path to qmllive plugins");
+ qWarning(" -importpath ........................path to the qml import path");
+ qWarning(" -stayontop .........................keep viewer window on top");
+ qWarning(" ");
+ exit(1);
+}
+
+static void parseArguments(const QStringList& arguments)
+{
+ for (int i = 1; i < arguments.count(); ++i) {
+ bool lastArg = (i == arguments.count() - 1);
+ QString arg = arguments.at(i);
+
+ if (arg == QLatin1String("-pluginpath")) {
+ if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage();
+ options.pluginPath = arguments.at(i);;
+ continue;
+ } else if (arg == QLatin1String("-importpath")) {
+ if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage();
+ options.importPaths.append(QDir(arguments.at(i)).absolutePath());
+ continue;
+ } else if (arg == QLatin1String("-stayontop")) {
+ options.stayontop = true;
+ continue;
+ } else if (arg.startsWith(QLatin1Char('-'))) {
+ usage();
+ return;
+ }
+
+ if (arg.endsWith(".qml")) {
+ qDebug() << "Found argument ending with \".qml\". Assuming it's a file.";
+ if (options.workspace.isEmpty()) {
+ qDebug() << "No workspace is set yet, assuming it's the whole path";
+ QFileInfo fi(arg);
+
+ options.workspace = fi.path();
+
+ if (!fi.exists()) {
+ qWarning() << "File does not exist: " << arg << " trying to set workspace anyway...";
+ }
+ else {
+ options.activeDocument = fi.absoluteFilePath();
+ }
+ }
+ else {
+ QFileInfo fi(arg);
+ if (!fi.exists())
+ qWarning() << "File does not exist: " << arg << "ignoring it.";
+ else
+ options.activeDocument = fi.absoluteFilePath();
+ }
+ }
+ else {
+ options.workspace = arg;
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ app.setApplicationName("QmlLiveBench");
+ app.setOrganizationDomain("pelagicore.com");
+ app.setOrganizationName("Pelagicore");
+ app.setAttribute(Qt::AA_NativeWindows, true);
+ app.setAttribute(Qt::AA_ImmediateWidgetCreation, true);
+ parseArguments(app.arguments());
+
+ //qDebug () << "apply settings...";
+ MainWindow win;
+ if (!options.workspace.isEmpty()) {
+ //qDebug() << "set workspace: " << options.workspace;
+ win.setWorkspace(QDir(options.workspace).absolutePath());
+ }
+ if (!options.pluginPath.isEmpty()) {
+ //qDebug() << "set pluginPath: " << options.pluginPath;
+ win.setPluginPath(QDir(options.pluginPath).absolutePath());
+ }
+ if (!options.importPaths.isEmpty()) {
+ //qDebug() << "set importPaths: " << options.importPaths;
+ win.setImportPaths(options.importPaths);
+ }
+ if (!options.activeDocument.isEmpty()) {
+ //qDebug() << "set active document: " << options.activeDocument;
+ win.activateDocument(options.activeDocument);
+ }
+
+ if (options.stayontop)
+ win.setStaysOnTop(true);
+
+ win.readSettings();
+
+ win.show();
+
+ return app.exec();
+}
diff --git a/src/bench/mainwindow.cpp b/src/bench/mainwindow.cpp
new file mode 100644
index 0000000..f009379
--- /dev/null
+++ b/src/bench/mainwindow.cpp
@@ -0,0 +1,455 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "widgets/windowwidget.h"
+
+#include <QToolBar>
+#include <QtNetwork>
+#include <private/qabstractanimation_p.h>
+
+#include "widgets/workspaceview.h"
+#include "widgets/logview.h"
+#include "livehubengine.h"
+#include "benchlivenodeengine.h"
+#include "qmlhelper.h"
+#include "optionsdialog.h"
+#include "benchquickview.h"
+#include "hostmodel.h"
+#include "hostmanager.h"
+#include "allhostswidget.h"
+#include "hostdiscoverymanager.h"
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , m_qmlview(0)
+ , m_workspace(new WorkspaceView())
+ , m_log(new LogView(true, this))
+ , m_hostManager(new HostManager(this))
+ , m_hostModel(new HostModel(this))
+ , m_discoveryManager(new HostDiscoveryManager(this))
+ , m_allHosts(new AllHostsWidget(this))
+ , m_hub(new LiveHubEngine(this))
+ , m_node(new BenchLiveNodeEngine(this))
+{
+ setupContent();
+ setupMenuBar();
+ setupToolBar();
+
+ m_discoveryManager->setKnownHostsModel(m_hostModel);\
+
+ m_hostManager->setModel(m_hostModel);
+ m_hostManager->setLiveHubEngine(m_hub);
+
+ setWindowIcon(QIcon("://images/favicon.png"));
+
+ m_hub->setFilePublishingActive(true);
+ m_node->setWorkspaceView(m_workspace);
+
+ connect(m_workspace, SIGNAL(pathActivated(QString)), m_hub, SLOT(setActivePath(QString)));
+ connect(m_workspace, SIGNAL(pathActivated(QString)), m_hostManager, SLOT(followTreeSelection(QString)));
+ connect(m_hub, SIGNAL(activateDocument(QString)), this, SLOT(updateWindowTitle()));
+ connect(m_hub, SIGNAL(activateDocument(QString)), m_node, SLOT(setActiveDocument(QString)));
+ connect(m_node, SIGNAL(viewChanged(BenchQuickView*)), this, SLOT(initView(BenchQuickView*)));
+ connect(m_allHosts, SIGNAL(publishAll()), m_hostManager, SLOT(publishAll()));
+ connect(m_allHosts, SIGNAL(currentFileChanged(QString)), m_hostManager, SLOT(setCurrentFile(QString)));
+ connect(m_allHosts, SIGNAL(refreshAll()), m_hostManager, SLOT(refreshAll()));
+ connect(m_hostManager, SIGNAL(logWidgetAdded(QDockWidget*)), this, SLOT(onLogWidgetAdded(QDockWidget*)));
+ connect(m_hostManager, SIGNAL(openHostConfig(Host*)), this, SLOT(openPreferences(Host*)));
+
+ BenchQuickView view;
+ m_qmlDefaultimportList = view.engine()->importPathList();
+}
+
+MainWindow::~MainWindow()
+{
+}
+
+
+void MainWindow::setupContent()
+{
+ setupLogView();
+ setupWorkspaceView();
+ setupHostView();
+
+ m_ww = new WindowWidget(this);
+ m_ww->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ m_ww->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ m_ww->setBackgroundRole(QPalette::Dark);
+ m_node->setWindowWidget(m_ww);
+
+ setCentralWidget(m_ww);
+}
+
+void MainWindow::initView(BenchQuickView *view)
+{
+ m_qmlview = view;
+
+ m_ww->setCenteringEnabled(true);
+ m_ww->setHostedWindow(m_qmlview);
+
+ connect(m_qmlview->engine(), SIGNAL(quit()), this, SLOT(logQuitEvent()));
+}
+
+void MainWindow::onLogWidgetAdded(QDockWidget *logDock)
+{
+ m_logDockMenu->addAction(logDock->toggleViewAction());
+
+ logDock->setFeatures(m_logDock->features());
+ logDock->setAllowedAreas(m_logDock->allowedAreas());
+ addDockWidget(dockWidgetArea(m_logDock), logDock);
+ tabifyDockWidget(m_logDock, logDock);
+}
+
+void MainWindow::setupWorkspaceView()
+{
+ m_workspaceDock = new QDockWidget("Workspace", this);
+ m_workspaceDock->setObjectName("workspace");
+ m_workspaceDock->setWidget(m_workspace);
+ m_workspaceDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
+ m_workspaceDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
+ addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock);
+}
+
+void MainWindow::setupHostView()
+{
+ m_hostDock = new QDockWidget("Hosts", this);
+ m_hostDock->setObjectName("hosts");
+ m_hostDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
+
+ QFrame* hostContainer = new QFrame();
+ hostContainer->setFrameStyle(QFrame::StyledPanel);
+ QHBoxLayout* layout = new QHBoxLayout(hostContainer);
+ QVBoxLayout* vbox = new QVBoxLayout();
+ vbox->addWidget(m_allHosts);
+ vbox->addStretch(1);
+ layout->addLayout(vbox);
+ layout->addWidget(m_hostManager);
+ layout->setContentsMargins(0,0,0,0);
+
+ m_hostDock->setWidget(hostContainer);
+ addDockWidget(Qt::TopDockWidgetArea, m_hostDock);
+}
+
+void MainWindow::setupLogView()
+{
+ m_logDock = new QDockWidget("Log Output", this);
+ m_logDock->setObjectName("log");
+ m_logDock->setWidget(m_log);
+ m_logDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
+ m_logDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
+ addDockWidget(Qt::BottomDockWidgetArea, m_logDock);
+
+ connect(m_node, SIGNAL(logClear()), m_log, SLOT(clear()));
+ connect(m_node, SIGNAL(logIgnoreMessages(bool)), m_log, SLOT(setIgnoreMessages(bool)));
+ connect(m_node, SIGNAL(logErrors(QList<QQmlError>)), m_log, SLOT(appendToLog(QList<QQmlError>)));
+}
+
+void MainWindow::setupMenuBar()
+{
+ QMenu *file = menuBar()->addMenu(tr("&File"));
+ m_openWorkspace = file->addAction(QIcon::fromTheme("folder-open"), tr("&Open Workspace..."), this, SLOT(openWorkspace()), QKeySequence::Open);
+ m_recentMenu = file->addMenu(QIcon::fromTheme("document-open-recent"), "&Recent");
+ m_recentMenu->setEnabled(false);
+ file->addAction(tr("Preferences..."), this, SLOT(openPreferences()), QKeySequence::Preferences);
+ file->addSeparator();
+ file->addAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this, SLOT(close()), QKeySequence::Quit);
+
+ QMenu *view = menuBar()->addMenu(tr("&View"));
+ view->addAction(tr("Take Snapshot"), this, SLOT(takeSnapshot()), QKeySequence("Ctrl+F3"));
+ view->addSeparator();
+
+ QAction *slow = view->addAction(tr("Slow Down Animations"), this, SLOT(slowDownAnimations(bool)), QKeySequence(tr("Ctrl+.")));
+ slow->setCheckable(true);
+ view->addSeparator();
+
+ m_refresh = view->addAction(QIcon::fromTheme("view-refresh"), tr("Refresh"), m_node, SLOT(refresh()), QKeySequence::Refresh);
+ m_enablePluginReload = view->addAction("Reload QML Plugins");
+ m_enablePluginReload->setCheckable(true);
+ connect(m_enablePluginReload, SIGNAL(toggled(bool)), m_node, SLOT(setReloadPluginsEnabled(bool)));
+
+ m_resizeFit = view->addAction(QIcon::fromTheme("zoom-fit-best"), tr("Resize to Fit"), this, SLOT(resizeToFit()));
+ view->addAction(tr("Show Containing Folder"), m_workspace, SLOT(goUp()), QKeySequence("Ctrl+Esc"));
+ m_stayOnTop = view->addAction(tr("Stay on Top"), this, SLOT(stayOnTop()));
+ m_stayOnTop->setCheckable(true);
+
+ view->addSeparator();
+ view->addAction(m_workspaceDock->toggleViewAction());
+ m_hostDock->close();
+ view->addAction(m_hostDock->toggleViewAction());
+ m_logDockMenu = view->addMenu("Logs");
+ m_logDockMenu->addAction(m_logDock->toggleViewAction());
+}
+
+void MainWindow::readSettings()
+{
+ QSettings s;
+ restoreGeometry(s.value("geometry").toByteArray());
+ //Only set the workspace if we didn't already set it by command line
+ if (m_hub->workspace() == QDir::currentPath())
+ setWorkspace(s.value("workspace").toString());
+
+ if (s.value("http_proxy/enabled").toBool()) {
+ QNetworkProxy proxy;
+ proxy.setType(QNetworkProxy::HttpProxy);
+ proxy.setHostName(s.value("http_proxy/hostname").toString());
+ proxy.setPort(s.value("http_proxy/port").toInt());
+ proxy.setUser(s.value("http_proxy/username").toString());
+ proxy.setPassword(s.value("http_proxy/password").toString());
+ QNetworkProxy::setApplicationProxy(proxy);
+ } else {
+ QNetworkProxy::setApplicationProxy(QNetworkProxy());
+ }
+
+ int size = s.beginReadArray("recentFolder");
+ for (int i = 0; i < size; i++) {
+ s.setArrayIndex(i);
+ m_recentFolder.append(s.value("folder").toString());
+ }
+ s.endArray();
+
+ updateRecentFolder();
+
+ //Only set the workspace if we didn't already set it by command line
+ if (m_workspace->activeDocument().isEmpty()) {
+ if (s.contains("activeDocument"))
+ activateDocument(s.value("activeDocument").toString());
+ else
+ m_workspace->activateRootPath();
+ }
+
+ resetImportPaths();
+
+ m_hostModel->restoreFromSettings(&s);
+ restoreState(s.value("windowState").toByteArray());
+}
+
+void MainWindow::writeSettings()
+{
+ QSettings s;
+ s.setValue("geometry", saveGeometry());
+ s.setValue("windowState", saveState());
+ s.setValue("workspace", m_hub->workspace());
+ s.setValue("activeDocument", m_node->activeDocument().toLocalFile());
+
+ s.beginWriteArray("recentFolder");
+ for (int i = 0; i < m_recentFolder.count(); i++) {
+ s.setArrayIndex(i);
+ s.setValue("folder", m_recentFolder.at(i));
+ }
+ s.endArray();
+
+ m_hostModel->saveToSettings(&s);
+}
+
+void MainWindow::resetImportPaths()
+{
+ QStringList importPaths;
+ QSettings s;
+ int count = s.beginReadArray("imports");
+ for (int i=0; i<count; i++) {
+ s.setArrayIndex(i);
+ importPaths.append(s.value("path").toString());
+ }
+ s.endArray();
+
+ setImportPaths(importPaths);
+}
+
+void MainWindow::setupToolBar()
+{
+ m_toolBar = addToolBar("ToolBar");
+ m_toolBar->setObjectName("toolbar");
+ m_toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ m_toolBar->addAction(m_openWorkspace);
+ m_toolBar->addSeparator();
+ m_toolBar->addAction(m_refresh);
+ m_toolBar->addAction(m_resizeFit);
+ m_toolBar->addAction(m_enablePluginReload);
+}
+
+void MainWindow::activateDocument(const QString path)
+{
+ m_workspace->activateDocument(path);
+}
+
+void MainWindow::resizeToFit()
+{
+ QSize diff = m_ww->sizeHint() - m_ww->rect().size();
+ resize(rect().size() + diff);
+ updateWindowTitle();
+}
+
+void MainWindow::takeSnapshot()
+{
+ QImage img;
+ img = m_qmlview->grabWindow();
+
+ if (img.isNull()) {
+ m_log->appendToLog(LogView::InternalError, tr("QmlLive: could not retrieve snapshot pixmap"));
+ } else {
+ static int counter = 1;
+ QString fileName = QString::fromLatin1("snapshot%1.png").arg(counter++);
+ bool ok = img.save(fileName);
+
+ if (!ok) // log
+ m_log->appendToLog(LogView::InternalError, tr("QmlLive: could not save snapshot as \"%1\"").arg(fileName));
+ else
+ m_log->appendToLog(LogView::InternalInfo, tr("QmlLive: created snapshot \"%1\"").arg(fileName));
+ }
+}
+
+void MainWindow::slowDownAnimations(bool enable)
+{
+ QUnifiedTimer::instance()->setSlowModeEnabled(enable);
+}
+
+
+void MainWindow::setWorkspace(const QString& path)
+{
+ m_workspace->setRootPath(path);
+ m_node->setWorkspace(path);
+ m_hub->setWorkspace(path);
+ m_allHosts->setWorkspace(path);
+ updateRecentFolder(path);
+}
+
+void MainWindow::setPluginPath(const QString &path)
+{
+ m_node->setPluginPath(path);
+}
+
+void MainWindow::setImportPaths(const QStringList &pathList)
+{
+ m_node->setImportPaths(pathList + m_qmlDefaultimportList);
+}
+
+void MainWindow::setStaysOnTop(bool enabled)
+{
+ m_stayOnTop->setChecked(enabled);
+ stayOnTop();
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ writeSettings();
+ QMainWindow::closeEvent(event);
+}
+
+void MainWindow::showEvent(QShowEvent *event)
+{
+ QMainWindow::showEvent(event);
+ raise();
+}
+
+void MainWindow::openWorkspace()
+{
+ QString path = QFileDialog::getExistingDirectory(this, "Open Workspace");
+ if (path.isEmpty()) {
+ return;
+ }
+ setWorkspace(path);
+}
+
+void MainWindow::logQuitEvent()
+{
+ m_log->appendToLog(LogView::InternalInfo, tr("Qml Viewer tries to quit."));
+}
+
+void MainWindow::updateWindowTitle()
+{
+ setWindowFilePath(QString());
+ if (m_hub->activePath().isEmpty()) {
+ setWindowTitle(QApplication::applicationName());
+ } else {
+ setWindowTitle(QString());
+ setWindowFilePath(m_hub->activePath());
+ }
+}
+
+void MainWindow::openPreferences(Host* host)
+{
+ OptionsDialog dialog;
+ dialog.setHostModel(m_hostModel);
+ dialog.setDiscoveredHostsModel(m_discoveryManager->discoveredHostsModel());
+
+ if (host)
+ dialog.openHostConfig(host);
+ if (dialog.exec()) {
+ resetImportPaths();
+ m_discoveryManager->rescan();
+ }
+}
+
+void MainWindow::clearRecentFolder()
+{
+ m_recentFolder.clear();
+ m_recentMenu->setEnabled(false);
+ updateRecentFolder();
+}
+
+void MainWindow::openRecentFolder()
+{
+ if (QAction* action = qobject_cast<QAction*>(sender())) {
+ setWorkspace(action->text());
+ }
+}
+
+void MainWindow::updateRecentFolder(const QString& path)
+{
+ if (!path.isEmpty())
+ m_recentFolder.prepend(path);
+ m_recentFolder.removeDuplicates();
+
+ if (m_recentFolder.count())
+ m_recentMenu->setEnabled(true);
+
+ while (m_recentFolder.count() > 7)
+ m_recentFolder.removeAt(m_recentFolder.count() - 1);
+
+ m_recentMenu->clear();
+ foreach (const QString file, m_recentFolder) {
+ m_recentMenu->addAction(file, this, SLOT(openRecentFolder()));
+ }
+
+ m_recentMenu->addSeparator();
+ m_recentMenu->addAction("Clear Menu", this, SLOT(clearRecentFolder()));
+}
+
+void MainWindow::stayOnTop()
+{
+ Qt::WindowFlags flags = windowFlags();
+ if (m_stayOnTop->isChecked()) {
+ setWindowFlags(flags | Qt::WindowStaysOnTopHint);
+ } else {
+ setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));
+ }
+ show();
+}
diff --git a/src/bench/mainwindow.h b/src/bench/mainwindow.h
new file mode 100644
index 0000000..430bd1d
--- /dev/null
+++ b/src/bench/mainwindow.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtWidgets>
+#include <QtQuick>
+
+
+class BenchQuickView;
+class WorkspaceView;
+class LogView;
+class LiveRuntime;
+class LiveHubEngine;
+class BenchLiveNodeEngine;
+class WindowWidget;
+class QToolBar;
+class HostModel;
+class HostManager;
+class AllHostsWidget;
+class Host;
+class HostDiscoveryManager;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+ void activateDocument(const QString path);
+ void setWorkspace(const QString& path);
+ void setPluginPath(const QString& path);
+ void setImportPaths(const QStringList& pathList);
+ void setStaysOnTop(bool enabled);
+ void readSettings();
+protected:
+ void closeEvent(QCloseEvent *event);
+ void showEvent(QShowEvent *event);
+private:
+ void setupContent();
+ void setupWorkspaceView();
+ void setupHostView();
+ void setupLogView();
+ void setupToolBar();
+ void setupMenuBar();
+ void writeSettings();
+ void resetImportPaths();
+private slots:
+ void resizeToFit();
+ void takeSnapshot();
+ void slowDownAnimations(bool enable);
+ void openWorkspace();
+ void logQuitEvent();
+ void updateWindowTitle();
+ void openPreferences(Host *host = 0);
+ void openRecentFolder();
+ void clearRecentFolder();
+ void stayOnTop();
+
+ void initView(BenchQuickView *view);
+
+ void onLogWidgetAdded(QDockWidget* logDock);
+
+private:
+ void updateRecentFolder(const QString &path = QString());
+ BenchQuickView *m_qmlview;
+ WindowWidget *m_ww;
+ WorkspaceView *m_workspace;
+ LogView *m_log;
+ QUrl m_currentSource;
+ QDockWidget *m_logDock;
+ QDockWidget *m_workspaceDock;
+ QDockWidget *m_hostDock;
+ HostManager *m_hostManager;
+ HostModel *m_hostModel;
+ HostDiscoveryManager *m_discoveryManager;
+ AllHostsWidget* m_allHosts;
+ LiveHubEngine *m_hub;
+ BenchLiveNodeEngine *m_node;
+ QStringList m_recentFolder;
+ QMenu* m_recentMenu;
+ QMenu* m_logDockMenu;
+ QAction *m_stayOnTop;
+ QAction *m_openWorkspace;
+ QAction *m_refresh;
+ QAction *m_resizeFit;
+ QAction *m_enablePluginReload;
+ QAction *m_clipRootObject;
+ QToolBar* m_toolBar;
+ QStringList m_qmlDefaultimportList;
+};
diff --git a/src/bench/optionsdialog.cpp b/src/bench/optionsdialog.cpp
new file mode 100644
index 0000000..439725c
--- /dev/null
+++ b/src/bench/optionsdialog.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "optionsdialog.h"
+#include "ui_optionsdialog.h"
+#include "httpproxyoptionpage.h"
+#include "importpathoptionpage.h"
+#include "hostsoptionpage.h"
+
+OptionsDialog::OptionsDialog(QWidget *parent)
+ : QDialog(parent)
+ , ui(new Ui::OptionsDialog)
+ , m_httpProxyForm(new HttpProxyOptionPage(this))
+ , m_importPathsForm(new ImportPathOptionPage(this))
+ , m_hostsForm(new HostsOptionsPage(this))
+{
+ ui->setupUi(this);
+
+ QListWidgetItem* item = new QListWidgetItem("HTTP Proxy");
+ int index = ui->optionsStack->addWidget(m_httpProxyForm);
+ item->setSelected(true);
+ item->setData(Qt::UserRole, index);
+ ui->optionsView->addItem(item);
+
+ item = new QListWidgetItem("Import Paths");
+ index = ui->optionsStack->addWidget(m_importPathsForm);
+ item->setData(Qt::UserRole, index);
+ ui->optionsView->addItem(item);
+
+ item = new QListWidgetItem("Hosts");
+ index = ui->optionsStack->addWidget(m_hostsForm);
+ item->setData(Qt::UserRole, index);
+ ui->optionsView->addItem(item);
+
+ connect(ui->optionsView, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
+ this, SLOT(optionSelected(QListWidgetItem*)));
+}
+
+OptionsDialog::~OptionsDialog()
+{
+ delete ui;
+}
+
+void OptionsDialog::setHostModel(HostModel *model)
+{
+ m_hostsForm->setHostModel(model);
+}
+
+void OptionsDialog::setDiscoveredHostsModel(HostModel *model)
+{
+ m_hostsForm->setDiscoveredHostsModel(model);
+}
+
+void OptionsDialog::openHostConfig(Host *host)
+{
+ ui->optionsView->setCurrentRow(2);
+ m_hostsForm->setHostSelected(host);
+}
+
+void OptionsDialog::optionSelected(QListWidgetItem *current)
+{
+ int index = current->data(Qt::UserRole).toInt();
+ ui->optionsStack->setCurrentIndex(index);
+}
+
+void OptionsDialog::accept()
+{
+ m_httpProxyForm->apply();
+ m_importPathsForm->apply();
+ m_hostsForm->apply();
+ QDialog::accept();
+}
+
+void OptionsDialog::reject()
+{
+ QDialog::reject();
+}
+
+
diff --git a/src/bench/optionsdialog.h b/src/bench/optionsdialog.h
new file mode 100644
index 0000000..c10eb49
--- /dev/null
+++ b/src/bench/optionsdialog.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtGui>
+#include <QtWidgets>
+
+namespace Ui {
+ class OptionsDialog;
+}
+
+class HttpProxyOptionPage;
+class ImportPathOptionPage;
+class HostsOptionsPage;
+class HostModel;
+class Host;
+
+class OptionsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit OptionsDialog(QWidget *parent = 0);
+ ~OptionsDialog();
+
+ void setHostModel(HostModel* model);
+ void setDiscoveredHostsModel(HostModel* model);
+
+ void openHostConfig(Host* host);
+
+private slots:
+ void optionSelected(QListWidgetItem* current);
+ void accept();
+ void reject();
+
+private:
+ Ui::OptionsDialog *ui;
+ HttpProxyOptionPage *m_httpProxyForm;
+ ImportPathOptionPage *m_importPathsForm;
+ HostsOptionsPage *m_hostsForm;
+};
diff --git a/src/bench/optionsdialog.ui b/src/bench/optionsdialog.ui
new file mode 100644
index 0000000..1ed4123
--- /dev/null
+++ b/src/bench/optionsdialog.ui
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OptionsDialog</class>
+ <widget class="QDialog" name="OptionsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>869</width>
+ <height>523</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preferences</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QListWidget" name="optionsView">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="resizeMode">
+ <enum>QListView::Adjust</enum>
+ </property>
+ <property name="selectionRectVisible">
+ <bool>false</bool>
+ </property>
+ <property name="currentRow">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QStackedWidget" name="optionsStack">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>OptionsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>OptionsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/bench/previewimageprovider.cpp b/src/bench/previewimageprovider.cpp
new file mode 100644
index 0000000..a020271
--- /dev/null
+++ b/src/bench/previewimageprovider.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "previewimageprovider.h"
+#include "contentadapterinterface.h"
+
+#include <QDebug>
+#include <QFileIconProvider>
+#include <QPainter>
+
+
+class CacheImage {
+public:
+ QImage image;
+ QDateTime time;
+};
+
+typedef QHash<QString, CacheImage> ImageHash;
+typedef QHash<QString, QImage> QImageHash;
+
+Q_GLOBAL_STATIC(ImageHash, imageCache)
+Q_GLOBAL_STATIC(QImageHash, iconCache)
+
+PreviewImageProvider::PreviewImageProvider(QObject *engine)
+ : QQuickImageProvider(QQuickImageProvider::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading)
+ , m_engine(engine)
+ , m_ignoreCache(false)
+{
+}
+
+QImage PreviewImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_ASSERT(size);
+ QFileInfo info(id);
+ info.refresh();
+ QList<ContentAdapterInterface*> plugins;
+ QString hashKey = id + QString("%1x%2").arg(QString::number(requestedSize.width())).arg(QString::number(requestedSize.height()));
+
+ {
+ QMutexLocker m(&m_mutex);
+ if (!m_ignoreCache && imageCache()->contains(hashKey)) {
+ CacheImage i = imageCache()->value(hashKey);
+ if (info.lastModified() <= i.time) {
+ *size = i.image.size();
+ return i.image;
+ }
+ }
+
+ plugins = m_plugins;
+ }
+
+ foreach (ContentAdapterInterface* plugin, plugins) {
+ if (plugin->canPreview(id)) {
+ QImage img = plugin->preview(id, requestedSize);
+ *size = img.size();
+ CacheImage i;
+ i.image = img;
+ i.time = info.lastModified();
+ imageCache()->insert(hashKey, i);
+
+ return img;
+ }
+ }
+
+
+ QImage img;
+ QString type = info.suffix();
+ QSize iconSize = requestedSize;
+ if (!iconSize.isValid() || iconSize.isNull())
+ iconSize = QSize(512, 512);
+
+ if (iconCache()->contains(type)) {
+ img = iconCache()->value(type);
+ *size = img.size();
+ } else if (m_engine){
+ QMetaObject::invokeMethod(m_engine, "convertIconToImage",
+ Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(QImage, img),
+ Q_ARG(QFileInfo, info),
+ Q_ARG(QSize, iconSize));
+ iconCache()->insert(type, img);
+ *size = iconSize;
+ }
+
+ return img;
+}
+
+void PreviewImageProvider::setPlugins(QList<ContentAdapterInterface *> plugins)
+{
+ QMutexLocker m(&m_mutex);
+ m_plugins = plugins;
+}
+
+void PreviewImageProvider::setIgnoreCache(bool enabled)
+{
+ QMutexLocker m(&m_mutex);
+ m_ignoreCache = enabled;
+}
+
+bool PreviewImageProvider::ignoreCache()
+{
+ QMutexLocker m(&m_mutex);
+ return m_ignoreCache;
+}
diff --git a/src/bench/previewimageprovider.h b/src/bench/previewimageprovider.h
new file mode 100644
index 0000000..2057e80
--- /dev/null
+++ b/src/bench/previewimageprovider.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QQuickImageProvider>
+#include <QMutex>
+#include <QHash>
+#include <QDateTime>
+
+class ContentAdapterInterface;
+class PreviewImageProvider : public QObject, public QQuickImageProvider
+{
+ Q_OBJECT
+
+public:
+ explicit PreviewImageProvider(QObject *engine);
+
+ QImage requestImage (const QString& id, QSize* size, const QSize& requestedSize);
+
+ void setPlugins(QList<ContentAdapterInterface*> plugins);
+ void setIgnoreCache(bool enabled);
+ bool ignoreCache();
+
+private:
+
+ QList<ContentAdapterInterface*> m_plugins;
+ QMutex m_mutex;
+ QObject* m_engine;
+ bool m_ignoreCache;
+};
diff --git a/src/bench/qmlpreviewadapter.cpp b/src/bench/qmlpreviewadapter.cpp
new file mode 100644
index 0000000..d919989
--- /dev/null
+++ b/src/bench/qmlpreviewadapter.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "qmlpreviewadapter.h"
+#include <QFileInfo>
+#include <QDir>
+#include <QCoreApplication>
+#include <QLocalSocket>
+#include <QDebug>
+
+Q_GLOBAL_STATIC(QProcess, proc)
+Q_GLOBAL_STATIC(QString, serverName)
+
+
+QmlPreviewAdapter::QmlPreviewAdapter(QObject *parent) :
+ QObject(parent)
+{
+}
+
+bool QmlPreviewAdapter::canPreview(const QString &path) const
+{
+ return path.endsWith(".qml");
+}
+
+QImage QmlPreviewAdapter::preview(const QString &path, const QSize &requestedSize)
+{
+ QImage img;
+
+ if (!requestedSize.isValid()) {
+ qWarning() << "preview for" << path << "with invalid size" << requestedSize << "requested";
+ return QImage();
+ }
+
+#ifdef Q_OS_WINDOWS
+ static const QString suffix = ".exe";
+#else
+ static const QString suffix;
+#endif
+
+ static const QString program = QCoreApplication::applicationDirPath() + QDir::separator() + "previewGenerator" + suffix;
+ static const QStringList arguments("QmlLiveBench");
+
+ if (proc()->state() != QProcess::Running) {
+ QStringList env = QProcess::systemEnvironment();
+ {
+ QMutexLocker m(&m_mutex);
+ env.append(QString("QT_PLUGIN_PATH=%1").arg(m_pluginPaths.join(":")));
+ env.append(QString("QML_IMPORT_PATH=%1").arg(m_importPaths.join(":")));
+ env.append(QString("QML2_IMPORT_PATH=%1").arg(m_importPaths.join(":")));
+ }
+ proc()->setEnvironment(env);
+ proc()->start(program, arguments);
+ if (!proc()->waitForStarted()) {
+ qWarning() << "Failed to start" << program;
+ return QImage();
+ }
+
+ proc()->waitForReadyRead();
+ QByteArray data = proc()->readAll();
+ if (!data.startsWith("ready#")) {
+ qWarning() << "previewGenerator did not send the \"ready\" token:" << proc()->readAllStandardError();
+ return QImage();
+ }
+ QString server = QString::fromUtf8(QByteArray::fromHex(data.mid(6)));
+ *serverName() = server;
+ }
+
+ QLocalSocket socket;
+
+ socket.connectToServer(*serverName());
+ if (!socket.waitForConnected(3000)) {
+ qWarning() << "Could not connect to PreviewGenerator";
+ return QImage();
+ }
+
+ //qWarning() << "QL: sending request [" << requestedSize << "]" << path;
+
+ {
+ QDataStream ds(&socket);
+ ds << requestedSize << path;
+ }
+ socket.waitForBytesWritten();
+
+ //qWarning() << "QL: sent";
+
+ QByteArray data;
+ bool allData = false;
+ while (!allData) {
+ int bytes = socket.bytesAvailable();
+ //qWarning() << "QL: can read" << bytes << "bytes";
+
+ if (proc()->state() != QProcess::Running) {
+ qWarning() << "previewGenerator stopped unexpectedly";
+ break;
+ }
+
+ if (!bytes) {
+ //qWarning() << "QL: waiting for more data (have" << data.size() << "already)";
+ socket.waitForReadyRead(5000);
+ continue;
+ }
+
+ data += socket.read(bytes);
+
+ if (data.endsWith("\nEND")) {
+ allData = true;
+ data.chop(4);
+ //qWarning() << "QL: received end marker after" << data.size() << "bytes";
+ }
+ }
+ socket.close();
+
+ img.loadFromData(data, "PNG");
+
+ if (img.size().isNull()) {
+ qWarning() << "Failed to generate Preview:" << proc()->readAllStandardError();
+
+ img = QImage("://livert/no.png");
+ }
+
+ return img;
+}
+
+bool QmlPreviewAdapter::canAdapt(const QUrl &url) const
+{
+ Q_UNUSED(url);
+
+ return false;
+}
+
+QUrl QmlPreviewAdapter::adapt(const QUrl &url, QQmlContext *context)
+{
+ Q_UNUSED(url);
+ Q_UNUSED(context);
+
+ return QUrl();
+}
+
+void QmlPreviewAdapter::setImportPaths(QStringList importPaths)
+{
+ QMutexLocker m(&m_mutex);
+ m_importPaths = importPaths;
+}
+
+void QmlPreviewAdapter::setPluginPaths(QStringList pluginPaths)
+{
+ QMutexLocker m(&m_mutex);
+ m_importPaths = pluginPaths;
+}
diff --git a/src/bench/qmlpreviewadapter.h b/src/bench/qmlpreviewadapter.h
new file mode 100644
index 0000000..2dba44b
--- /dev/null
+++ b/src/bench/qmlpreviewadapter.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include "contentadapterinterface.h"
+#include <QMutex>
+#include <QStringList>
+#include <QProcess>
+
+class QmlContext;
+class QDeclarativeContext;
+class QmlPreviewAdapter : public QObject, public ContentAdapterInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(ContentAdapterInterface)
+public:
+ explicit QmlPreviewAdapter(QObject *parent = 0);
+
+ bool canPreview(const QString& path) const;
+ QImage preview(const QString& path, const QSize &requestedSize);
+
+ bool canAdapt(const QUrl& url) const;
+ virtual QUrl adapt(const QUrl& url, QQmlContext* context);
+
+ void setImportPaths(QStringList importPaths);
+ void setPluginPaths(QStringList pluginPaths);
+
+private:
+
+ QStringList m_pluginPaths;
+ QStringList m_importPaths;
+ QMutex m_mutex;
+};
diff --git a/src/bench/reload.pro b/src/bench/reload.pro
new file mode 100644
index 0000000..89a9668
--- /dev/null
+++ b/src/bench/reload.pro
@@ -0,0 +1,33 @@
+TEMPLATE = app
+TARGET = livereload
+
+equals(QT_MAJOR_VERSION, "5"): CONFIG += qt5
+
+QT = gui core
+qt5:QT += quick widgets core-private
+else:QT += declarative
+
+osx: CONFIG -= app_bundle
+
+qt5:DEFINES += USING_QT5
+else:DEFINES += USING_QT4
+
+SOURCES += \
+ main.cpp \
+ watcher.cpp \
+ mainwindow.cpp
+
+qt5:SOURCES += windowwidget.cpp
+
+HEADERS += \
+ watcher.h \
+ mainwindow.h
+
+qt5:HEADERS += windowwidget.h
+
+RESOURCES += \
+ reload.qrc
+
+OTHER_FILES += \
+ error.qml \
+ error2.qml
diff --git a/src/bench/reload.qrc b/src/bench/reload.qrc
new file mode 100644
index 0000000..2c37c6e
--- /dev/null
+++ b/src/bench/reload.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>logo.png</file>
+ <file>error.qml</file>
+ <file>error2.qml</file>
+ <file>livert/ImageViewer.qml</file>
+ </qresource>
+</RCC>
diff --git a/src/concept.dox b/src/concept.dox
new file mode 100644
index 0000000..e7cabed
--- /dev/null
+++ b/src/concept.dox
@@ -0,0 +1,10 @@
+/*!
+ \page concept Concept
+
+ \tableofcontents
+
+ \section Fundamentals
+
+ QmlLive provides a way to synchronize a workspace on the same machine or across devices and manage the active shown document.
+
+*/
diff --git a/src/contentadapterinterface.h b/src/contentadapterinterface.h
new file mode 100644
index 0000000..c589eef
--- /dev/null
+++ b/src/contentadapterinterface.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QUrl>
+#include <QImage>
+
+class QDeclarativeContext;
+class QQmlContext;
+//! [0]
+class ContentAdapterInterface
+{
+public:
+
+ enum Feature {
+ QtQuickControls = 0x1
+ };
+ Q_DECLARE_FLAGS(Features, Feature)
+
+ virtual ~ContentAdapterInterface() {}
+
+ virtual void cleanUp() {}
+
+ virtual bool canPreview(const QString& path) const = 0;
+ virtual QImage preview(const QString& path, const QSize &requestedSize) = 0;
+
+ virtual bool canAdapt(const QUrl& url) const = 0;
+ virtual bool isFullScreen() const { return false; }
+
+ void setAvailableFeatures(ContentAdapterInterface::Features features) { m_features = features; }
+ ContentAdapterInterface::Features availableFeatures() { return m_features; }
+
+ virtual QUrl adapt(const QUrl& url, QQmlContext* context) = 0;
+
+private:
+ Features m_features;
+};
+//! [0]
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(ContentAdapterInterface::Features)
+Q_DECLARE_INTERFACE(ContentAdapterInterface, "com.pelagicore.qmllive.ContentAdapterInterface/1.0")
+
diff --git a/src/contentpluginfactory.cpp b/src/contentpluginfactory.cpp
new file mode 100644
index 0000000..1894ab3
--- /dev/null
+++ b/src/contentpluginfactory.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "contentpluginfactory.h"
+#include "contentadapterinterface.h"
+
+#include <QPluginLoader>
+#include <QDirIterator>
+#include <QDebug>
+
+ContentPluginFactory::ContentPluginFactory(QObject *parent) :
+ QObject(parent) ,
+ m_loaded(false)
+{
+ m_pluginPath = QDir::currentPath() + QDir::separator() + "plugins";
+}
+
+void ContentPluginFactory::setPluginPath(const QString &path)
+{
+ m_pluginPath = path;
+}
+
+QString ContentPluginFactory::pluginPath()
+{
+ return m_pluginPath;
+}
+
+
+QList<ContentAdapterInterface *> ContentPluginFactory::plugins()
+{
+ return m_plugins;
+}
+
+bool ContentPluginFactory::isLoaded()
+{
+ return m_loaded;
+}
+
+void ContentPluginFactory::load()
+{
+ if (m_loaded)
+ return;
+
+ QDirIterator it(m_pluginPath);
+
+ while (it.hasNext()) {
+ const QString path = it.next();
+
+ if (!it.fileInfo().isFile())
+ continue;
+
+ QPluginLoader loader(path);
+
+ ContentAdapterInterface* plugin = qobject_cast<ContentAdapterInterface*>(loader.instance());
+ if (plugin)
+ m_plugins.append(plugin);
+
+ if (!loader.isLoaded())
+ qWarning() << "Error while trying to load" <<path << ":" << loader.errorString();
+ }
+
+ if (!m_plugins.isEmpty())
+ m_loaded = true;
+}
diff --git a/src/contentpluginfactory.h b/src/contentpluginfactory.h
new file mode 100644
index 0000000..29e83b4
--- /dev/null
+++ b/src/contentpluginfactory.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+
+class ContentAdapterInterface;
+class ContentPluginFactory : public QObject
+{
+ Q_OBJECT
+public:
+ explicit ContentPluginFactory(QObject *parent = 0);
+
+ void setPluginPath(const QString& path);
+ QString pluginPath();
+
+ QList<ContentAdapterInterface*> plugins();
+ bool isLoaded();
+
+public Q_SLOTS:
+
+ void load();
+
+private:
+ QString m_pluginPath;
+ QList<ContentAdapterInterface*> m_plugins;
+ bool m_loaded;
+};
diff --git a/src/fontadapter.cpp b/src/fontadapter.cpp
new file mode 100644
index 0000000..6825a54
--- /dev/null
+++ b/src/fontadapter.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "fontadapter.h"
+#include <QDebug>
+#include <QQmlContext>
+
+FontAdapter::FontAdapter(QObject *parent) :
+ QObject(parent),
+ fontId(-1)
+{
+ fontExtensions.append(".ttf");
+ fontExtensions.append(".otf");
+}
+
+void FontAdapter::cleanUp()
+{
+ base.removeAllApplicationFonts();
+}
+
+bool FontAdapter::canPreview(const QString &path) const
+{
+ Q_UNUSED(path);
+
+ return false;
+}
+
+QImage FontAdapter::preview(const QString &path, const QSize &requestedSize)
+{
+ Q_UNUSED(path);
+ Q_UNUSED(requestedSize);
+
+ return QImage();
+}
+
+bool FontAdapter::canAdapt(const QUrl &url) const
+{
+ QString path = url.toLocalFile();
+
+ foreach (const QString& extension, fontExtensions) {
+ if (path.endsWith(extension))
+ return true;
+ }
+
+ return false;
+}
+
+bool FontAdapter::isFullScreen() const
+{
+ return true;
+}
+
+QUrl FontAdapter::adapt(const QUrl &url, QQmlContext *context)
+{
+ fontId = base.addApplicationFont(url.toLocalFile());
+
+ QStringList families = base.applicationFontFamilies(fontId);
+
+ QVariantList styles;
+ foreach (QString family, families) {
+ QVariantMap style;
+ QVariantList weights;
+ foreach (QString styleName, base.styles(family)) {
+ QVariantMap newWeight;
+ int styleWeight = base.weight(family, styleName);
+
+ newWeight.insert("name", styleName);
+ newWeight.insert("weight", styleWeight);
+
+ bool added = false;
+ for (int i=0; i < weights.count(); i++) {
+ if (styleWeight <= weights.at(i).toMap().value("weight").toInt()) {
+ added = true;
+ weights.insert(i, newWeight);
+ break;
+ }
+ }
+
+ if (!added)
+ weights.append(newWeight);
+ }
+
+ style.insert("family", family);
+ style.insert("weights", weights);
+ styles.append(style);
+ }
+
+ context->setContextProperty("styles", styles);
+
+ if (availableFeatures().testFlag(QtQuickControls))
+ return QUrl("qrc:/livert/fontviewer_qt5_controls.qml");
+
+ return QUrl("qrc:/livert/fontviewer_qt5.qml");
+}
diff --git a/src/fontadapter.h b/src/fontadapter.h
new file mode 100644
index 0000000..9eb2152
--- /dev/null
+++ b/src/fontadapter.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include "contentadapterinterface.h"
+#include <QStringList>
+#include <QFontDatabase>
+
+class QDeclarativeContext;
+class FontAdapter : public QObject, public ContentAdapterInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(ContentAdapterInterface)
+public:
+ explicit FontAdapter(QObject *parent = 0);
+
+ void cleanUp();
+
+ bool canPreview(const QString& path) const;
+ QImage preview(const QString& path, const QSize &requestedSize);
+
+ bool canAdapt(const QUrl& url) const;
+
+ bool isFullScreen() const;
+
+ virtual QUrl adapt(const QUrl& url, QQmlContext* context);
+
+private:
+ QStringList fontExtensions;
+ QFontDatabase base;
+ int fontId;
+};
diff --git a/src/imageadapter.cpp b/src/imageadapter.cpp
new file mode 100644
index 0000000..439ab8b
--- /dev/null
+++ b/src/imageadapter.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "imageadapter.h"
+#include <QImageReader>
+#include <QDebug>
+#include <QFileInfo>
+#include <QQmlContext>
+
+ImageAdapter::ImageAdapter(QObject *parent) :
+ QObject(parent)
+{
+}
+
+bool ImageAdapter::canPreview(const QString &path) const
+{
+ QString format = QImageReader::imageFormat(path);
+ if (!format.isEmpty()) {
+ if (format == "pcx") {
+ if (QFileInfo(path).suffix() == "pcx")
+ return true;
+ } else {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QImage ImageAdapter::preview(const QString &path, const QSize &requestedSize)
+{
+ QImage img(path);
+
+ if (requestedSize.isValid())
+ return img.scaled(requestedSize, Qt::KeepAspectRatio);
+ return img;
+}
+
+bool ImageAdapter::canAdapt(const QUrl &url) const
+{
+ return !QImageReader::imageFormat(url.toLocalFile()).isEmpty();
+}
+
+QUrl ImageAdapter::adapt(const QUrl &url, QQmlContext *context)
+{
+ context->setContextProperty("imageViewerBackgroundColor", "black");
+ context->setContextProperty("imageViewerSource", url);
+
+ return QUrl("qrc:/livert/imageviewer_qt5.qml");
+}
diff --git a/src/imageadapter.h b/src/imageadapter.h
new file mode 100644
index 0000000..3d64f57
--- /dev/null
+++ b/src/imageadapter.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include "contentadapterinterface.h"
+
+class QDeclarativeContext;
+class ImageAdapter : public QObject, public ContentAdapterInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(ContentAdapterInterface)
+public:
+ explicit ImageAdapter(QObject *parent = 0);
+
+ bool canPreview(const QString& path) const;
+ QImage preview(const QString& path, const QSize &requestedSize);
+
+ bool canAdapt(const QUrl& url) const;
+
+ virtual QUrl adapt(const QUrl& url, QQmlContext* context);
+};
+
diff --git a/src/images/client.png b/src/images/client.png
new file mode 100644
index 0000000..1192b0f
--- /dev/null
+++ b/src/images/client.png
Binary files differ
diff --git a/src/images/concept.png b/src/images/concept.png
new file mode 100644
index 0000000..dec994d
--- /dev/null
+++ b/src/images/concept.png
Binary files differ
diff --git a/src/images/creator_result.png b/src/images/creator_result.png
new file mode 100644
index 0000000..a26a980
--- /dev/null
+++ b/src/images/creator_result.png
Binary files differ
diff --git a/src/images/creator_shortcut.png b/src/images/creator_shortcut.png
new file mode 100644
index 0000000..18d8106
--- /dev/null
+++ b/src/images/creator_shortcut.png
Binary files differ
diff --git a/src/images/creator_tool.png b/src/images/creator_tool.png
new file mode 100644
index 0000000..a34b403
--- /dev/null
+++ b/src/images/creator_tool.png
Binary files differ
diff --git a/src/images/favicon.png b/src/images/favicon.png
new file mode 100644
index 0000000..4714c88
--- /dev/null
+++ b/src/images/favicon.png
Binary files differ
diff --git a/src/images/graphics_sheets.png b/src/images/graphics_sheets.png
new file mode 100644
index 0000000..d9c9f5a
--- /dev/null
+++ b/src/images/graphics_sheets.png
Binary files differ
diff --git a/src/images/icon_failover.png b/src/images/icon_failover.png
new file mode 100644
index 0000000..1ce4c0f
--- /dev/null
+++ b/src/images/icon_failover.png
Binary files differ
diff --git a/src/images/icon_offline.png b/src/images/icon_offline.png
new file mode 100644
index 0000000..760524e
--- /dev/null
+++ b/src/images/icon_offline.png
Binary files differ
diff --git a/src/images/icon_online.png b/src/images/icon_online.png
new file mode 100644
index 0000000..62f64d9
--- /dev/null
+++ b/src/images/icon_online.png
Binary files differ
diff --git a/src/images/qml_sheets.png b/src/images/qml_sheets.png
new file mode 100644
index 0000000..9037f00
--- /dev/null
+++ b/src/images/qml_sheets.png
Binary files differ
diff --git a/src/images/remote.png b/src/images/remote.png
new file mode 100644
index 0000000..0d7872f
--- /dev/null
+++ b/src/images/remote.png
Binary files differ
diff --git a/src/images/runtime.png b/src/images/runtime.png
new file mode 100644
index 0000000..41804af
--- /dev/null
+++ b/src/images/runtime.png
Binary files differ
diff --git a/src/images/server.png b/src/images/server.png
new file mode 100644
index 0000000..5e00a21
--- /dev/null
+++ b/src/images/server.png
Binary files differ
diff --git a/src/images/workbench.png b/src/images/workbench.png
new file mode 100644
index 0000000..9c4ec78
--- /dev/null
+++ b/src/images/workbench.png
Binary files differ
diff --git a/src/ipc/ipc.dox b/src/ipc/ipc.dox
new file mode 100644
index 0000000..6b4eeb2
--- /dev/null
+++ b/src/ipc/ipc.dox
@@ -0,0 +1,14 @@
+/*!
+ \defgroup ipc Ipc Communication
+
+ A set of classes to support ipc client and server.
+*/
+
+/*!
+ @{
+*/
+
+/*!
+ @}
+*/
+
diff --git a/src/ipc/ipc.pri b/src/ipc/ipc.pri
new file mode 100644
index 0000000..85ae7e9
--- /dev/null
+++ b/src/ipc/ipc.pri
@@ -0,0 +1,11 @@
+QT += network
+
+SOURCES += \
+ $$PWD/ipcserver.cpp \
+ $$PWD/ipcconnection.cpp \
+ $$PWD/ipcclient.cpp
+
+HEADERS += \
+ $$PWD/ipcserver.h \
+ $$PWD/ipcconnection.h \
+ $$PWD/ipcclient.h
diff --git a/src/ipc/ipcclient.cpp b/src/ipc/ipcclient.cpp
new file mode 100644
index 0000000..e3a0846
--- /dev/null
+++ b/src/ipc/ipcclient.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "ipcclient.h"
+#include <QElapsedTimer>
+#include <QPointer>
+
+#ifdef QMLLIVE_IPC_DEBUG
+#define DEBUG qDebug()
+#else
+#define DEBUG if (0) qDebug()
+#endif
+
+class Package : public QObject {
+public:
+ QUuid m_uuid;
+ QString m_method;
+ QByteArray m_data;
+ int m_tries;
+ qint64 m_bytes;
+};
+
+/*!
+ * \class IpcClient
+ * \brief Client to send remote calls to an IpcServer
+ * \group ipc
+ *
+ * The IPC system uses the normalized signal/slot signature to
+ * identify a message call. The arguments are passed as a QByteArray to the
+ * send function.
+ *
+ * Here is a simple example:
+ * \code{.cpp}
+ * IpcClient *client = new IpcClient(this);
+ * client->connectToServer("127.0.0.1", 10234);
+ * QString text = "Hello";
+ * QByteArray content;
+ * QDataStream out(&bytes, QIODevice::WriteOnly);
+ * out << text;
+ * QUuid uuid = client->send("echo(QString)", content);
+ * client->waitForSent(uuid);
+ * \endcode
+ *
+ * Don't use the waitFor*-Methods in your gui applications. They will block
+ * the eventloop. Instead react on the signals when the packages are sent or
+ * an error happened.
+ */
+
+/*!
+ * \brief Constructs an IpcClient with parent \a parent to send commands to an IpcServer.
+ */
+IpcClient::IpcClient(QObject *parent)
+ : QObject(parent)
+ , m_socket(new QTcpSocket(this))
+ , m_current(0)
+ , m_written(0)
+ , m_connection(new IpcConnection(m_socket))
+{
+ connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected()));
+ connect(m_socket, SIGNAL(connected()), this, SLOT(processQueue()));
+ connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
+ connect(m_socket, SIGNAL(bytesWritten(qint64)), this , SLOT(onBytesWritten(qint64)));
+
+ connect(m_connection, SIGNAL(received(QString,QByteArray)), this, SIGNAL(received(QString,QByteArray)));
+}
+
+IpcClient::IpcClient(QTcpSocket *socket, QObject *parent)
+ : QObject(parent)
+ , m_socket(socket)
+ , m_current(0)
+ , m_written(0)
+ , m_connection(0)
+{
+ connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected()));
+ connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
+ connect(m_socket, SIGNAL(bytesWritten(qint64)), this , SLOT(onBytesWritten(qint64)));
+}
+
+QAbstractSocket::SocketState IpcClient::state() const
+{
+ return m_socket->state();
+}
+
+/*!
+ * Sets the Ip-Address to \a hostName and port to \a port to be used for a ipc call.
+ */
+void IpcClient::connectToServer(const QString &hostName, int port)
+{
+ m_socket->connectToHost(hostName, port);
+}
+
+/*!
+ * Send call to server given by destination
+ *
+ * Expects the \a method to be in the form of "echo(QString)" and uses \a data as the content of the arguments
+ * Returns a QUuid which identifies this Package
+ *
+ * \sa sentSuccessfully(), sendingError()
+ */
+QUuid IpcClient::send(const QString &method, const QByteArray &data)
+{
+ Package* pkg = new Package;
+ pkg->m_method = method;
+ pkg->m_data = data;
+ pkg->m_uuid = QUuid::createUuid();
+ pkg->m_bytes = 0;
+ pkg->m_tries = 0;
+ m_queue.enqueue(pkg);
+
+ QTimer::singleShot(0, this, SLOT(processQueue()));
+
+ return pkg->m_uuid;
+}
+
+/*!
+ * Waits until the client is connected to the server
+ * \a msecs specfies the time how long to wait
+ * Returns true when the client is connected
+ *
+ * This call blocks your eventloop()
+ *
+ * \sa waitForDisconnected(), waitForSent()
+ */
+bool IpcClient::waitForConnected(int msecs)
+{
+ return m_socket->waitForConnected(msecs);
+}
+
+/*!
+ * Waits until the client is disconnected from the server
+ * \a msecs specfies the time how long to wait
+ * Returns true when the client is disconnected
+ *
+ * This call blocks your eventloop()
+ *
+ * \sa waitForConnected(), waitForSent()
+ */
+bool IpcClient::waitForDisconnected(int msecs)
+{
+ return m_socket->waitForDisconnected(msecs);
+}
+
+/*!
+ * Waits until the Package identified by \a uuid is sent
+ * \arg msecs specfies the time how long to wait
+ * Returns true when the Package is sent successfully
+ *
+ * This call blocks your eventloop()
+ *
+ * \sa waitForConnected(), waitForDisconnected()
+ */
+bool IpcClient::waitForSent(const QUuid uuid, int msecs)
+{
+ QPointer<Package> waitForPackage = 0;
+ if (m_current && m_current->m_uuid == uuid) {
+ waitForPackage = m_current;
+ } else {
+ foreach (Package* pkg, m_queue) {
+ if (pkg->m_uuid == uuid) {
+ waitForPackage = pkg;
+ break;
+ }
+ }
+ }
+
+ if (!waitForPackage)
+ return false;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ bool sent = false;
+ while (!sent && (msecs == -1 || stopWatch.elapsed() < msecs)) {
+ if (!m_socket->waitForBytesWritten(msecs - stopWatch.elapsed()))
+ return false;
+
+ if (!waitForPackage)
+ return m_lastSuccess == uuid;
+ }
+
+ return false;
+}
+
+QString IpcClient::errorToString(QAbstractSocket::SocketError error)
+{
+ switch (error) {
+
+ case QAbstractSocket::ConnectionRefusedError:
+ return QString("The connection was refused by the peer (or timed out).");
+ case QAbstractSocket::RemoteHostClosedError:
+ return QString("The remote host closed the connection.");
+ case QAbstractSocket::HostNotFoundError:
+ return QString("The host address was not found.");
+ case QAbstractSocket::SocketAccessError:
+ return QString("You don't have the required privileges.");
+ case QAbstractSocket::SocketResourceError:
+ return QString("The local system ran out of resources (e.g., too many sockets).");
+ case QAbstractSocket::SocketTimeoutError:
+ return QString("The socket operation timed out.");
+ case QAbstractSocket::DatagramTooLargeError:
+ return QString("The datagram was larger than the operating system's limit (which can be as low as 8192 bytes).");
+ case QAbstractSocket::NetworkError:
+ return QString("An error occurred with the network (e.g., the network cable was accidentally plugged out).");
+ case QAbstractSocket::AddressInUseError:
+ return QString("Address already in use.");
+ case QAbstractSocket::SocketAddressNotAvailableError:
+ return QString("Address not available.");
+ case QAbstractSocket::UnsupportedSocketOperationError:
+ return QString("Unsupported Socket.");
+ case QAbstractSocket::ProxyAuthenticationRequiredError:
+ return QString("The socket is using a proxy, and the proxy requires authentication.");
+ case QAbstractSocket::SslHandshakeFailedError:
+ return QString("The SSL/TLS handshake failed, so the connection was closed");
+ case QAbstractSocket::UnfinishedSocketOperationError:
+ return QString("The last operation attempted has not finished yet (still in progress in the background).");
+ case QAbstractSocket::ProxyConnectionRefusedError:
+ return QString("Could not contact the proxy server because the connection to that server was denied.");
+ case QAbstractSocket::ProxyConnectionClosedError:
+ return QString("The connection to the proxy server was closed unexpectedly (before the connection to the final peer was established).");
+ case QAbstractSocket::ProxyConnectionTimeoutError:
+ return QString("The connection to the proxy server timed out or the proxy server stopped responding in the authentication phase.");
+ case QAbstractSocket::ProxyNotFoundError:
+ return QString("The proxy address was not found.");
+ case QAbstractSocket::ProxyProtocolError:
+ return QString("The connection negotiation with the proxy server because the response from the proxy server could not be understood.");
+ case QAbstractSocket::UnknownSocketError:
+ return QString("Unknown Error");
+ case QAbstractSocket::OperationError:
+ return QString("An operation was attempted while the socket was in a state that did not permit it.");
+ case QAbstractSocket::SslInternalError:
+ return QString("The SSL library being used reported a internal error, this is probably the result of a bad installation or misconfiguration of the library.");
+ case QAbstractSocket::SslInvalidUserDataError:
+ return QString("Invalid data(certificate, key, cypher, etc.) was provided and its use resulted in an error in the SSL library.");
+ case QAbstractSocket::TemporaryError:
+ return QString("A temporary error occurred(e.g., operation would block and socket is non-blocking).");
+ }
+
+ return QString("No Error Description for this Error");
+}
+
+/*!
+ * Disconnects from the Server
+ */
+void IpcClient::disconnectFromServer()
+{
+ m_socket->disconnectFromHost();
+}
+
+void IpcClient::processQueue()
+{
+ if (m_current)
+ return;
+
+ if (!m_queue.isEmpty()) {
+ m_current = m_queue.head();
+ m_current->m_tries++;
+
+ if (m_current->m_tries >= 5) {
+ DEBUG << "Tried to sent the package" << m_current->m_tries << "times, but didn't succeed";
+ m_queue.dequeue();
+ onError(QAbstractSocket::ConnectionRefusedError);
+ QTimer::singleShot(0, this, SLOT(processQueue()));
+ return;
+ }
+
+ int size = sendPackage(m_current->m_method, m_current->m_data);
+
+ if (size != -1) {
+ m_queue.dequeue();
+ m_current->m_bytes = size;
+ } else {
+ QTimer::singleShot(1000, this, SLOT(processQueue()));
+ m_current = 0;
+ }
+ }
+}
+
+void IpcClient::onBytesWritten(qint64 written)
+{
+ Q_ASSERT(m_current);
+
+ m_written += written;
+ if (m_written < m_current->m_bytes)
+ return;
+
+ m_written = m_written - m_current->m_bytes;
+ emit sentSuccessfully(m_current->m_uuid);
+ m_lastSuccess = m_current->m_uuid;
+ delete m_current;
+ m_current = 0;
+
+ processQueue();
+}
+
+void IpcClient::onError(QAbstractSocket::SocketError socketError)
+{
+ if (m_current) {
+ emit sendingError(m_current->m_uuid, socketError);
+ delete m_current;
+ m_current = 0;
+
+ QTimer::singleShot(0, this, SLOT(processQueue()));
+ }
+
+ if ((m_socket->state() != QAbstractSocket::ConnectedState &&
+ m_socket->state() != QAbstractSocket::BoundState) ||
+ socketError == QAbstractSocket::RemoteHostClosedError) {
+ emit connectionError(socketError);
+ }
+}
+
+qint64 IpcClient::sendPackage(const QString &method, const QByteArray &data)
+{
+ DEBUG << "IpcClient::send: " << method;
+
+ if (!m_socket->isValid() || m_socket->state() != QAbstractSocket::ConnectedState) {
+ DEBUG << "Tried to write on a Unconnected Socket. Try again later";
+ return -1;
+ }
+
+ m_socket->write(QString("Method:%1\n").arg(method).toLatin1());
+ m_socket->write(QString("Content-Length:%1\n").arg(data.length()).toLatin1());
+ m_socket->write(QString("\n").toLatin1());
+ m_socket->write(data);
+
+ return m_socket->bytesToWrite();
+}
+
+/*!
+ * \fn void IpcClient::connected();
+ * Emitted once when the connection to the server is established
+ */
+
+/*!
+ * \fn void IpcClient::disconnected();
+ * Emitted once when the connection to the server is terminated
+ */
+
+/*!
+ * \fn void IpcClient::connectionError(QAbstractSocket::SocketError socketError);
+ * Emitted when an error happens when connecting or disconnecting from the server
+ * \a socketError describes what error happened
+ */
+
+/*!
+ * \fn void IpcClient::sentSuccessfully(const QUuid& uuid);
+ * Emitted when the Package identified by \a uuid was successfully sent.
+ */
+
+/*!
+ * \fn void IpcClient::sendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError);
+ * Emitted when an error happens when sending the Package identified by \a uuid.
+ * \a socketError describes what error happened
+ */
+
diff --git a/src/ipc/ipcclient.h b/src/ipc/ipcclient.h
new file mode 100644
index 0000000..dd9190f
--- /dev/null
+++ b/src/ipc/ipcclient.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QTcpSocket>
+#include <QUuid>
+#include <QQueue>
+#include "ipcconnection.h"
+
+class Package;
+class IpcClient : public QObject
+{
+ Q_OBJECT
+public:
+ explicit IpcClient(QObject *parent = 0);
+ IpcClient(QTcpSocket* socket, QObject *parent = 0);
+
+ QAbstractSocket::SocketState state() const;
+
+ void connectToServer(const QString& hostName, int port);
+ QUuid send(const QString& method, const QByteArray& data);
+
+ bool waitForConnected(int msecs = 30000);
+ bool waitForDisconnected(int msecs = 30000);
+ bool waitForSent(const QUuid uuid, int msecs = 30000);
+
+ QString errorToString(QAbstractSocket::SocketError error);
+
+Q_SIGNALS:
+ void connected();
+ void disconnected();
+ void connectionError(QAbstractSocket::SocketError socketError);
+
+ void sentSuccessfully(const QUuid& uuid);
+ void sendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError);
+
+ void received(const QString& method, const QByteArray& content);
+
+public Q_SLOTS:
+ void disconnectFromServer();
+
+private Q_SLOTS:
+ void processQueue();
+ void onBytesWritten(qint64 written);
+ void onError(QAbstractSocket::SocketError socketError);
+
+private:
+ qint64 sendPackage(const QString& method, const QByteArray& data);
+
+ QTcpSocket *m_socket;
+ QQueue<Package*> m_queue;
+ Package* m_current;
+ qint64 m_written;
+ QUuid m_lastSuccess;
+
+ IpcConnection* m_connection;
+};
+
diff --git a/src/ipc/ipcconnection.cpp b/src/ipc/ipcconnection.cpp
new file mode 100644
index 0000000..7b9c4d9
--- /dev/null
+++ b/src/ipc/ipcconnection.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "ipcconnection.h"
+
+#ifdef QMLLIVE_IPC_DEBUG
+#define DEBUG qDebug()
+#else
+#define DEBUG if (0) qDebug()
+#endif
+
+/**
+ * \class IpcConnection
+ * \brief Handles a single connection from the IpcServer
+ * \group ipc
+ */
+
+/**
+ * \brief Constructs a IpcConnection with \a socket and a \a parent
+ */
+IpcConnection::IpcConnection(QTcpSocket *socket, QObject *parent)
+ : QObject(parent)
+ , m_socket(socket)
+ , m_headerComplete(false)
+ , m_maxContentSize(1024*1024*10)
+{
+ DEBUG << "IpcConnection()";
+
+ connect(m_socket, SIGNAL(disconnected()), this, SLOT(close()));
+ connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(closeWithError()));
+ connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData()));
+}
+
+/**
+ * \brief Close the connection and delete it
+ */
+void IpcConnection::close()
+{
+ DEBUG << "IpcConnection::close()";
+ emit connectionClosed();
+}
+
+/**
+ * \brief Report errors and close the connection
+ */
+void IpcConnection::closeWithError()
+{
+ DEBUG << "IpcConnection::closeWithError: " << m_socket->errorString();
+ emit error(m_socket->errorString());
+ close();
+}
+
+/**
+ * \brief handles incoming data
+ */
+void IpcConnection::readData()
+{
+ while (m_socket->bytesAvailable()) {
+ if (!m_headerComplete) {
+
+ //Not enough bytesAvailable() try again later.
+ if (!m_socket->canReadLine())
+ return;
+
+ while (m_socket->canReadLine()) {
+ QString line = m_socket->readLine().trimmed();
+ DEBUG << "\treceived header: " << line;
+ if (line.isEmpty()) {
+ DEBUG << "\theader complete";
+ if (m_headers.contains("Method") || m_headers.contains("Content-Length")) {
+ m_headerComplete = true;
+ } else { // we can't recover
+ qWarning() << "\tincomplete header";
+ reset();
+ }
+ break;
+ }
+ QStringList parts = line.split(":");
+ if (parts.count() != 2) {
+ qWarning() << "invalid header line: " << line;
+ break;
+ }
+ m_headers.insert(parts.at(0).trimmed(), parts.at(1).trimmed());
+ }
+ }
+ if (m_headerComplete) {
+ int bufferSize = m_headers.value("Content-Length").toInt();
+ if (bufferSize > m_maxContentSize) {
+ qWarning() << "content to large to be received. max size: " << m_maxContentSize;
+ reset();
+ return;
+ }
+
+ DEBUG << "receive content (bytes): " << bufferSize;
+ if (m_socket->bytesAvailable() < bufferSize) {
+ DEBUG << "content wait for more data";
+ return;
+ } else {
+ QByteArray content;
+ content.resize(bufferSize);
+ if (m_socket->read(content.data(), bufferSize) != bufferSize) {
+ qWarning() << "error reading content from stream";
+ }
+ QString method = m_headers.value("Method");
+ reset();
+ emit received(method, content);
+ }
+ }
+ }
+}
+
+/**
+ * \brief Max bytes we are able to receive. Defaults to 10Mbytes.
+ * Returns the max content size
+ */
+qint64 IpcConnection::maxContentSize() const
+{
+ return m_maxContentSize;
+}
+
+void IpcConnection::reset()
+{
+ m_headerComplete = false;
+ m_headers.clear();
+}
+
+QTcpSocket *IpcConnection::socket() const
+{
+ return m_socket;
+}
diff --git a/src/ipc/ipcconnection.h b/src/ipc/ipcconnection.h
new file mode 100644
index 0000000..821342a
--- /dev/null
+++ b/src/ipc/ipcconnection.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtNetwork>
+
+class IpcConnection : public QObject
+{
+ Q_OBJECT
+public:
+ explicit IpcConnection(QTcpSocket* socket, QObject *parent = 0);
+ QTcpSocket* socket() const;
+private:
+ void setMaxContentSize(qint64 size);
+ qint64 maxContentSize() const;
+ void reset();
+private Q_SLOTS:
+ void close();
+ void closeWithError();
+ void readData();
+Q_SIGNALS:
+ void connectionClosed();
+ void error(const QString& message);
+ void received(const QString& method, const QByteArray& content);
+private:
+ QTcpSocket *m_socket;
+ QHash<QString,QString> m_headers;
+ bool m_headerComplete;
+ qint64 m_maxContentSize;
+};
+
diff --git a/src/ipc/ipcserver.cpp b/src/ipc/ipcserver.cpp
new file mode 100644
index 0000000..623cbff
--- /dev/null
+++ b/src/ipc/ipcserver.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "ipcserver.h"
+#include "ipcconnection.h"
+
+#ifdef QMLLIVE_IPC_DEBUG
+#define DEBUG qDebug()
+#else
+#define DEBUG if (0) qDebug()
+#endif
+
+/*!
+ * \class IpcServer
+ * \brief The IpcServer listens on a port and creates an IpcConnection for an incoming
+ * connection.
+ * \group ipc
+ *
+ * The IPC server receives a method call from the client an notifies the user through
+ * the IpcServer::received signal.
+ *
+ * \code{.cpp}
+ * m_server = new IpcServer(this);
+ * connect(
+ * m_server, SIGNAL(received(QString,QByteArray)),
+ * this, SLOT(handleCall(QString, QByteArray))
+ * );
+ * m_server->listen(10234);
+ *
+ * ...
+ *
+ * MyHandler::handleCall(const QString& method, const QByteArray& contnt) {
+ * if (method == "echo(QString)") {
+ * QString text;
+ * QDataStream in(content);
+ * in >> text;
+ * qDebug() << "call received: " << method << ": " << text;
+ * }
+ * }
+ * \endcode
+ */
+
+/*!
+ * \brief Standard constructor using \a parent as parent object
+ */
+IpcServer::IpcServer(QObject *parent)
+ : QObject(parent)
+ , m_server(new QTcpServer(this))
+{
+ connect(m_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
+}
+
+/*!
+ * \brief listens to incomong connections on \a port
+ */
+void IpcServer::listen(int port)
+{
+ DEBUG << "IpcServer::listen: " << port;
+ m_server->listen(QHostAddress::Any, port);
+}
+
+/*!
+ * \brief Creates a IpcConnection on incoming connection
+ */
+void IpcServer::newConnection()
+{
+ DEBUG << "IpcServer::newConnection";
+ if (m_server->hasPendingConnections()) {
+ QTcpSocket* socket = m_server->nextPendingConnection();
+ emit clientConnected(socket->peerAddress());
+ emit clientConnected(socket);
+ IpcConnection* connection = new IpcConnection(socket, this);
+ connect(connection, SIGNAL(connectionClosed()), this, SLOT(onConnectionClosed()));
+ connect(connection, SIGNAL(received(QString,QByteArray)), this, SIGNAL(received(QString,QByteArray)));
+ }
+}
+
+/*!
+ * \fn void IpcServer::received(const QString& method, const QByteArray& content);
+ * \brief signals a ipc call has arrived
+ *
+ * A ipc call requesting \a method and using \a content a the parameters for the method
+ */
+
+
+void IpcServer::onConnectionClosed()
+{
+ IpcConnection* connection = qobject_cast<IpcConnection*>(sender());
+
+ emit clientDisconnected(connection->socket()->peerAddress());
+ emit clientDisconnected(connection->socket());
+
+ if (connection->parent() == this)
+ delete connection;
+}
+
+void IpcServer::setMaxConnections(int num)
+{
+ m_server->setMaxPendingConnections(num);
+}
diff --git a/src/ipc/ipcserver.h b/src/ipc/ipcserver.h
new file mode 100644
index 0000000..337ea3d
--- /dev/null
+++ b/src/ipc/ipcserver.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtNetwork>
+
+class IpcServer : public QObject
+{
+ Q_OBJECT
+public:
+ explicit IpcServer(QObject *parent = 0);
+ void listen(int port);
+ void setMaxConnections(int num);
+private Q_SLOTS:
+ void newConnection();
+Q_SIGNALS:
+ void received(const QString& method, const QByteArray& content);
+ void clientConnected(const QHostAddress& address);
+ void clientConnected(QTcpSocket* socket);
+ void clientDisconnected(QTcpSocket* socket);
+ void clientDisconnected(const QHostAddress& address);
+
+private Q_SLOTS:
+ void onConnectionClosed();
+
+private:
+ QTcpServer *m_server;
+};
+
diff --git a/src/lib/lib.pro b/src/lib/lib.pro
new file mode 100644
index 0000000..81af9ea
--- /dev/null
+++ b/src/lib/lib.pro
@@ -0,0 +1,14 @@
+TEMPLATE = lib
+TARGET = qmllive
+
+
+DESTDIR = ../../libs
+DEFINES += QMLLIVE_LIBRARY
+
+SOURCES += \
+ qmllive.cpp
+
+HEADERS +=\
+ qmllive_global.h \
+ qmllive.h
+
diff --git a/src/lib/qmllive.cpp b/src/lib/qmllive.cpp
new file mode 100644
index 0000000..65ffb52
--- /dev/null
+++ b/src/lib/qmllive.cpp
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+#include "qmllive.h"
+
+
+QmlLive::QmlLive()
+{
+}
diff --git a/src/lib/qmllive.h b/src/lib/qmllive.h
new file mode 100644
index 0000000..f69a6e3
--- /dev/null
+++ b/src/lib/qmllive.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#ifndef QMLLIVELIB_H
+#define QMLLIVELIB_H
+
+#include "qmllive_global.h"
+
+class QMLLIVESHARED_EXPORT QmlLive
+{
+public:
+ QmlLive();
+};
+
+#endif // QMLLIVELIB_H
diff --git a/src/lib/qmllive_global.h b/src/lib/qmllive_global.h
new file mode 100644
index 0000000..cdad758
--- /dev/null
+++ b/src/lib/qmllive_global.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#ifndef QMLLIVELIB_GLOBAL_H
+#define QMLLIVELIB_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(QMLLIVE_LIBRARY)
+# define QMLLIVESHARED_EXPORT Q_DECL_EXPORT
+#else
+# define QMLLIVESHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // QMLLIVELIB_GLOBAL_H
diff --git a/src/livehubengine.cpp b/src/livehubengine.cpp
new file mode 100644
index 0000000..3561053
--- /dev/null
+++ b/src/livehubengine.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "livehubengine.h"
+#include "watcher.h"
+
+#ifdef QMLLIVE_DEBUG
+#define DEBUG qDebug()
+#else
+#define DEBUG if (0) qDebug()
+#endif
+
+/*!
+ * \class LiveHubEngine
+ * \brief The LiveHubEngine class watches over a workspace and notifies a node on changes
+ * \group qmllive
+ *
+ * The live hub watches over a workspace and notifies a live node about changed files. A
+ * node can run on the same device or even on a remote device using a RemotePublisher.
+ */
+
+/*!
+ * Standard constructor using \a parent as parent
+ */
+LiveHubEngine::LiveHubEngine(QObject *parent)
+ : QObject(parent)
+ , m_watcher(new Watcher(this))
+ , m_filePublishingActive(false)
+{
+ connect(m_watcher, SIGNAL(directoriesChanged(QStringList)), this, SLOT(directoriesChanged(QStringList)));
+}
+
+/*!
+ * Sets the workspace folder to watch over to \a path
+ */
+void LiveHubEngine::setWorkspace(const QString &path)
+{
+ m_watcher->setDirectory(path);
+
+ emit workspaceChanged(path);
+}
+
+/*!
+ * Returns the current workspace
+ */
+QString LiveHubEngine::workspace() const
+{
+ return m_watcher->directory();
+}
+
+/*!
+ * Sets the active document path to path.
+ * Emits activateDocument() with the workspace relative path.
+ */
+void LiveHubEngine::setActivePath(const QString &path)
+{
+ m_activePath = path;
+ emit activateDocument(m_watcher->relativeFilePath(path));
+}
+
+/*!
+ * Returns the active Document
+ */
+QString LiveHubEngine::activePath() const
+{
+ return m_activePath;
+}
+
+/*!
+ * Handles watcher changes signals.
+ */
+void LiveHubEngine::directoriesChanged(const QStringList &changes)
+{
+ DEBUG << "LiveHubEngine::workspaceChanged: " << changes;
+ if (m_filePublishingActive) {
+ foreach (const QString& change, changes) {
+ publishDirectory(change, true);
+ }
+ }
+
+ emit activateDocument(m_watcher->relativeFilePath(m_activePath));
+}
+
+/*!
+ * Publish the whole workspace to a connected node.
+ */
+void LiveHubEngine::publishWorkspace()
+{
+ if (!m_filePublishingActive) { return; }
+ QDirIterator iter(m_watcher->directory(), QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
+ publishDirectory(m_watcher->directory(), false);
+ while (iter.hasNext()) {
+ publishDirectory(iter.next(), false);
+ }
+}
+
+/*!
+ * Publish the directory \a dirPath to a connected node.
+ */
+void LiveHubEngine::publishDirectory(const QString& dirPath, bool fileChange)
+{
+ if (!m_filePublishingActive) { return; }
+ QDirIterator iter(dirPath, QDir::Files);
+ while (iter.hasNext()) {
+ if (fileChange)
+ emit fileChanged(iter.next());
+ else
+ emit publishFile(iter.next());
+ }
+}
+
+/*!
+ * Sets the file publishing to \a on
+ */
+void LiveHubEngine::setFilePublishingActive(bool on)
+{
+ m_filePublishingActive = on;
+}
+
+/*!
+ * \fn void LiveHubEngine::workspaceChanged()
+ * Emits that the workspace changed
+ */
+
+/*!
+ * \fn void LiveHubEngine::activateDocument(const QString& document)
+ * The document \a document is now active
+ */
+
+/*!
+ * \fn void LiveHubEngine::sendDocument(const QString& document, const QByteArray& data)
+ * The Document \a document with the content \a data was sent
+ */
diff --git a/src/livehubengine.h b/src/livehubengine.h
new file mode 100644
index 0000000..bf087ad
--- /dev/null
+++ b/src/livehubengine.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+
+class Watcher;
+class ContentPluginFactory;
+
+class LiveHubEngine : public QObject
+{
+ Q_OBJECT
+public:
+ explicit LiveHubEngine(QObject *parent = 0);
+ void setWorkspace(const QString& path);
+ QString workspace() const;
+
+ QString activePath() const;
+public Q_SLOTS:
+ void setActivePath(const QString& path);
+ void setFilePublishingActive(bool on);
+ void publishWorkspace();
+Q_SIGNALS:
+ void publishFile(const QString& document);
+ void fileChanged(const QString& document);
+ void activateDocument(const QString& document);
+ void workspaceChanged(const QString& workspace);
+private Q_SLOTS:
+ void directoriesChanged(const QStringList& changes);
+private:
+ void publishDirectory(const QString& dirPath, bool fileChange);
+private:
+ Watcher *m_watcher;
+ bool m_filePublishingActive;
+ QString m_activePath;
+};
+
diff --git a/src/livenodeengine.cpp b/src/livenodeengine.cpp
new file mode 100644
index 0000000..8bfeefe
--- /dev/null
+++ b/src/livenodeengine.cpp
@@ -0,0 +1,477 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "livenodeengine.h"
+#include "liveruntime.h"
+#include "qmlhelper.h"
+#include "contentpluginfactory.h"
+#include "imageadapter.h"
+#include "fontadapter.h"
+
+#include "QtQml/qqml.h"
+#include "QtQuick/private/qquickpixmapcache_p.h"
+
+// TODO: create proxy configuration settings, controlled by command line and ui
+
+#ifdef QMLLIVE_DEBUG
+#define DEBUG qDebug()
+#else
+#define DEBUG if (0) qDebug()
+#endif
+
+/*!
+ * \class LiveNodeEngine
+ * \brief The LiveNodeEngine class instruments a qml viewer in cooperation with LiveHubEngine.
+ * \group qmllive
+ *
+ * LiveNodeEngine provides ways to reload qml documents based incoming requests
+ * from a hub. A hub can be connected via a local mode ( LocalPublisher) or
+ * remote mode (RemotePublisher with a RemoteReceiver).
+ *
+ * In Addition to showing qml-Files the LiveNodeEngine can be extended by plugins to show any other datatype.
+ * One need to set the Plugin path to the right destination and the LiveNodeEngine will load all the plugins
+ * it finds there.
+ *
+ * \sa {ContentPlugin Example}
+ */
+
+/*!
+ * Standard constructor using \a parent as parent
+ */
+LiveNodeEngine::LiveNodeEngine(QObject *parent)
+ : QObject(parent)
+ , m_runtime(new LiveRuntime(this))
+ , m_xOffset(0)
+ , m_yOffset(0)
+ , m_rotation(0)
+ , m_view(0)
+ , m_recreateView(0)
+ , m_delayReload(new QTimer(this))
+ , m_mode(ReloadDocument)
+ , m_pluginFactory(new ContentPluginFactory(this))
+ , m_activePlugin(0)
+ , m_reloadPlugins(false)
+{
+ m_delayReload->setInterval(250);
+ m_delayReload->setSingleShot(true);
+ connect(m_delayReload, SIGNAL(timeout()), this, SLOT(reloadDocument()));
+}
+
+/*!
+ * Sets the view which should be used to \a view
+ */
+ void LiveNodeEngine::setView(QQuickView *view)
+{
+ m_view = view;
+ m_view->rootContext()->setContextProperty("livert", m_runtime);
+ m_view->engine()->setOutputWarningsToStandardError(false); // log
+ m_view->engine()->setImportPathList(m_importPaths);
+
+ connect(m_view->engine(), SIGNAL(warnings(QList<QQmlError>)),
+ this, SIGNAL(logErrors(QList<QQmlError>)));
+ connect(m_view, SIGNAL(statusChanged(QQuickView::Status)),
+ this, SLOT(onStatusChanged(QQuickView::Status)));
+ connect(m_view, SIGNAL(widthChanged(int)),
+ this, SLOT(onSizeChanged()));
+ connect(m_view, SIGNAL(heightChanged(int)),
+ this, SLOT(onSizeChanged()));
+}
+
+void LiveNodeEngine::setXOffset(int offset)
+{
+ QQuickView* view = 0;
+
+ if (m_view)
+ view = m_view;
+ if (m_recreateView)
+ view = m_recreateView;
+ if (view)
+ view->contentItem()->setX(offset);
+
+ m_xOffset = offset;
+}
+
+int LiveNodeEngine::xOffset() const
+{
+ return m_xOffset;
+}
+
+void LiveNodeEngine::setYOffset(int offset)
+{
+ QQuickView* view = 0;
+
+ if (m_view)
+ view = m_view;
+ if (m_recreateView)
+ view = m_recreateView;
+ if (view)
+ view->contentItem()->setY(offset);
+
+ m_yOffset = offset;
+}
+
+int LiveNodeEngine::yOffset() const
+{
+ return m_yOffset;
+}
+
+void LiveNodeEngine::setRotation(int rotation)
+{
+ QQuickView* view = 0;
+
+ if (m_view)
+ view = m_view;
+ if (m_recreateView)
+ view = m_recreateView;
+ if (view) {
+ view->contentItem()->setRotation(0);
+ view->contentItem()->setTransformOriginPoint(QPointF(view->width()/2, view->height()/2));
+ view->contentItem()->setRotation(rotation);
+ }
+
+ m_rotation = rotation;
+}
+
+int LiveNodeEngine::rotation() const
+{
+ return m_rotation;
+}
+
+void LiveNodeEngine::setUpdateMode(LiveNodeEngine::UpdateMode mode)
+{
+ m_mode = mode;
+}
+
+LiveNodeEngine::UpdateMode LiveNodeEngine::updateMode() const
+{
+ return m_mode;
+}
+
+/*!
+ * Loads the given \a url onto the qml view. Clears any caches and reloads
+ * the dummy data initially.
+ */
+void LiveNodeEngine::loadDocument(const QUrl& url)
+{
+ DEBUG << "LiveNodeEngine::loadDocument: " << url;
+ m_activeFile = url;
+
+ if (!m_activeFile.isEmpty())
+ reloadDocument();
+}
+
+void LiveNodeEngine::delayReload()
+{
+ m_delayReload->start();
+}
+
+/*!
+ * Sets the view which should be used to \a view
+ */
+void LiveNodeEngine::recreateView()
+{
+ if (m_windowComponent)
+ delete m_windowComponent;
+ if (m_windowObject)
+ delete m_windowObject;
+
+ if (m_recreateView) {
+ //m_recreateView->setSource(QUrl());
+ m_recreateView->engine()->clearComponentCache();
+ delete m_recreateView;
+ if (m_reloadPlugins)
+ qmlClearTypeRegistrations();
+ QQuickPixmap::purgeCache();
+ }
+
+ m_recreateView = initView();
+
+ setXOffset(m_xOffset);
+ setYOffset(m_yOffset);
+
+ m_recreateView->rootContext()->setContextProperty("livert", m_runtime);
+ m_recreateView->engine()->setOutputWarningsToStandardError(false); // log
+ if (!m_importPaths.isEmpty())
+ m_recreateView->engine()->setImportPathList(m_importPaths);
+
+ m_recreateView->engine()->clearComponentCache();
+ QmlHelper::loadDummyData(m_recreateView, m_workspace.absolutePath());
+
+ connect(m_recreateView->engine(), SIGNAL(warnings(QList<QQmlError>)),
+ this, SIGNAL(logErrors(QList<QQmlError>)));
+ connect(m_recreateView, SIGNAL(statusChanged(QQuickView::Status)),
+ this, SLOT(onStatusChanged(QQuickView::Status)));
+ connect(m_recreateView, SIGNAL(widthChanged(int)),
+ this, SLOT(onSizeChanged()));
+ connect(m_recreateView, SIGNAL(heightChanged(int)),
+ this, SLOT(onSizeChanged()));
+}
+
+void LiveNodeEngine::checkQmlFeatures(QQuickView *view)
+{
+ foreach (QString importPath, view->engine()->importPathList()) {
+ QDir dir(importPath);
+ if (dir.exists("QtQuick/Controls") &&
+ dir.exists("QtQuick/Layouts") &&
+ dir.exists("QtQuick/Dialogs")) {
+ m_quickFeatures |= ContentAdapterInterface::QtQuickControls;
+ }
+ }
+}
+
+/*!
+ * Reloads the qml view source.
+ */
+void LiveNodeEngine::reloadDocument()
+{
+ QQuickView *view = 0;
+
+ if (m_mode == RecreateView) {
+ recreateView();
+
+ view = m_recreateView;
+ } else {
+ view = m_view;
+ view->setSource(QUrl());
+ }
+
+ checkQmlFeatures(view);
+
+ emit logClear();
+ //emit logIgnoreMessages(true);
+
+ QUrl url = queryDocumentViewer(m_activeFile);
+ QQmlEngine* engine = view->engine();
+ m_windowComponent = new QQmlComponent(engine);
+
+ m_windowComponent->loadUrl(url);
+
+ m_windowObject = m_windowComponent->create();
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(m_windowObject);
+ if (window) {
+ engine->setIncubationController(window->incubationController());
+ window->show();
+ } else {
+ view->setContent(url, m_windowComponent, m_windowObject);
+ }
+
+ //emit logIgnoreMessages(false);
+
+ QList<QQmlError> errors = view->errors();
+ if (!errors.isEmpty()) {
+ emit logErrors(errors);
+ if (m_quickFeatures.testFlag(ContentAdapterInterface::QtQuickControls))
+ view->setSource(QUrl("qrc:/livert/error_qt5_controls.qml"));
+ view->setSource(QUrl("qrc:/livert/error_qt5.qml"));
+ }
+
+ if (m_mode == RecreateView)
+ view->setVisible(true);
+
+ if (m_activePlugin || (view->rootObject() && QSize(view->rootObject()->width(), view->rootObject()->height()).isEmpty())) {
+ view->setResizeMode(QQuickView::SizeRootObjectToView);
+ } else {
+ view->setResizeMode(QQuickView::SizeViewToRootObject);
+ }
+}
+
+
+/*!
+ * Allows to adapt a \a url to display not native qml documents (e.g. images).
+ */
+QUrl LiveNodeEngine::queryDocumentViewer(const QUrl& url)
+{
+ initPlugins();
+
+ foreach (ContentAdapterInterface* adapter, m_plugins) {
+ if (adapter->canAdapt(url)) {
+ adapter->cleanUp();
+ adapter->setAvailableFeatures(m_quickFeatures);
+
+ m_activePlugin = adapter;
+
+ if (m_mode == RecreateView)
+ return adapter->adapt(url, m_recreateView->rootContext());
+ else
+ return adapter->adapt(url, m_view->rootContext());
+ }
+ }
+
+ m_activePlugin = 0;
+
+ return url;
+}
+
+/*!
+ * Sets the document \a document to be shown
+ *
+ */
+void LiveNodeEngine::setActiveDocument(const QString &document)
+{
+ QUrl url;
+ if (!document.isEmpty()) {
+ url = QUrl::fromLocalFile(m_workspace.absoluteFilePath(document));
+ }
+
+ loadDocument(url);
+ emit activateDocument(document);
+}
+
+/*!
+ * Sets the current workspace to \a path. Documents location will be adjusted based on
+ * this workspace path.
+ */
+void LiveNodeEngine::setWorkspace(const QString &path)
+{
+ m_workspace = QDir(path);
+}
+
+void LiveNodeEngine::setImportPaths(const QStringList &paths)
+{
+ m_importPaths = paths;
+
+ if (m_view)
+ m_view->engine()->setImportPathList(paths);
+}
+
+QStringList LiveNodeEngine::importPaths() const
+{
+ return m_importPaths;
+}
+
+/*!
+ * Sets the pluginPath to \a path.
+ *
+ * The pluginPath will be used to load QmlLive plugins
+ * \sa {ContentPlugin Example}
+ */
+void LiveNodeEngine::setPluginPath(const QString &path)
+{
+ m_pluginFactory->setPluginPath(path);
+}
+
+/*!
+ * Returns the current pluginPath
+ */
+QString LiveNodeEngine::pluginPath() const
+{
+ return m_pluginFactory->pluginPath();
+}
+
+/*!
+ * Returns the current active document url.
+ */
+QUrl LiveNodeEngine::activeDocument() const
+{
+ return m_activeFile;
+}
+
+ContentAdapterInterface *LiveNodeEngine::activePlugin() const
+{
+ return m_activePlugin;
+}
+
+void LiveNodeEngine::setReloadPluginsEnabled(bool enabled)
+{
+ m_reloadPlugins = enabled;
+}
+
+bool LiveNodeEngine::isReloadPluginsEnabled() const
+{
+ return m_reloadPlugins;
+}
+
+/*!
+ * Loads all plugins found in the Pluginpath
+ */
+void LiveNodeEngine::initPlugins()
+{
+ if (m_plugins.isEmpty()) {
+ m_pluginFactory->load();
+ m_plugins.append(m_pluginFactory->plugins());
+ m_plugins.append(new ImageAdapter(this));
+ m_plugins.append(new FontAdapter(this));
+ }
+}
+
+void LiveNodeEngine::onStatusChanged(QQuickView::Status status)
+{
+ if (status == QQuickView::Ready ||
+ status == QQuickView::Error) {
+ emit documentLoaded();
+ }
+}
+
+QQuickView *LiveNodeEngine::initView()
+{
+ QQuickView* view = new QQuickView();
+ emit viewChanged(view);
+ return view;
+}
+
+void LiveNodeEngine::onSizeChanged()
+{
+ int width = -1, height = -1;
+
+ if (m_mode == RecreateView && m_recreateView) {
+ width = m_recreateView->width();
+ height = m_recreateView->height();
+ } else if (m_mode == ReloadDocument && m_view) {
+ width = m_view->width();
+ height = m_view->height();
+ }
+
+ if (width != -1 && height != -1) {
+ m_runtime->setScreenWidth(width);
+ m_runtime->setScreenHeight(height);
+ }
+
+ setRotation(m_rotation);
+}
+
+/*!
+ * \fn void LiveNodeEngine::activateDocument(const QString& document);
+ * The document \a document was activated
+ */
+
+/*!
+ * \fn void LiveNodeEngine::logClear();
+ * Requested to clear the log
+ */
+
+/*!
+ * \fn void LiveNodeEngine::logIgnoreMessages(bool);
+ * Requsted to ignore the Messages when \a on is true
+ */
+
+/*!
+ * \fn void LiveNodeEngine::logErrors(const QList<QQmlError> &errors);
+ * Log the Errors \a errors
+ */
diff --git a/src/livenodeengine.h b/src/livenodeengine.h
new file mode 100644
index 0000000..f9d5f6f
--- /dev/null
+++ b/src/livenodeengine.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtQuick>
+
+#include "contentadapterinterface.h"
+
+class IpcPeer;
+class LiveRuntime;
+class ContentPluginFactory;
+
+class LiveNodeEngine : public QObject
+{
+ Q_OBJECT
+public:
+
+ enum UpdateMode {
+ ReloadDocument,
+ RecreateView,
+ RecreateProcess
+ };
+ Q_ENUMS(UpdateMode)
+
+ explicit LiveNodeEngine(QObject *parent = 0);
+ virtual void setView(QQuickView* view);
+
+ int xOffset() const;
+ int yOffset() const;
+ int rotation() const;
+
+ void setUpdateMode(LiveNodeEngine::UpdateMode mode);
+ LiveNodeEngine::UpdateMode updateMode() const;
+
+ void setWorkspace(const QString& path);
+
+ void setImportPaths(const QStringList& paths);
+ QStringList importPaths() const;
+
+ void setPluginPath(const QString& path);
+ QString pluginPath() const;
+
+ QUrl activeDocument() const;
+ ContentAdapterInterface *activePlugin() const;
+ bool isReloadPluginsEnabled() const;
+
+public Q_SLOTS:
+
+ void setXOffset(int offset);
+ void setYOffset(int offset);
+ void setRotation(int rotation);
+ void setReloadPluginsEnabled(bool enabled);
+ void setActiveDocument(const QString& document);
+ void loadDocument(const QUrl& url);
+ void delayReload();
+ virtual void reloadDocument();
+Q_SIGNALS:
+ void activateDocument(const QString& document);
+ void logClear();
+ void logIgnoreMessages(bool on);
+ void documentLoaded();
+ void viewChanged(QQuickView *view);
+ void logErrors(const QList<QQmlError> &errors);
+
+
+protected:
+ virtual QQuickView* initView();
+ virtual void initPlugins();
+ QList<ContentAdapterInterface*> m_plugins;
+ QUrl m_activeFile;
+ LiveRuntime *m_runtime;
+private Q_SLOTS:
+ void onStatusChanged(QQuickView::Status status);
+ void onSizeChanged();
+
+ void recreateView();
+
+ void checkQmlFeatures(QQuickView *view);
+
+private:
+ QUrl queryDocumentViewer(const QUrl& url);
+private:
+ int m_xOffset;
+ int m_yOffset;
+ int m_rotation;
+
+ IpcPeer *m_ipc;
+ QQuickView *m_view;
+ QQuickView *m_recreateView;
+ QPointer<QQmlComponent> m_windowComponent;
+ QPointer<QObject> m_windowObject;
+ QDir m_workspace;
+ QTimer *m_delayReload;
+ QStringList m_importPaths;
+
+ UpdateMode m_mode;
+
+ ContentPluginFactory* m_pluginFactory;
+ ContentAdapterInterface* m_activePlugin;
+
+ ContentAdapterInterface::Features m_quickFeatures;
+
+ bool m_reloadPlugins;
+};
+
diff --git a/src/livert.qrc b/src/livert.qrc
new file mode 100644
index 0000000..6c9d2ce
--- /dev/null
+++ b/src/livert.qrc
@@ -0,0 +1,18 @@
+<RCC>
+ <qresource prefix="/">
+ <file>livert/error_qt5.qml</file>
+ <file>livert/logo.png</file>
+ <file>livert/imageviewer_qt5.qml</file>
+ <file>images/favicon.png</file>
+ <file>livert/folderview_qt5.qml</file>
+ <file>livert/fontviewer_qt5.qml</file>
+ <file>livert/no.png</file>
+ <file>livert/error_qt5_controls.qml</file>
+ <file>livert/folderview_qt5_controls.qml</file>
+ <file>livert/fontviewer_qt5_controls.qml</file>
+ <file>livert/imageviewer_qt5_controls.qml</file>
+ <file>images/icon_online.png</file>
+ <file>images/icon_offline.png</file>
+ <file>images/icon_failover.png</file>
+ </qresource>
+</RCC>
diff --git a/src/livert/error_qt5.qml b/src/livert/error_qt5.qml
new file mode 100644
index 0000000..8a48a8d
--- /dev/null
+++ b/src/livert/error_qt5.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Rectangle {
+ width: 800
+ height: 480
+
+ SystemPalette {
+ id: palette;
+ colorGroup: SystemPalette.Active
+ }
+ color: palette.base
+
+ Image {
+ anchors.fill: parent;
+ source: "logo.png"
+ fillMode: Image.Tile
+ opacity: 0.5
+ }
+ Text {
+ anchors.centerIn: parent
+ text: qsTr("An error occurred - please check the Log Output pane.")
+ font.pointSize: 20
+ font.bold: true
+ color: palette.text
+ }
+}
diff --git a/src/livert/error_qt5_controls.qml b/src/livert/error_qt5_controls.qml
new file mode 100644
index 0000000..fc89ad3
--- /dev/null
+++ b/src/livert/error_qt5_controls.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+
+Rectangle {
+ width: 800
+ height: 480
+
+ SystemPalette {
+ id: palette;
+ colorGroup: SystemPalette.Active
+ }
+ color: palette.base
+
+ Image {
+ anchors.fill: parent;
+ source: "logo.png"
+ fillMode: Image.Tile
+ opacity: 0.5
+ }
+ Label {
+ anchors.fill: parent
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ text: qsTr("An error occurred - please check the Log Output pane. (Controls)")
+ wrapMode: Text.WordWrap
+ font.pointSize: 20
+ font.bold: true
+ color: palette.text
+ }
+}
diff --git a/src/livert/folderview_qt5.qml b/src/livert/folderview_qt5.qml
new file mode 100644
index 0000000..54a4e33
--- /dev/null
+++ b/src/livert/folderview_qt5.qml
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: livert.screenWidth
+ height: livert.screenHeight
+
+ property color backgroundColor: '#666'
+ property color textColor: '#fff'
+
+ Rectangle {
+ anchors.fill: parent
+ color: root.backgroundColor
+ }
+
+ Rectangle {
+ id: header
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ height: 32
+
+ z: 2
+
+ color: "#E0E0E0"
+
+ Rectangle {
+ }
+
+ Row {
+ anchors.left: parent.left
+ anchors.leftMargin: 8
+ width: childrenRect.width
+ height: 24
+ anchors.verticalCenter: parent.verticalCenter
+ Repeater {
+ model: [
+ { bg: '#000', text: '#fff' },
+ { bg: '#666', text: '#000' },
+ { bg: '#fff', text: '#000' }
+ ]
+ Rectangle {
+ color: modelData.bg
+ width: 24
+ height: parent.height
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ root.backgroundColor = modelData.bg
+ root.textColor = modelData.text
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ id: slider
+ anchors.right: parent.right
+ anchors.rightMargin: 8
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+
+ property real minValue: 80
+ property real maxValue: 300
+ //Math.min workaround to prevent that it its Infinity (otherwise the Selection item doesn't work anymore)
+ property real value: Math.min((handle.x / line.width) * (maxValue - minValue) + minValue, maxValue)
+
+ width: 200
+
+ Rectangle {
+ id: line
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+
+ color: "black"
+
+ height: 2
+ }
+
+ Rectangle {
+ id: handle
+
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.margins: 5
+ x: parent.width/2
+ width: 12
+
+ border.width: 2
+ border.color: "black"
+
+ color: "#e0e0e0"
+
+ MouseArea {
+ anchors.fill: parent
+
+ property real xPos
+
+ onClicked: xPos = mouse.x
+
+ onPositionChanged: {
+ var delta = mouse.x - xPos - handle.width / 2
+ var newPos = handle.x + delta
+ if (newPos + handle.width / 2> 0 && newPos < line.width - handle.width / 2)
+ handle.x = newPos
+ }
+ }
+ }
+ }
+ }
+
+ GridView {
+ id: grid
+
+ anchors.top: header.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ anchors.margins: 30
+
+ cellWidth: slider.value
+ cellHeight: slider.value
+
+ keyNavigationWraps: true
+
+ focus: true
+
+ model: files
+
+ delegate: FocusScope {
+ width: grid.cellWidth - 4
+ height: grid.cellHeight - 4
+
+
+ Item {
+ id: delegate
+ anchors.fill: parent
+ anchors.margins: 4
+
+ function loadDocument() {
+ adapter.loadDocument(path + "/" + modelData)
+ }
+
+ focus: true
+
+ Keys.onReturnPressed: delegate.loadDocument()
+ Keys.onLeftPressed: grid.moveCurrentIndexLeft()
+ Keys.onRightPressed: grid.moveCurrentIndexRight()
+ Keys.onUpPressed: grid.moveCurrentIndexUp()
+ Keys.onDownPressed: grid.moveCurrentIndexDown()
+
+ Image {
+ id: image
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ height: 0.8 * width
+
+ source: "image://qmlLiveDirectoryPreview/" + path + "/" + modelData
+
+ fillMode: Image.PreserveAspectFit
+ sourceSize.width: slider.maxValue
+ sourceSize.height: slider.maxValue
+
+ asynchronous: true
+ cache: false
+ }
+
+ Text {
+ id: label
+ anchors.top: image.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ text: modelData
+ color: root.textColor
+
+ textFormat: Text.PlainText
+ elide: Text.ElideMiddle
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: grid.currentIndex = index
+ onDoubleClicked: delegate.loadDocument()
+ }
+ }
+ }
+
+ highlight: FocusScope {
+ id: highlight
+ Rectangle {
+ width: grid.cellWidth
+ height: grid.cellHeight
+ color: "#33B5E5"
+ opacity: 0.5
+ }
+ }
+ }
+
+ Item {
+ id: scrollBar
+
+ width: 15; height: grid.height
+ anchors.top: header.bottom
+ anchors.right: parent.right
+ anchors.rightMargin: 3
+ anchors.bottom: parent.bottom
+
+ // The properties that define the scrollbar's state.
+ // position and pageSize are in the range 0.0 - 1.0. They are relative to the
+ // height of the page, i.e. a pageSize of 0.5 means that you can see 50%
+ // of the height of the view.
+ // orientation can be either Qt.Vertical or Qt.Horizontal
+ property Flickable flickable: grid
+ property real position: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.yPosition : flickable.visibleArea.xPosition
+ property real pageSize: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.heightRatio : flickable.visibleArea.widthRatio
+ property int orientation : Qt.Vertical
+ property alias enableDrag: mouseArea.enabled
+
+ visible: pageSize != 1
+
+ // A light, semi-transparent background
+ Rectangle {
+ id: background
+ anchors.fill: parent
+ radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
+ color: "white"
+ opacity: 0.3
+ }
+
+ // Size the bar to the required size, depending upon the orientation.
+ Rectangle {
+ id: bar
+ x: scrollBar.orientation == Qt.Vertical ? 1 : (scrollBar.position * (scrollBar.width-2) + 1)
+ y: scrollBar.orientation == Qt.Vertical ? (scrollBar.position * (scrollBar.height-2) + 1) : 1
+ width: scrollBar.orientation == Qt.Vertical ? (parent.width-2) : (scrollBar.pageSize * (scrollBar.width-2))
+ height: scrollBar.orientation == Qt.Vertical ? (scrollBar.pageSize * (scrollBar.height-2)) : (parent.height-2)
+ radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
+ color: "black"
+ opacity: 0.7
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ property variant pressedPos
+ property bool drag: true
+ onPressed: {
+ pressedPos = mapToItem(bar, mouseX, mouseY)
+ if (pressedPos.x >= 0 && pressedPos.x <= bar.width &&
+ pressedPos.y >= 0 && pressedPos.y <= bar.height)
+ drag = true
+ }
+ onReleased: drag = false
+
+ onPositionChanged: {
+ if (drag) {
+ if (scrollBar.orientation == Qt.Vertical) {
+ var newPos =((mouseY - pressedPos.y -1 ) / (scrollBar.height-2)) * scrollBar.flickable.contentHeight
+ if (newPos < 0)
+ scrollBar.flickable.contentY = 0
+ else if (newPos > (scrollBar.flickable.contentHeight - scrollBar.flickable.height))
+ scrollBar.flickable.contentY = (scrollBar.flickable.contentHeight - scrollBar.flickable.height)
+ else
+ scrollBar.flickable.contentY = newPos
+ } else {
+ var newPos =((mouseX - pressedPos.x -1 ) / (scrollBar.width-2)) * scrollBar.flickable.contentWidth
+ if (newPos < 0)
+ scrollBar.flickable.contentX = 0
+ else if (newPos > (scrollBar.flickable.contentWidth - scrollBar.flickable.width))
+ scrollBar.flickable.contentX = (scrollBar.flickable.contentWidth - scrollBar.flickable.width)
+ else
+ scrollBar.flickable.contentX = newPos
+ }
+ }
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ grid.forceActiveFocus();
+ }
+}
diff --git a/src/livert/folderview_qt5_controls.qml b/src/livert/folderview_qt5_controls.qml
new file mode 100644
index 0000000..ef8b1af
--- /dev/null
+++ b/src/livert/folderview_qt5_controls.qml
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Controls.Styles 1.0
+import QtQuick.Layouts 1.0
+
+Item {
+ id: root
+ width: livert.screenWidth
+ height: livert.screenHeight
+
+ property color backgroundColor: '#666'
+ property color textColor: '#fff'
+
+ Rectangle {
+ anchors.fill: parent
+ color: root.backgroundColor
+ }
+
+ Item {
+ id: header
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 32
+
+ z: 0
+
+ Rectangle {
+ anchors.fill: parent
+ color: "#E0E0E0"
+ }
+ RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: 8
+ anchors.rightMargin: 8
+ Repeater {
+ model: [
+ { bg: '#000', text: '#fff' },
+ { bg: '#666', text: '#000' },
+ { bg: '#fff', text: '#000' }
+ ]
+ Button {
+ text: " "
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 2
+ color: modelData.bg
+ }
+ onClicked: {
+ root.backgroundColor = modelData.bg
+ root.textColor = modelData.text
+ }
+ }
+ }
+ Item {
+ width: 16; height: 16
+ Layout.fillWidth: true
+ }
+
+ Slider {
+ id: slider
+ anchors.verticalCenter: parent.verticalCenter
+ maximumValue: 300
+ value: 190
+ minimumValue: 80
+ }
+ }
+
+ }
+
+
+ Component {
+ id: gridDelegate
+ FocusScope {
+ id: delegateContainer
+ width: grid.cellWidth - 4
+ height: grid.cellHeight - 4
+ Item {
+ id: delegate
+ anchors.fill: parent
+ anchors.margins: 4
+
+ function loadDocument() {
+ adapter.loadDocument(path + "/" + modelData)
+ }
+
+ focus: true
+
+ Keys.onReturnPressed: delegate.loadDocument()
+ Keys.onLeftPressed: grid.moveCurrentIndexLeft()
+ Keys.onRightPressed: grid.moveCurrentIndexRight()
+ Keys.onUpPressed: grid.moveCurrentIndexUp()
+ Keys.onDownPressed: grid.moveCurrentIndexDown()
+
+ Image {
+ id: image
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ height: 0.8 * width
+
+ source: "image://qmlLiveDirectoryPreview/" + path + "/" + modelData
+
+ fillMode: Image.PreserveAspectFit
+ sourceSize.width: slider.maximumValue
+ sourceSize.height: slider.maximumValue
+
+ asynchronous: true
+ cache: false
+ }
+
+ Text {
+ id: label
+ anchors.top: image.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ text: modelData
+ color: root.textColor
+
+ textFormat: Text.PlainText
+ elide: Text.ElideMiddle
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: grid.currentIndex = index;
+ onDoubleClicked: delegate.loadDocument()
+ }
+ }
+ }
+ }
+ ScrollView {
+ id: scrollView
+ anchors.top: header.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ //anchors.margins: 30
+ GridView {
+ id: grid
+
+
+ cellWidth: slider.value
+ cellHeight: slider.value
+
+ keyNavigationWraps: true
+
+ focus: true
+
+ model: files
+
+ delegate: gridDelegate
+
+ highlight: Item {
+ id: highlight
+ Rectangle {
+ width: grid.cellWidth
+ height: grid.cellHeight
+ color: "#33B5E5"
+ opacity: 0.5
+ }
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ scrollView.forceActiveFocus();
+ }
+}
diff --git a/src/livert/fontviewer_qt5.qml b/src/livert/fontviewer_qt5.qml
new file mode 100644
index 0000000..cfe497b
--- /dev/null
+++ b/src/livert/fontviewer_qt5.qml
@@ -0,0 +1,387 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: livert.screenWidth
+ height: livert.screenHeight
+
+ property alias testText: textInput.text
+ property int pointSize: 12
+ property var defaultWeights:[
+ { name: "Light", weight: Font.Light },
+ { name: "Regular", weight: Font.Normal },
+ { name: "DemiBold", weight: Font.DemiBold },
+ { name: "Bold", weight: Font.Bold },
+ { name: "Black", weight: Font.Black },
+ ]
+
+ property bool showAllWeights: false
+
+ Rectangle {
+ id: header
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ height: 32
+
+ z: 2
+
+ color: "#E0E0E0"
+
+ Row {
+ anchors.centerIn: parent
+
+ spacing: 2
+
+ height: 20
+ width: parent.width
+
+ Text {
+ width: 120
+ height: 20
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ text: "Font Size: " + root.pointSize + "pt "
+ }
+
+ Rectangle {
+ width: 20
+ height: 20
+
+ Text {
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: "+"
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: pointSize += 2
+ }
+ }
+
+ Rectangle {
+ width: 20
+ height: 20
+
+ Text {
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: "-"
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: pointSize -= 2
+ }
+ }
+
+ Text {
+ width: 150
+ height: 20
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ text: "Example Text: "
+ }
+
+ Rectangle {
+ height: 20
+ width: 300
+
+ clip: true
+
+ TextInput {
+ id: textInput
+
+ anchors.fill: parent
+ anchors.margins: 1
+
+ focus: true
+
+ text: "The quick brown fox jumps over the lazy dog"
+ }
+ }
+
+ Text {
+ width: 250
+ height: 20
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ text: "Show all QML font styles: "
+ }
+
+ Rectangle {
+ height: 20
+ width: 20
+
+ border.width: 1
+
+ Rectangle {
+ id: checker
+ anchors.centerIn: parent
+ width: 15
+ height: 15
+ color: "black"
+
+ visible: showAllWeights
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: showAllWeights = !showAllWeights
+ }
+ }
+ }
+ }
+
+ ListView {
+ id: list
+ anchors.top: header.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ model: styles
+
+ delegate: ListView {
+
+ id: familyDelegate
+
+ property var style: styles[index]
+
+ interactive: false
+
+ width: parent.width
+ height: childrenRect.height;
+
+ model: !showAllWeights ? style.weights : defaultWeights
+
+ delegate: Column {
+
+ width: root.width
+ height: childrenRect.height + 20
+
+ anchors.margins: 2
+
+ spacing: 2
+
+ property string name: showAllWeights ? modelData.name : familyDelegate.style.weights[index].name
+ property int weight: showAllWeights ? modelData.weight : familyDelegate.style.weights[index].weight
+
+ Text {
+ text: familyDelegate.style.family + ", " + name
+ }
+
+ Rectangle {
+ color: "black"
+ height: 1
+ width: root.width
+ }
+
+ Text {
+ id: exampleText
+ font.pointSize: root.pointSize
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "abcdefghijklmnopqrstuvwxyz"
+ }
+
+ Text {
+ font.pointSize: root.pointSize
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ }
+
+ Text {
+ font.pointSize: root.pointSize
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "0123456789.:;(*!?'/\\\")%&-+@~#<>{}[]"
+ }
+
+ Rectangle {
+ color: "black"
+ height: 1
+ width: root.width
+ }
+
+ Text {
+ font.pointSize: 6
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 8
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 10
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 18
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 24
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 30
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 36
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 42
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+ }
+ }
+ }
+
+ Item {
+ id: scrollBar
+
+ width: 15; height: list.height
+ anchors.top: header.bottom
+ anchors.right: parent.right
+ anchors.rightMargin: 3
+ anchors.bottom: parent.bottom
+
+ // The properties that define the scrollbar's state.
+ // position and pageSize are in the range 0.0 - 1.0. They are relative to the
+ // height of the page, i.e. a pageSize of 0.5 means that you can see 50%
+ // of the height of the view.
+ // orientation can be either Qt.Vertical or Qt.Horizontal
+ property Flickable flickable: list
+ property real position: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.yPosition : flickable.visibleArea.xPosition
+ property real pageSize: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.heightRatio : flickable.visibleArea.widthRatio
+ property int orientation : Qt.Vertical
+ property alias enableDrag: mouseArea.enabled
+
+ visible: pageSize != 1
+
+ // A light, semi-transparent background
+ Rectangle {
+ id: background
+ anchors.fill: parent
+ radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
+ color: "white"
+ opacity: 0.3
+ }
+
+ // Size the bar to the required size, depending upon the orientation.
+ Rectangle {
+ id: bar
+ x: scrollBar.orientation == Qt.Vertical ? 1 : (scrollBar.position * (scrollBar.width-2) + 1)
+ y: scrollBar.orientation == Qt.Vertical ? (scrollBar.position * (scrollBar.height-2) + 1) : 1
+ width: scrollBar.orientation == Qt.Vertical ? (parent.width-2) : (scrollBar.pageSize * (scrollBar.width-2))
+ height: scrollBar.orientation == Qt.Vertical ? (scrollBar.pageSize * (scrollBar.height-2)) : (parent.height-2)
+ radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
+ color: "black"
+ opacity: 0.7
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ property variant pressedPos
+ property bool drag: true
+ onPressed: {
+ pressedPos = mapToItem(bar, mouseX, mouseY)
+ if (pressedPos.x >= 0 && pressedPos.x <= bar.width &&
+ pressedPos.y >= 0 && pressedPos.y <= bar.height)
+ drag = true
+ }
+ onReleased: drag = false
+
+ onPositionChanged: {
+ if (drag) {
+ if (scrollBar.orientation == Qt.Vertical) {
+ var newPos =((mouseY - pressedPos.y -1 ) / (scrollBar.height-2)) * scrollBar.flickable.contentHeight
+ if (newPos < 0)
+ scrollBar.flickable.contentY = 0
+ else if (newPos > (scrollBar.flickable.contentHeight - scrollBar.flickable.height))
+ scrollBar.flickable.contentY = (scrollBar.flickable.contentHeight - scrollBar.flickable.height)
+ else
+ scrollBar.flickable.contentY = newPos
+ } else {
+ var newPos =((mouseX - pressedPos.x -1 ) / (scrollBar.width-2)) * scrollBar.flickable.contentWidth
+ if (newPos < 0)
+ scrollBar.flickable.contentX = 0
+ else if (newPos > (scrollBar.flickable.contentWidth - scrollBar.flickable.width))
+ scrollBar.flickable.contentX = (scrollBar.flickable.contentWidth - scrollBar.flickable.width)
+ else
+ scrollBar.flickable.contentX = newPos
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/livert/fontviewer_qt5_controls.qml b/src/livert/fontviewer_qt5_controls.qml
new file mode 100644
index 0000000..8bfa7f9
--- /dev/null
+++ b/src/livert/fontviewer_qt5_controls.qml
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+import QtQuick.Controls 1.0
+import QtQuick.Controls.Styles 1.0
+import QtQuick.Layouts 1.0
+
+Rectangle {
+ id: root
+ width: livert.screenWidth
+ height: livert.screenHeight
+
+ property alias testText: textInput.text
+ property alias pointSize: pointSizeSpinBox.value
+ property var defaultWeights:[
+ { name: "Light", weight: Font.Light },
+ { name: "Regular", weight: Font.Normal },
+ { name: "DemiBold", weight: Font.DemiBold },
+ { name: "Bold", weight: Font.Bold },
+ { name: "Black", weight: Font.Black },
+ ]
+
+ property alias showAllWeights: showAllWeightsCheckBox.checked
+
+ Rectangle {
+ id: header
+
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ height: 32
+
+ z: 2
+
+ color: "#E0E0E0"
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: 8
+ anchors.rightMargin: 8
+
+ Label {
+ width: 120
+ height: 20
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ text: "Font Size:"
+ }
+
+ SpinBox {
+ id: pointSizeSpinBox
+ suffix: "pt"
+ stepSize: 2
+ value: 12
+ minimumValue: 0
+ maximumValue: 50
+
+ Layout.preferredWidth: 60
+ }
+
+ Label {
+ width: 150
+ height: 20
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ text: "Example Text: "
+ }
+
+ TextField {
+ id: textInput
+
+ height: 20
+ Layout.preferredWidth: 600
+
+ readOnly: false
+
+ text: "The quick brown fox jumps over the lazy dog"
+
+ focus: true
+ }
+
+ Label {
+ width: 250
+ height: 20
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ text: "Show all QML font styles: "
+ }
+
+ CheckBox {
+ id: showAllWeightsCheckBox
+ height: 20
+ width: 20
+ }
+
+ Item {
+ width: 16; height: 16
+ Layout.fillWidth: true
+ }
+
+ }
+ }
+
+ ScrollView {
+ anchors.top: header.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ ListView {
+ id: list
+
+ model: styles
+
+ delegate: ListView {
+
+ id: familyDelegate
+
+ property var style: styles[index]
+
+ interactive: false
+
+ width: parent.width
+ height: childrenRect.height;
+
+ model: !showAllWeights ? style.weights : defaultWeights
+
+ delegate: Column {
+
+ width: root.width
+ height: childrenRect.height + 20
+
+ anchors.margins: 2
+
+ spacing: 2
+
+ property string name: showAllWeights ? modelData.name : familyDelegate.style.weights[index].name
+ property int weight: showAllWeights ? modelData.weight : familyDelegate.style.weights[index].weight
+
+ Text {
+ text: familyDelegate.style.family + ", " + name
+ }
+
+ Rectangle {
+ color: "black"
+ height: 1
+ width: root.width
+ }
+
+ Text {
+ id: exampleText
+ font.pointSize: root.pointSize
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "abcdefghijklmnopqrstuvwxyz"
+ }
+
+ Text {
+ font.pointSize: root.pointSize
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ }
+
+ Text {
+ font.pointSize: root.pointSize
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "0123456789.:;(*!?'/\\\")%&-+@~#<>{}[]"
+ }
+
+ Rectangle {
+ color: "black"
+ height: 1
+ width: root.width
+ }
+
+ Text {
+ font.pointSize: 6
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 8
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 10
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 18
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 24
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 30
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 36
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+
+ Text {
+ font.pointSize: 42
+ font.family: familyDelegate.style.family
+ font.weight: weight
+ text: "(" + font.pointSize + "pt)" + testText
+ }
+ }
+ }
+ }
+
+ }
+
+// Item {
+// id: scrollBar
+
+// width: 15; height: list.height
+// anchors.top: header.bottom
+// anchors.right: parent.right
+// anchors.rightMargin: 3
+// anchors.bottom: parent.bottom
+
+// // The properties that define the scrollbar's state.
+// // position and pageSize are in the range 0.0 - 1.0. They are relative to the
+// // height of the page, i.e. a pageSize of 0.5 means that you can see 50%
+// // of the height of the view.
+// // orientation can be either Qt.Vertical or Qt.Horizontal
+// property Flickable flickable: list
+// property real position: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.yPosition : flickable.visibleArea.xPosition
+// property real pageSize: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.heightRatio : flickable.visibleArea.widthRatio
+// property int orientation : Qt.Vertical
+// property alias enableDrag: mouseArea.enabled
+
+// visible: pageSize != 1
+
+// // A light, semi-transparent background
+// Rectangle {
+// id: background
+// anchors.fill: parent
+// radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
+// color: "white"
+// opacity: 0.3
+// }
+
+// // Size the bar to the required size, depending upon the orientation.
+// Rectangle {
+// id: bar
+// x: scrollBar.orientation == Qt.Vertical ? 1 : (scrollBar.position * (scrollBar.width-2) + 1)
+// y: scrollBar.orientation == Qt.Vertical ? (scrollBar.position * (scrollBar.height-2) + 1) : 1
+// width: scrollBar.orientation == Qt.Vertical ? (parent.width-2) : (scrollBar.pageSize * (scrollBar.width-2))
+// height: scrollBar.orientation == Qt.Vertical ? (scrollBar.pageSize * (scrollBar.height-2)) : (parent.height-2)
+// radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
+// color: "black"
+// opacity: 0.7
+// }
+
+// MouseArea {
+// id: mouseArea
+// anchors.fill: parent
+
+// property variant pressedPos
+// property bool drag: true
+// onPressed: {
+// pressedPos = mapToItem(bar, mouseX, mouseY)
+// if (pressedPos.x >= 0 && pressedPos.x <= bar.width &&
+// pressedPos.y >= 0 && pressedPos.y <= bar.height)
+// drag = true
+// }
+// onReleased: drag = false
+
+// onPositionChanged: {
+// if (drag) {
+// if (scrollBar.orientation == Qt.Vertical) {
+// var newPos =((mouseY - pressedPos.y -1 ) / (scrollBar.height-2)) * scrollBar.flickable.contentHeight
+// if (newPos < 0)
+// scrollBar.flickable.contentY = 0
+// else if (newPos > (scrollBar.flickable.contentHeight - scrollBar.flickable.height))
+// scrollBar.flickable.contentY = (scrollBar.flickable.contentHeight - scrollBar.flickable.height)
+// else
+// scrollBar.flickable.contentY = newPos
+// } else {
+// var newPos =((mouseX - pressedPos.x -1 ) / (scrollBar.width-2)) * scrollBar.flickable.contentWidth
+// if (newPos < 0)
+// scrollBar.flickable.contentX = 0
+// else if (newPos > (scrollBar.flickable.contentWidth - scrollBar.flickable.width))
+// scrollBar.flickable.contentX = (scrollBar.flickable.contentWidth - scrollBar.flickable.width)
+// else
+// scrollBar.flickable.contentX = newPos
+// }
+// }
+// }
+// }
+// }
+}
diff --git a/src/livert/imageviewer_qt5.qml b/src/livert/imageviewer_qt5.qml
new file mode 100644
index 0000000..321dec5
--- /dev/null
+++ b/src/livert/imageviewer_qt5.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 480; height: 272
+ Rectangle {
+ anchors.fill: parent
+ color: imageViewerBackgroundColor
+ }
+ Image {
+ id: image
+ anchors.centerIn: parent
+ source: imageViewerSource
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.margins: 4
+ color: '#ffffff'
+ text: image.width + "x" + image.height
+ }
+}
diff --git a/src/livert/imageviewer_qt5_controls.qml b/src/livert/imageviewer_qt5_controls.qml
new file mode 100644
index 0000000..321dec5
--- /dev/null
+++ b/src/livert/imageviewer_qt5_controls.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 480; height: 272
+ Rectangle {
+ anchors.fill: parent
+ color: imageViewerBackgroundColor
+ }
+ Image {
+ id: image
+ anchors.centerIn: parent
+ source: imageViewerSource
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.margins: 4
+ color: '#ffffff'
+ text: image.width + "x" + image.height
+ }
+}
diff --git a/src/livert/logo.png b/src/livert/logo.png
new file mode 100644
index 0000000..347df0e
--- /dev/null
+++ b/src/livert/logo.png
Binary files differ
diff --git a/src/livert/no.png b/src/livert/no.png
new file mode 100644
index 0000000..8410421
--- /dev/null
+++ b/src/livert/no.png
Binary files differ
diff --git a/src/liveruntime.cpp b/src/liveruntime.cpp
new file mode 100644
index 0000000..d909896
--- /dev/null
+++ b/src/liveruntime.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "liveruntime.h"
+
+// TODO: create a variant model for dynamic passing of key value pairs with notify
+// TODO: create support for background and overlay layer image files livert.background, livert.overlay
+
+/*!
+ * \class LiveRuntime
+ * \brief Collects properties to be used for an enhanced live runtime.
+ * \group qmllive
+ *
+ * This runtime is used in an live enhanced qml project to be able to access more
+ * advanced features. Currently it does nothing
+ */
+
+/*!
+ * Standard constructor using \a parent as parent
+ */
+LiveRuntime::LiveRuntime(QObject *parent) :
+ QObject(parent)
+{
+}
+
+void LiveRuntime::setScreenHeight(qreal arg)
+{
+ if (m_screenHeight != arg) {
+ m_screenHeight = arg;
+ emit screenHeightChanged(arg);
+ }
+}
+
+qreal LiveRuntime::screenWidth() const
+{
+ return m_screenWidth;
+}
+
+qreal LiveRuntime::screenHeight() const
+{
+ return m_screenHeight;
+}
+
+void LiveRuntime::setScreenWidth(qreal arg)
+{
+ if (m_screenWidth != arg) {
+ m_screenWidth = arg;
+ emit screenWidthChanged(arg);
+ }
+}
diff --git a/src/liveruntime.h b/src/liveruntime.h
new file mode 100644
index 0000000..5c2b5a8
--- /dev/null
+++ b/src/liveruntime.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtGui>
+
+class LiveRuntime : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal screenWidth READ screenWidth WRITE setScreenWidth NOTIFY screenWidthChanged)
+ Q_PROPERTY(qreal screenHeight READ screenHeight WRITE setScreenHeight NOTIFY screenHeightChanged)
+
+
+public:
+ explicit LiveRuntime(QObject *parent = 0);
+ qreal screenWidth() const;
+ qreal screenHeight() const;
+
+public slots:
+ void setScreenWidth(qreal arg);
+ void setScreenHeight(qreal arg);
+
+signals:
+ void screenWidthChanged(qreal arg);
+ void screenHeightChanged(qreal arg);
+
+private:
+ qreal m_screenWidth;
+ qreal m_screenHeight;
+};
+
diff --git a/src/logger.cpp b/src/logger.cpp
new file mode 100644
index 0000000..a12b762
--- /dev/null
+++ b/src/logger.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "logger.h"
+#include "stdio.h"
+
+Logger *Logger::s_instance = 0;
+bool Logger::s_ignoreMesssages = false;
+QMutex Logger::m_mutex;
+
+/*!
+ * \class Logger
+ * \brief Installs a qt messageHandler and receives all log messages
+ * \group qmllive
+ *
+ * The intention is to use this class if you want to display the log into widget
+ * or you want to preproccess the log messages itself before displaying it
+ *
+ * \sa RemoteLogger
+ */
+
+/*!
+ * Standard constructor using \a parent as parent
+ */
+Logger::Logger(QObject *parent) :
+ QObject(parent)
+{
+ if (s_instance) {
+ qFatal("Cannot create more than one Logger");
+ }
+ s_instance = this;
+
+ qInstallMessageHandler(messageHandler);
+}
+
+/*!
+ * Standard destructor
+ */
+Logger::~Logger()
+{
+ qInstallMessageHandler(0);
+}
+
+/*!
+ * When \a ignoreMessages set to true, the Logger ignores all incoming log messages
+ */
+void Logger::setIgnoreMessages(bool ignoreMessages)
+{
+ QMutexLocker l(&m_mutex);
+ s_ignoreMesssages = ignoreMessages;
+}
+
+void Logger::messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
+{
+ if (!s_instance) {
+ printf("No Logger instance for log message:\n %s\n", msg.toLatin1().constData());
+ abort();
+ }
+
+ {
+ QMutexLocker l(&m_mutex);
+ if (s_ignoreMesssages)
+ return;
+ }
+
+ emit s_instance->message(type, msg);
+
+ // and output to stdout
+ QByteArray localMsg = msg.toLocal8Bit();
+ switch (type) {
+ case QtDebugMsg:
+ fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ break;
+ case QtWarningMsg:
+ fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ break;
+ case QtCriticalMsg:
+ fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ break;
+ case QtFatalMsg:
+ fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ }
+}
+
+/*!
+ * \fn void Logger::message(int type, const QString &msg)
+ * Emitted for every incoming log message
+ * \a type describes the type of the log message (QtMsgType).
+ * \a msg is the debug message
+ * This signal will not be emitted when ignoreMessages set to true
+ * \sa setIgnoreMessages()
+ */
diff --git a/src/logger.h b/src/logger.h
new file mode 100644
index 0000000..a6f3ff8
--- /dev/null
+++ b/src/logger.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QMutex>
+#include <QUrl>
+
+class Logger : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Logger(QObject *parent = 0);
+ virtual ~Logger();
+
+public Q_SLOTS:
+ static void setIgnoreMessages(bool ignoreMessages);
+
+Q_SIGNALS:
+ void message(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
+
+private:
+ static void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
+
+ static Logger *s_instance;
+ static bool s_ignoreMesssages;
+
+ static QMutex m_mutex;
+};
diff --git a/src/logreceiver.cpp b/src/logreceiver.cpp
new file mode 100644
index 0000000..5ecd123
--- /dev/null
+++ b/src/logreceiver.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include <QUdpSocket>
+#include <QStringList>
+#include <QUrl>
+#include "logreceiver.h"
+
+/*!
+ * \class LogReceiver
+ * \brief Connects to a port and waits for log messages sent via udp
+ * \group qmllive
+ *
+ * \sa Logger, RemoteLogger
+ */
+
+/*!
+ * Standard constructor using \a parent as parent
+ */
+LogReceiver::LogReceiver(QObject *parent) :
+ QObject(parent),
+ m_socket(new QUdpSocket(this))
+{
+ setPort(45454);
+ connect(m_socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
+}
+
+/*!
+ * Sets the \a port on which we wait for incoming logs
+ */
+void LogReceiver::setPort(int port)
+{
+ m_port = port;
+}
+
+void LogReceiver::setAddress(const QString &address)
+{
+ m_address = QHostAddress(address);
+}
+
+void LogReceiver::connectToServer()
+{
+ m_socket->disconnectFromHost();
+ m_socket->bind(m_address, m_port, QUdpSocket::ShareAddress);
+}
+
+/*!
+ * The port on which we wait for incoming logs
+ */
+int LogReceiver::port() const
+{
+ return m_port;
+}
+
+QString LogReceiver::address() const
+{
+ return m_address.toString();
+}
+
+void LogReceiver::processPendingDatagrams()
+{
+ while (m_socket->hasPendingDatagrams()) {
+ QByteArray datagram;
+ datagram.resize(m_socket->pendingDatagramSize());
+ m_socket->readDatagram(datagram.data(), datagram.size());
+
+ QStringList data = QString::fromUtf8(datagram).split("%%%");
+ if (data.count() != 5) {
+ qWarning("Invalid Log package received");
+ return;
+ }
+
+ emit message(data.at(0).toInt(), data.at(1), QUrl(data.at(2)) ,data.at(3).toInt(), data.at(4).toInt());
+ }
+}
diff --git a/src/logreceiver.h b/src/logreceiver.h
new file mode 100644
index 0000000..4f2a8fc
--- /dev/null
+++ b/src/logreceiver.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QObject>
+#include <QUrl>
+#include <QHostAddress>
+
+class QUdpSocket;
+class LogReceiver : public QObject
+{
+ Q_OBJECT
+public:
+ explicit LogReceiver(QObject *parent = 0);
+
+ int port() const;
+ QString address() const;
+
+public Q_SLOTS:
+ void setPort(int port);
+ void setAddress(const QString& address);
+ void connectToServer();
+
+Q_SIGNALS:
+ void message(int type, const QString &msg, const QUrl &url, int line, int column);
+
+private Q_SLOTS:
+ void processPendingDatagrams();
+
+private:
+ QUdpSocket* m_socket;
+ QHostAddress m_address;
+ int m_port;
+};
diff --git a/src/mainpage.dox b/src/mainpage.dox
new file mode 100644
index 0000000..447b0a9
--- /dev/null
+++ b/src/mainpage.dox
@@ -0,0 +1,16 @@
+/************************************************************************************************
+ * Copyright (c) 2012 Pelagicore AG. All rights reserved.
+ *
+ * This software, including documentation, is protected by copyright controlled by Pelagicore AG.
+ * All rights reserved. Copying, including reproducing, storing, adapting or translating, any or
+ * all of this material requires prior written consent of Pelagicore AG Corporation. This material
+ * also contains confidential information which may not be disclosed to others without the prior
+ * written consent of Pelagicore AG.
+ ************************************************************************************************/
+
+/*!
+\mainpage QmlLive Documentation
+
+Welcome to QmlLive.
+*/
+
diff --git a/src/previewGenerator/main.cpp b/src/previewGenerator/main.cpp
new file mode 100644
index 0000000..ff3282d
--- /dev/null
+++ b/src/previewGenerator/main.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QQuickView>
+#include <QQmlEngine>
+#include <QElapsedTimer>
+#include <QDir>
+#include <QBuffer>
+#include <QLocalServer>
+#include <QLocalSocket>
+#include <QDebug>
+
+#include <stdio.h>
+
+void handlePreview(QLocalSocket *socket);
+
+class PreviewServer : public QObject
+{
+ Q_OBJECT
+public:
+ PreviewServer()
+ : m_server(new QLocalServer())
+ {
+ connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
+ }
+
+ bool listen()
+ {
+ return m_server->listen("QmlLivePreviewGenerator");
+ }
+
+ QString serverName() const
+ {
+ return m_server->serverName();
+ }
+
+protected slots:
+ void onNewConnection()
+ {
+ while (m_server->hasPendingConnections()) {
+ QLocalSocket *socket = m_server->nextPendingConnection();
+
+ handlePreview(socket);
+
+ delete socket;
+ }
+ }
+private:
+ QLocalServer *m_server;
+};
+
+
+FILE *dbgf = 0;
+
+int main (int argc, char** argv)
+{
+ QApplication app(argc, argv);
+
+ if (app.arguments().count() != 2 ||
+ (app.arguments().at(1) != "QmlLiveBench") )
+ qFatal("This application is managed by QmlLive and is not supposed to be manually started");
+
+ PreviewServer preview;
+ if (!preview.listen()) {
+ qFatal("Failed to listen to local socket \"QmlLivePreviewGenerator\"");
+ }
+
+ printf("ready#%s\n", preview.serverName().toUtf8().toHex().constData());
+ fflush(stdout);
+
+ //dbgf = fopen("C:\\Qt\\pg.log", "w");
+ return app.exec();
+}
+
+void handlePreview(QLocalSocket *socket)
+{
+ if (dbgf) { fprintf(dbgf, "PG: waiting on input\n"); fflush(dbgf); }
+
+ socket->waitForReadyRead();
+
+ QDataStream ds (socket);
+ QSize expectedSize;
+ QString path;
+
+ ds >> expectedSize >> path;
+
+ if (dbgf) { fprintf(dbgf, "PG: received [%dx%d] %s\n", expectedSize.width(), expectedSize.height(), qPrintable(path)); fflush(dbgf); }
+
+ //QML Import paths and plugin paths will be set by environment variables
+ QQuickView *view = new QQuickView();
+ view->setFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint |
+ Qt::CustomizeWindowHint | Qt::WindowDoesNotAcceptFocus); // | Qt::WindowStaysOnBottomHint);
+ view->setPosition(-9999999, -9999999);
+ view->setSource(QUrl::fromLocalFile(path));
+
+ if (view->errors().isEmpty()) {
+ view->show();
+
+ //Wait until the Window is exposed;
+ int timeout = 3000;
+ QElapsedTimer timer;
+ timer.start();
+ while (!view->isExposed()) {
+ int remaining = timeout - int(timer.elapsed());
+ if (remaining <= 0)
+ break;
+ QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
+ //Garbage collection (Delivers all DeferredDeleteEvents which are in the pipe)
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+
+ if (view->width() <= 0 || view->height() <= 0) {
+ view->setWidth(500);
+ view->setHeight(500);
+ }
+
+ if (view->rootObject()) {
+ QImage img = view->grabWindow();
+ if (!img.isNull()) {
+ img = img.scaled(expectedSize, Qt::KeepAspectRatio);
+ img.save(socket, "PNG");
+
+ if (dbgf) { fprintf(dbgf, "PG: sending image\n"); fflush(dbgf); }
+ }
+ }
+ }
+ delete view;
+
+ socket->write("\nEND");
+ socket->flush();
+
+ if (dbgf) { fprintf(dbgf, "PG: sent END and flushed\n"); fflush(dbgf); }
+}
+
+
+#include "main.moc"
diff --git a/src/previewGenerator/previewGenerator.pro b/src/previewGenerator/previewGenerator.pro
new file mode 100644
index 0000000..7afd257
--- /dev/null
+++ b/src/previewGenerator/previewGenerator.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+TARGET = previewGenerator
+DESTDIR = ../../bin
+
+osx: {
+ CONFIG -= app_bundle
+ DESTDIR = ../../bin/qmllivebench.app/Contents/MacOS/
+}
+
+QT = gui core quick widgets
+
+SOURCES += \
+ main.cpp
diff --git a/src/qmlhelper.cpp b/src/qmlhelper.cpp
new file mode 100644
index 0000000..b47dbd3
--- /dev/null
+++ b/src/qmlhelper.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "qmlhelper.h"
+
+
+/*!
+ * \class QmlHelper
+ * \brief Provides a set of helper functions to setup your qml viewer
+ * \group qmllive
+ */
+
+/*!
+ * \brief Standard constructor using \a parent as parent
+ */
+QmlHelper::QmlHelper(QObject *parent) :
+ QObject(parent)
+{
+}
+
+/*!
+ * Loads dummy data from a "dummydata" folder in the workspace folder
+ * \a view defines the View where you want to export the dummy data to
+ * The "dummydata" will be searched in the "dummydata" sub directory of \a workspace
+ */
+void QmlHelper::loadDummyData(QQuickView *view, const QString &workspace)
+{
+ Q_ASSERT(view);
+ QDir dir(workspace + "/dummydata", "*.qml");
+ foreach (QString entry, dir.entryList()) {
+
+ QQmlComponent comp(view->engine(), dir.filePath(entry));
+ QObject* obj = comp.create();
+
+ if (comp.isError()) {
+ foreach (const QQmlError error, comp.errors()) {
+ qWarning() << error;
+ }
+ }
+ if (obj) {
+ qWarning() << "loaded dummy data: " << dir.filePath(entry);
+ entry.chop(4);
+ view->rootContext()->setContextProperty(entry, obj);
+ obj->setParent(view);
+ }
+ }
+}
+
+/*!
+ * \fn void QmlHelper::addImportPath(QQuickView *view, const QString &path)
+ * Adds an import path \a path to your qml viewer \a view
+ */
+void QmlHelper::addImportPath(QQuickView *view, const QString &path)
+{
+ Q_ASSERT(view);
+ view->engine()->addImportPath(path);
+}
+
+
+
+
diff --git a/src/qmlhelper.h b/src/qmlhelper.h
new file mode 100644
index 0000000..7c5cb05
--- /dev/null
+++ b/src/qmlhelper.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtQml>
+#include <QtQuick>
+
+class QmlHelper : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QmlHelper(QObject *parent = 0);
+
+ static void loadDummyData(QQuickView* view, const QString& workspace);
+ static void addImportPath(QQuickView* view, const QString& path);
+
+Q_SIGNALS:
+
+public Q_SLOTS:
+
+};
diff --git a/src/remotelogger.cpp b/src/remotelogger.cpp
new file mode 100644
index 0000000..f2f2899
--- /dev/null
+++ b/src/remotelogger.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include <QUdpSocket>
+#include "remotelogger.h"
+
+/*!
+ * \class RemoteLogger
+ * \brief Installs a qt messageHandler and sends the logs over udp
+ * \group qmllive
+ *
+ * \sa Logger, LogReceiver
+ */
+
+/*!
+ * Standard constructor using \a parent as parent
+ */
+RemoteLogger::RemoteLogger(QObject *parent) :
+ Logger(parent) ,
+ m_socket(new QUdpSocket(this)) ,
+ m_port(45454)
+{
+ connect(this, SIGNAL(message(int,QString)), this, SLOT(broadcast(int,QString)));
+}
+
+/*!
+ * Sets the \a address where the log messages will be sent to
+ * \sa setPort()
+ */
+void RemoteLogger::setHostAddress(const QHostAddress &address)
+{
+ m_host = address;
+}
+
+/*!
+ * Sets the \a port where the log messages will be sent to
+ * \sa setHostAddress()
+ */
+void RemoteLogger::setPort(int port)
+{
+ m_port = port;
+}
+
+void RemoteLogger::broadcast(int type, const QString &msg, const QUrl &url, int line, int column)
+{
+ QByteArray datagram;
+ QStringList data;
+ data << QString::number(type) << msg << url.toString() << QString::number(line) << QString::number(column);
+
+ datagram = data.join("%%%").toUtf8();
+ m_socket->writeDatagram(datagram.data(), datagram.size(),
+ m_host, m_port);
+}
+
+void RemoteLogger::appendToLog(const QList<QQmlError> &errors)
+{
+ foreach (const QQmlError &err, errors) {
+ if (!err.isValid())
+ continue;
+
+ QtMsgType type = QtDebugMsg;
+
+ if (err.description().contains(QString::fromLatin1("error"), Qt::CaseInsensitive) ||
+ err.description().contains(QString::fromLatin1("is not installed"), Qt::CaseInsensitive) ||
+ err.description().contains(QString::fromLatin1("is not a type"), Qt::CaseInsensitive))
+ type = QtCriticalMsg;
+ else if (err.description().contains(QString::fromLatin1("warning"), Qt::CaseInsensitive))
+ type = QtWarningMsg;
+
+ broadcast(type, err.description(), err.url(), err.line(), err.column());
+ }
+}
diff --git a/src/remotelogger.h b/src/remotelogger.h
new file mode 100644
index 0000000..f41e106
--- /dev/null
+++ b/src/remotelogger.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include "logger.h"
+#include <QHostAddress>
+#include <QtQuick>
+
+class QUdpSocket;
+class RemoteLogger : public Logger
+{
+ Q_OBJECT
+public:
+ explicit RemoteLogger(QObject *parent = 0);
+
+public Q_SLOTS:
+ void setHostAddress(const QHostAddress &address);
+ void setPort(int port);
+ void appendToLog(const QList<QQmlError> &errors);
+
+private Q_SLOTS:
+ void broadcast(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
+
+private:
+ QUdpSocket* m_socket;
+ int m_port;
+ QHostAddress m_host;
+};
diff --git a/src/remotepublisher.cpp b/src/remotepublisher.cpp
new file mode 100644
index 0000000..5ee343b
--- /dev/null
+++ b/src/remotepublisher.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "remotepublisher.h"
+#include "ipc/ipcclient.h"
+#include "livehubengine.h"
+
+#ifdef QMLLIVE_DEBUG
+#define DEBUG qDebug()
+#else
+#define DEBUG if (0) qDebug()
+#endif
+/*!
+ * \class RemotePublisher
+ * \brief Publishes hub changes to a remote node
+ * \group qmllive
+ *
+ * To see the progress which commands were really sent successfully to to the server
+ * you have to connect the signals from the LiveHubEngine yourself and monitor the QUuids you
+ * got and wait for sendingError() or sentSuccessfully() signals
+ */
+
+/*!
+ * Standard Constructor using \a parent as parent
+ */
+RemotePublisher::RemotePublisher(QObject *parent)
+ : QObject(parent)
+ , m_ipc(new IpcClient(this))
+ , m_hub(0)
+{
+ connect(m_ipc, SIGNAL(sentSuccessfully(QUuid)), this, SIGNAL(sentSuccessfully(QUuid)));
+ connect(m_ipc, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)),
+ this, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)));
+ connect(m_ipc, SIGNAL(connectionError(QAbstractSocket::SocketError)),
+ this, SIGNAL(connectionError(QAbstractSocket::SocketError)));
+ connect(m_ipc, SIGNAL(connected()), this, SIGNAL(connected()));
+ connect(m_ipc, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+
+ connect(m_ipc, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
+
+ connect(m_ipc, SIGNAL(sentSuccessfully(QUuid)), this, SLOT(onSentSuccessfully(QUuid)));
+ connect(m_ipc, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)),
+ this, SLOT(onSendingError(QUuid,QAbstractSocket::SocketError)));
+}
+
+QAbstractSocket::SocketState RemotePublisher::state() const
+{
+ return m_ipc->state();
+}
+
+/*!
+ * Register the \a hub to be used with this publisher
+ */
+void RemotePublisher::registerHub(LiveHubEngine *hub)
+{
+ if (m_hub) {
+ disconnect(m_hub);
+ }
+ m_hub = hub;
+ connect(hub, SIGNAL(activateDocument(QString)), this, SLOT(activateDocument(QString)));
+ connect(hub, SIGNAL(fileChanged(QString)), this, SLOT(sendDocument(QString)));
+}
+
+/*!
+ * Sets the current workspace to \a path. Documents location will be adjusted based on
+ * this workspace path.
+ */
+void RemotePublisher::setWorkspace(const QString &path)
+{
+ m_workspace = QDir(path);
+}
+
+/*!
+ * Set Ipc destination to use \a hostName and \a port
+ * \sa IpcClient::connectToServer()
+ */
+void RemotePublisher::connectToServer(const QString &hostName, int port)
+{
+ m_ipc->connectToServer(hostName, port);
+}
+
+QString RemotePublisher::errorToString(QAbstractSocket::SocketError error)
+{
+ return m_ipc->errorToString(error);
+}
+
+void RemotePublisher::disconnectFromServer()
+{
+ m_ipc->disconnectFromServer();
+}
+
+/*!
+ * Send "activateDocument(QString)" to ipc-server on activate document.
+ * \a document defines the Document which should be activated
+ */
+QUuid RemotePublisher::activateDocument(const QString &document)
+{
+ DEBUG << "RemotePublisher::activateDocument" << document;
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << document;
+ return m_ipc->send("activateDocument(QString)", bytes);
+}
+
+/*!
+ * Send "sendDocument(QString,QByteArray)" to ipc-server on send document.
+ * It sends \a document with content \a data
+ */
+QUuid RemotePublisher::sendDocument(const QString& document)
+{
+ DEBUG << "RemotePublisher::sendDocument" << document;
+ return sendWholeDocument(document);
+}
+
+QUuid RemotePublisher::checkPin(const QString &pin)
+{
+ DEBUG << "RemotePublisher::checkPin" << pin;
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << pin;
+ return m_ipc->send("checkPin(QString)", bytes);
+}
+
+QUuid RemotePublisher::setXOffset(int offset)
+{
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << offset;
+ return m_ipc->send("setXOffset(int)", bytes);
+}
+
+QUuid RemotePublisher::setYOffset(int offset)
+{
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << offset;
+ return m_ipc->send("setYOffset(int)", bytes);
+}
+
+QUuid RemotePublisher::setRotation(int rotation)
+{
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << rotation;
+ return m_ipc->send("setRotation(int)", bytes);
+}
+
+QUuid RemotePublisher::sendWholeDocument(const QString& document)
+{
+ DEBUG << "RemotePublisher::sendWholeDocument" << document;
+ QFile file(document);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "ERROR: can't open file: " << document;
+ return QUuid();
+ }
+ QByteArray data = file.readAll();
+
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << m_workspace.relativeFilePath(document);
+ out << data;
+ return m_ipc->send("sendDocument(QString,QByteArray)", bytes);
+}
+
+void RemotePublisher::onSentSuccessfully(const QUuid &uuid)
+{
+ QString path = m_packageHash.value(uuid);
+ m_packageHash.remove(uuid);
+
+ QList<QUuid> keys = m_packageHash.keys(path);
+ if (keys.count() == 1) {
+ m_packageHash.remove(keys.at(0));
+ emit sentSuccessfully(keys.at(0));
+ }
+}
+
+void RemotePublisher::onSendingError(const QUuid &uuid, QAbstractSocket::SocketError socketError)
+{
+ QString path = m_packageHash.value(uuid);
+ m_packageHash.remove(uuid);
+
+ QList<QUuid> keys = m_packageHash.keys(path);
+ if (keys.count() == 1) {
+ m_packageHash.remove(keys.at(0));
+ emit sendingError(keys.at(0), socketError);
+ }
+}
+
+
+void RemotePublisher::handleCall(const QString &method, const QByteArray &content)
+{
+ DEBUG << "RemotePublisher::handleIpcCall: " << method << content;
+
+ if (method == "needsPinAuthentication()") {
+ qDebug() << "needsPinAuthentication";
+ emit needsPinAuthentication();
+ } else if (method == "pinOK(bool)") {
+ qDebug() << "pinOk" << content.toInt();
+ emit pinOk(content.toInt());
+ } else if (method == "qmlLog(QtMsgType, QString, QUrl, int, int)") {
+ int msgType;
+ QString description;
+ QUrl url;
+ int line = -1;
+ int column = -1;
+
+ QDataStream in(content);
+ in >> msgType;
+ in >> description;
+ in >> url;
+ in >> line;
+ in >> column;
+
+ emit remoteLog(msgType, description, url, line, column);
+ }
+}
diff --git a/src/remotepublisher.h b/src/remotepublisher.h
new file mode 100644
index 0000000..2132787
--- /dev/null
+++ b/src/remotepublisher.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QAbstractSocket>
+
+class LiveHubEngine;
+class IpcClient;
+
+class RemotePublisher : public QObject
+{
+ Q_OBJECT
+public:
+ explicit RemotePublisher(QObject *parent = 0);
+ void connectToServer(const QString& hostName, int port);
+ QString errorToString(QAbstractSocket::SocketError error);
+ QAbstractSocket::SocketState state() const;
+
+ void registerHub(LiveHubEngine *hub);
+Q_SIGNALS:
+ void connected();
+ void disconnected();
+ void sentSuccessfully(const QUuid& uuid);
+ void sendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError);
+ void connectionError(QAbstractSocket::SocketError error);
+ void needsPinAuthentication();
+ void pinOk(bool ok);
+ void remoteLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
+
+public Q_SLOTS:
+ void setWorkspace(const QString &path);
+ void disconnectFromServer();
+ QUuid activateDocument(const QString& document);
+ QUuid sendDocument(const QString& document);
+ QUuid checkPin(const QString& pin);
+ QUuid setXOffset(int offset);
+ QUuid setYOffset(int offset);
+ QUuid setRotation(int rotation);
+
+private Q_SLOTS:
+ void handleCall(const QString &method, const QByteArray &content);
+ QUuid sendWholeDocument(const QString &document);
+
+ void onSentSuccessfully(const QUuid& uuid);
+ void onSendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError);
+
+private:
+ IpcClient *m_ipc;
+ LiveHubEngine *m_hub;
+ QDir m_workspace;
+
+ QHash<QUuid, QString> m_packageHash;
+};
diff --git a/src/remotereceiver.cpp b/src/remotereceiver.cpp
new file mode 100644
index 0000000..7bacb46
--- /dev/null
+++ b/src/remotereceiver.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "remotereceiver.h"
+#include "ipc/ipcserver.h"
+#include "ipc/ipcclient.h"
+#include "livenodeengine.h"
+
+#include <QTcpSocket>
+
+#ifdef QMLLIVE_DEBUG
+#define DEBUG qDebug()
+#else
+#define DEBUG if (0) qDebug()
+#endif
+
+RemoteReceiver::RemoteReceiver(QObject *parent)
+ : QObject(parent)
+ , m_server(new IpcServer(this))
+ , m_node(0)
+ , m_connectionAcknowledged(false)
+ , m_socket(0)
+ , m_client(0)
+{
+ connect(m_server, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
+ connect(m_server, SIGNAL(clientConnected(QTcpSocket*)), this, SLOT(onClientConnected(QTcpSocket*)));
+ connect(m_server, SIGNAL(clientConnected(QHostAddress)), this, SIGNAL(clientConnected(QHostAddress)));
+ connect(m_server, SIGNAL(clientDisconnected(QHostAddress)), this, SIGNAL(clientDisconnected(QHostAddress)));
+}
+
+void RemoteReceiver::listen(int port)
+{
+ m_server->listen(port);
+}
+
+/*!
+ * Sets the current workspace to \a path. Documents location will be adjusted based on
+ * this workspace path.
+ */
+void RemoteReceiver::setWorkspace(const QString &path)
+{
+ m_workspace = QDir(path);
+}
+
+QString RemoteReceiver::workspace() const
+{
+ return m_workspace.absolutePath();
+}
+
+void RemoteReceiver::setPin(const QString &pin)
+{
+ m_pin = pin;
+}
+
+QString RemoteReceiver::pin() const
+{
+ return m_pin;
+}
+
+void RemoteReceiver::setMaxConnections(int max)
+{
+ m_server->setMaxConnections(max);
+}
+
+/*!
+ * Sets whether the workspace is writeable to \a on. Otherwise incoming write document requests will be ignored.
+ */
+void RemoteReceiver::setWorkspaceWriteable(bool on)
+{
+ m_workspaceWriteable = on;
+}
+
+
+void RemoteReceiver::handleCall(const QString &method, const QByteArray &content)
+{
+ DEBUG << "RemoteReceiver::handleIpcCall: " << method;
+
+ if (method == "checkPin(QString)") {
+ QString pin;
+ QDataStream in(content);
+ in >> pin;
+ if (m_pin == pin && m_client) {
+ m_connectionAcknowledged = true;
+ emit pinOk(true);
+ m_client->send("pinOK(bool)", QByteArray::number(1));
+ } else if (m_client) {
+ emit pinOk(false);
+ m_client->send("pinOK(bool)", QByteArray::number(0));
+ }
+ }
+
+ if (!m_connectionAcknowledged) {
+ qWarning() << "Connecting without Pin Authentication is not allowed";
+ return;
+ }
+
+ if (method == "setXOffset(int)") {
+ int offset;
+ QDataStream in(content);
+ in >> offset;
+ emit xOffsetChanged(offset);
+ } else if (method == "setYOffset(int)") {
+ int offset;
+ QDataStream in(content);
+ in >> offset;
+ emit yOffsetChanged(offset);
+ } else if (method == "setRotation(int)") {
+ int rotation;
+ QDataStream in(content);
+ in >> rotation;
+ emit rotationChanged(rotation);
+ } else if (method == "sendDocument(QString,QByteArray)") {
+ QString document;
+ QByteArray data;
+ QDataStream in(content);
+ in >> document;
+ in >> data;
+ writeDocument(document, data);
+ } else if (method == "activateDocument(QString)") {
+ QString document;
+ QDataStream in(content);
+ in >> document;
+ qDebug() << "\tactivate document: " << document;
+ emit activateDocument(document);
+ } else if (method == "ping()") {
+ if (m_client)
+ m_client->send("pong()", QByteArray());
+ }
+}
+
+
+void RemoteReceiver::registerNode(LiveNodeEngine *node)
+{
+ if (m_node) { disconnect(m_node); }
+ m_node = node;
+ connect(this, SIGNAL(activateDocument(QString)), m_node, SLOT(setActiveDocument(QString)));
+}
+
+void RemoteReceiver::writeDocument(const QString &document, const QByteArray &content)
+{
+ if (!m_workspaceWriteable) { return; }
+ QString filePath = m_workspace.absoluteFilePath(document);
+ QString dirPath = QFileInfo(filePath).absoluteDir().absolutePath();
+ m_workspace.mkpath(dirPath);
+ QFile file(filePath);
+ if (!file.open(QIODevice::WriteOnly)) {
+ qWarning() << "Unable to save file: " << file.errorString();
+ return;
+ }
+ file.write(content);
+ file.close();
+
+ if (m_node)
+ m_node->delayReload();
+}
+
+void RemoteReceiver::onClientConnected(QTcpSocket *socket)
+{
+ if (m_client)
+ delete m_client;
+
+ m_client = new IpcClient(socket);
+
+ m_socket = socket;
+
+ if (!m_pin.isEmpty()) {
+ m_client->send("needsPinAuthentication()", QByteArray());
+ m_connectionAcknowledged = false;
+ } else {
+ m_connectionAcknowledged = true;
+ }
+}
+
+void RemoteReceiver::appendToLog(const QList<QQmlError> &errors)
+{
+ foreach (const QQmlError &err, errors) {
+ if (!err.isValid())
+ continue;
+
+ QtMsgType type = QtDebugMsg;
+
+ if (err.description().contains(QString::fromLatin1("error"), Qt::CaseInsensitive) ||
+ err.description().contains(QString::fromLatin1("is not installed"), Qt::CaseInsensitive) ||
+ err.description().contains(QString::fromLatin1("is not a type"), Qt::CaseInsensitive))
+ type = QtCriticalMsg;
+ else if (err.description().contains(QString::fromLatin1("warning"), Qt::CaseInsensitive))
+ type = QtWarningMsg;
+
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << type;
+ out << err.description();
+ out << err.url();
+ out << err.line();
+ out << err.column();
+
+ m_client->send("qmlLog(QtMsgType, QString, QUrl, int, int)", bytes);
+ }
+}
diff --git a/src/remotereceiver.h b/src/remotereceiver.h
new file mode 100644
index 0000000..7e7b16e
--- /dev/null
+++ b/src/remotereceiver.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QHostAddress>
+
+#include <QQmlError>
+
+class QTcpSocket;
+class LiveNodeEngine;
+class IpcServer;
+class IpcClient;
+
+class RemoteReceiver : public QObject
+{
+ Q_OBJECT
+public:
+ explicit RemoteReceiver(QObject *parent = 0);
+ void listen(int port);
+ void registerNode(LiveNodeEngine *node);
+ void setWorkspaceWriteable(bool on);
+ void setWorkspace(const QString &path);
+ QString workspace() const;
+ void setPin(const QString& pin);
+ QString pin() const;
+
+ void setMaxConnections(int max);
+Q_SIGNALS:
+ void activateDocument(const QString& document);
+ void reload();
+ void clientConnected(const QHostAddress& address);
+ void clientDisconnected(const QHostAddress& address);
+ void pinOk(bool ok);
+ void xOffsetChanged(int offset);
+ void yOffsetChanged(int offset);
+ void rotationChanged(int rotation);
+
+private Q_SLOTS:
+ void handleCall(const QString& method, const QByteArray& content);
+ void writeDocument(const QString& document, const QByteArray& content);
+
+ void appendToLog(const QList<QQmlError> &errors);
+
+ void onClientConnected(QTcpSocket *socket);
+private:
+ IpcServer *m_server;
+ LiveNodeEngine *m_node;
+
+ QDir m_workspace;
+ bool m_workspaceWriteable;
+
+ QString m_pin;
+ bool m_connectionAcknowledged;
+
+ QTcpSocket* m_socket;
+ IpcClient* m_client;
+};
+
diff --git a/src/runtime/main.cpp b/src/runtime/main.cpp
new file mode 100644
index 0000000..2c2a4f1
--- /dev/null
+++ b/src/runtime/main.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QCryptographicHash>
+#include <QtQuick>
+#include <QtWidgets>
+
+#include "livenodeengine.h"
+#include "remotereceiver.h"
+#include "logger.h"
+#include "qmlhelper.h"
+
+
+struct Options
+{
+ Options()
+ : ipcPort(10234)
+ , allowUpdates(true)
+ , fullscreen(false)
+ , transparent(false)
+ , frameless(false)
+ , stayontop(false)
+ {}
+ int ipcPort;
+ bool allowUpdates;
+ QString activeDocument;
+ QString workspace;
+ QString pluginPath;
+ QStringList importPaths;
+ bool fullscreen;
+ bool transparent;
+ bool frameless;
+ bool stayontop;
+};
+
+static Options options;
+
+static void usage()
+{
+ qWarning("Usage qmlliveruntime [options] <workspace>");
+ qWarning(" ");
+ qWarning(" options:");
+ qWarning(" -ipcport <port> ....................the port the ipc shall listen on");
+ qWarning(" -no-file-updates ...................do not write to files on changes");
+ qWarning(" -pluginpath ........................path to qmllive plugins");
+ qWarning(" -importpath ........................path to the qml import path");
+ qWarning(" -fullscreen ........................shows in fullscreen mode");
+ qWarning(" -transparent .......................Make the window transparent");
+ qWarning(" -frameless .........................run with no window frame");
+ qWarning(" -stayontop .........................keep viewer window on top");
+ qWarning(" ");
+ exit(1);
+}
+
+static void parseArguments(const QStringList& arguments)
+{
+ for (int i = 1; i < arguments.count(); ++i) {
+ bool lastArg = (i == arguments.count() - 1);
+ QString arg = arguments.at(i);
+ if (arg == QLatin1String("-ipcport")) {
+ if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage();
+ options.ipcPort = arguments.at(i).toInt();
+ } else if (arg == QLatin1String("-pluginpath")) {
+ if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage();
+ options.pluginPath = arguments.at(i);
+ } else if (arg == QLatin1String("-importpath")) {
+ if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage();
+ options.importPaths.append(QDir(arguments.at(i)).absolutePath());
+ continue;
+ } else if (arg == QLatin1String("-no-file-updates")) {
+ options.allowUpdates = false;
+ } else if (arg == QLatin1String("-fullscreen")) {
+ options.fullscreen = true;
+ } else if (arg == QLatin1String("-transparent")) {
+ options.transparent = true;
+ } else if (arg == QLatin1String("-frameless")) {
+ options.frameless = true;
+ } else if (arg == QLatin1String("-stayontop")) {
+ options.stayontop = true;
+ } else if (!arg.startsWith(QLatin1Char('-'))) {
+ options.workspace = arg;
+ } else if (true || arg == QLatin1String("-help")) {
+ usage();
+ }
+ }
+}
+
+class RuntimeLiveNodeEngine : public LiveNodeEngine {
+
+ virtual QQuickView* initView()
+ {
+ QQuickView* view = new QQuickView();
+ if (options.transparent) {
+ QSurfaceFormat surfaceFormat;
+ surfaceFormat.setAlphaBufferSize(8);
+ view->setFormat(surfaceFormat);
+ view->setClearBeforeRendering(true);
+ view->setColor(QColor(Qt::transparent));
+ }
+
+ if (options.stayontop) {
+ view->setFlags(view->flags() | Qt::X11BypassWindowManagerHint);
+ view->setFlags(view->flags() | Qt::WindowStaysOnTopHint);
+ }
+
+ if (options.frameless)
+ view->setFlags(view->flags() | Qt::FramelessWindowHint);
+
+ if (options.fullscreen)
+ view->setWindowState(Qt::WindowFullScreen);
+
+ return view;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ app.setApplicationName("QmlLiveRuntime");
+ app.setOrganizationDomain("pelagicore.com");
+ app.setOrganizationName("Pelagicore");
+ parseArguments(app.arguments());
+
+ QQuickView view;
+
+ QStringList defaultImports = view.engine()->importPathList();
+
+ RuntimeLiveNodeEngine engine;
+ engine.setUpdateMode(LiveNodeEngine::RecreateView);
+ engine.setWorkspace(options.workspace);
+ engine.setPluginPath(options.pluginPath);
+ engine.setImportPaths(options.importPaths + defaultImports);
+ engine.loadDocument(QUrl("qrc:/qml/qmlsplash/splash-qt5.qml"));
+ RemoteReceiver receiver;
+ receiver.listen(options.ipcPort);
+ receiver.setWorkspace(options.workspace);
+ receiver.setWorkspaceWriteable(options.allowUpdates);
+ receiver.registerNode(&engine);
+
+ engine.connect(&engine, SIGNAL(logErrors(QList<QQmlError>)), &receiver, SLOT(appendToLog(QList<QQmlError>)));
+
+ receiver.connect(&receiver, SIGNAL(xOffsetChanged(int)), &engine, SLOT(setXOffset(int)));
+ receiver.connect(&receiver, SIGNAL(yOffsetChanged(int)), &engine, SLOT(setYOffset(int)));
+ receiver.connect(&receiver, SIGNAL(rotationChanged(int)), &engine, SLOT(setRotation(int)));
+
+ QMap<QString, QString> extraSyslog;
+ extraSyslog.insert("LOCATION", QString("qmllive://${HOST}:%1").arg(options.ipcPort));
+
+ int ret = app.exec();
+
+ return ret;
+}
diff --git a/src/runtime/qml.qrc b/src/runtime/qml.qrc
new file mode 100644
index 0000000..f47865a
--- /dev/null
+++ b/src/runtime/qml.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/qml">
+ <file>qmlsplash/pelagicore-symbol-white-rgb.png</file>
+ <file>qmlsplash/splash-qt5.qml</file>
+ </qresource>
+</RCC>
diff --git a/src/runtime/qmlsplash/pelagicore-symbol-white-rgb.png b/src/runtime/qmlsplash/pelagicore-symbol-white-rgb.png
new file mode 100644
index 0000000..09e7dce
--- /dev/null
+++ b/src/runtime/qmlsplash/pelagicore-symbol-white-rgb.png
Binary files differ
diff --git a/src/runtime/qmlsplash/splash-qt4.qml b/src/runtime/qmlsplash/splash-qt4.qml
new file mode 100644
index 0000000..799928e
--- /dev/null
+++ b/src/runtime/qmlsplash/splash-qt4.qml
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 1.1
+
+Rectangle {
+ id: root
+ width: 1024
+ height: 768
+ color: "#FF6600"
+
+ Image {
+ id: logo
+ source: "pelagicore-symbol-white-rgb.png"
+ x: 50
+ anchors.top: parent.top
+ anchors.topMargin: 100
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 250
+
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Text {
+ id: mantraText
+
+ text: "Open Source Infotainment\n Enabling Great Design"
+
+ font.pixelSize: 60
+ color: "white"
+ lineHeight: 1.2
+
+ y: logo.y
+ anchors.left: logo.right
+ anchors.leftMargin: 25
+
+ }
+
+ Text {
+ id: qmllivetext
+ text: "QmlLive"
+
+ font.pixelSize: 70
+ color: "white"
+
+ x: mantraText.x
+ anchors.top: mantraText.bottom
+ anchors.margins: 200
+ }
+ Text {
+ id: pleaseConnectText
+ text: "Please connect with QmlLiveRemote"
+
+ font.pixelSize: 40
+ color: "white"
+ SequentialAnimation {
+ running: true
+ loops: Animation.Infinite
+ ColorAnimation { target: pleaseConnectText; property: "color"; from: "white"; to: root.color; duration: 2000;}
+ ColorAnimation { target: pleaseConnectText; property: "color"; from: root.color; to: "white"; duration: 2000;}
+ }
+
+ x: mantraText.x
+ anchors.top: qmllivetext.bottom
+ anchors.margins: 20
+ }
+}
diff --git a/src/runtime/qmlsplash/splash-qt5.qml b/src/runtime/qmlsplash/splash-qt5.qml
new file mode 100644
index 0000000..6743343
--- /dev/null
+++ b/src/runtime/qmlsplash/splash-qt5.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 1024
+ height: 768
+ color: "#FF6600"
+
+ Image {
+ id: logo
+ source: "pelagicore-symbol-white-rgb.png"
+ x: 50
+ anchors.top: parent.top
+ anchors.topMargin: 100
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 250
+
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Text {
+ id: mantraText
+
+ text: "Open Source Infotainment\n Enabling Great Design"
+
+ font.pixelSize: 60
+ color: "white"
+ lineHeight: 1.2
+
+ y: logo.y
+ anchors.left: logo.right
+ anchors.leftMargin: 25
+
+ }
+
+ Text {
+ id: qmllivetext
+ text: "QmlLive"
+
+ font.pixelSize: 70
+ color: "white"
+
+ x: mantraText.x
+ anchors.top: mantraText.bottom
+ anchors.margins: 200
+ }
+ Text {
+ id: pleaseConnectText
+ text: "Please connect with QmlLiveRemote"
+
+ font.pixelSize: 40
+ color: "white"
+ SequentialAnimation {
+ running: true
+ loops: Animation.Infinite
+ ColorAnimation { target: pleaseConnectText; property: "color"; from: "white"; to: root.color; duration: 2000;}
+ ColorAnimation { target: pleaseConnectText; property: "color"; from: root.color; to: "white"; duration: 2000;}
+ }
+
+
+ x: mantraText.x
+ anchors.top: qmllivetext.bottom
+ anchors.margins: 20
+ }
+}
diff --git a/src/runtime/runtime.pro b/src/runtime/runtime.pro
new file mode 100644
index 0000000..73dd6d7
--- /dev/null
+++ b/src/runtime/runtime.pro
@@ -0,0 +1,19 @@
+TARGET = qmlliveruntime
+DESTDIR = ../../bin
+
+QT *= widgets quick
+osx: CONFIG -= app_bundle
+
+SOURCES += main.cpp
+
+win32: RC_FILE = ../../icons/appicon.rc
+
+include(../widgets/widgets.pri)
+include(../src.pri)
+
+RESOURCES += \
+ qml.qrc
+
+
+
+
diff --git a/src/src.pri b/src/src.pri
new file mode 100644
index 0000000..326f705
--- /dev/null
+++ b/src/src.pri
@@ -0,0 +1,54 @@
+!greaterThan(QT_MAJOR_VERSION, 4):error("You need at least Qt5 to build this application")
+
+QT *= quick quick-private qml-private network
+
+INCLUDEPATH += $${PWD}
+DEFINES += NO_LIBRSYNC
+
+SOURCES += \
+ $$PWD/watcher.cpp \
+ $$PWD/livehubengine.cpp \
+ $$PWD/livenodeengine.cpp \
+ $$PWD/qmlhelper.cpp \
+ $$PWD/liveruntime.cpp \
+ $$PWD/remotepublisher.cpp \
+ $$PWD/remotereceiver.cpp \
+ $$PWD/imageadapter.cpp \
+ $$PWD/contentpluginfactory.cpp \
+ $$PWD/logger.cpp \
+ $$PWD/remotelogger.cpp \
+ $$PWD/logreceiver.cpp \
+ $$PWD/fontadapter.cpp
+
+HEADERS += \
+ $$PWD/watcher.h \
+ $$PWD/livehubengine.h \
+ $$PWD/livenodeengine.h \
+ $$PWD/qmlhelper.h \
+ $$PWD/liveruntime.h \
+ $$PWD/remotepublisher.h \
+ $$PWD/remotereceiver.h \
+ $$PWD/contentadapterinterface.h \
+ $$PWD/imageadapter.h \
+ $$PWD/contentpluginfactory.h \
+ $$PWD/logger.h \
+ $$PWD/remotelogger.h \
+ $$PWD/logreceiver.h \
+ $$PWD/fontadapter.h
+
+OTHER_FILES += \
+ $$PWD/livert/error_qt5.qml \
+ $$PWD/livert/error_qt5_controls.qml \
+ $$PWD/livert/imageviewer_qt5.qml \
+ $$PWD/livert/imageviewer_qt5_controls.qml \
+ $$PWD/livert/folderview_qt5.qml \
+ $$PWD/livert/folderview_qt5_controls.qml \
+ $$PWD/livert/fontviewer_qt5.qml \
+ $$PWD/livert/fontviewer_qt5_controls.qml
+
+RESOURCES += \
+ $$PWD/livert.qrc
+
+include(ipc/ipc.pri)
+
+
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..96e3681
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,9 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS += \
+ bench \
+ previewGenerator \
+ runtime \
+
+include(src.pri)
diff --git a/src/usage.dox b/src/usage.dox
new file mode 100644
index 0000000..431e189
--- /dev/null
+++ b/src/usage.dox
@@ -0,0 +1,122 @@
+/*!
+\page usage Usage
+
+The QmlLive system ws designed from the ground up to support your needs. It is structured in a modular fashion to be able to support various usage requirements.
+
+In the early phase of a project you normally want to use the `QmlLiveBench`, which has everything included in a typical desktop application. Later in the project you may want to test your UI code on a device. For this we have designed the `QmlLiveRuntime` in combination with the `QmlLiveRemote`. This combi pack offers you a default qml renderer to be run on the device and a small remote application on the desktop to control it. For the C++ developers we also offer the ability to just integrate the QmlLive system into your own custom runtime using our *QmlLiveNodeEngine* class with a few lines of code and then use the *QmlLiveRemote* to instrument it.
+
+Workbench
+---------
+
+The standard workbench is the all inclusve qml live tool. It allows you to select a workspace to watch over and provides a default qml runtime for the active selected qml document.
+
+![Workbench](images/workbench.png)
+
+You launch it by just executing the ``qmllivebench`` executable
+
+ $(QMLIVEPROJECT)/bin/qmllivebench[.exe]
+
+
+Creator Integration
+-------------------
+
+You can integrate the QmlLiveBench into creator as an external tool. For this you need to open the Settings/Options dialog from QtCreator and open the `Environment` group. There you will find the ``External Tools`` tab.
+
+Under exectuble enter the path of your QmlLiveBench executable.
+
+![Creator](images/creator_tool.png)
+
+Now QmlLiveBench is availabe under the menu entry Tool->External->QmlLiveBench. To be able to easier launch QmlLiveBench you can also assign a shortcut to the tool.
+
+![Creator](images/creator_shortcut.png)
+
+Now when you press "Alt-F8" QmlLiveBench will be launched with the current project root folder open as workspace.
+
+![Creator](images/creator_result.png)
+
+
+
+Default Runtime
+---------------
+
+The default runtime is meant to be used with the QmlLiveRemote tool. It provides a default qml viewer and listens on a given port for ipc calls from the remote. As such it's ideal to start developing on a target device, when no extra c++ code is required.
+
+![Runtime](images/runtime.png)
+
+Calling the runtime
+
+ $(QMLIVEPROJECT)/bin/qmlliveruntime[.exe]
+
+Usage of the runtime
+
+ Usage qmlliveruntime [options] <workspace>
+
+ options:
+ -ipcport <port>
+ -no-writes
+
+
+Remote
+------
+
+The remote controls a runtime running on the same PC or on another device. On changes on the workspace is send the changes over to the runtime and reloads the current active document.
+
+![Remote](images/remote.png)
+
+QmlLiveRemote Execution
+
+ $(QMLIVEPROJECT)/bin/qmlliveremote[.exe]
+
+Note: Is it possible to disable the publishing of source changes
+
+
+QmlLiveRemote Usage
+
+ Usage qmlliveremote [options] <workspace>
+
+ options:
+ -activate <qml-document> ....... active document
+ -runtime <ip-address:port> ..... define remote runtime
+ -publishFirst .................. publish initially the workspace
+ -publishChanges ................ allow publishing workspace changes to remote
+
+
+Custom Runtime
+--------------
+
+You can create your own custom runtime with the QmlLive features. This allows you to use your qml view setup with your additional c++ code together with the QmlLive system.
+
+For this you need to add `$(QMLLIVEPROJECT)/src/src.pri` to your project folder and use the `LiveNodeEngine` class to be able to receive workspace changes and active document updates. By default the IPC will listen on the port 10234.
+
+Here is a short example of a minimal custom runtime:
+
+\code{.cpp}
+#include <QtGui>
+#include <QtDeclarative>
+
+// use live node header
+#include "livenodeengine.h"
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ QDeclarativeView view;
+
+ LiveNodeEngine node;
+ // let qml live instrument your view
+ node.setView(&view);
+ // where file updates should be stored relative to
+ node.setWorkspace(".");
+ // for local usage use the LocalPublisher
+ RemoteReceiver receiver;
+ receiver.registerNode(node);
+ // listen to ipc call from remote
+ receiver.listen(10234);
+
+ view.setResizeMode(QDeclarativeView::SizeViewToRootObject);
+ view.show();
+ return app.exec();
+}
+\endcode
+
+*/
diff --git a/src/usage.qdoc b/src/usage.qdoc
new file mode 100644
index 0000000..6cf8e38
--- /dev/null
+++ b/src/usage.qdoc
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+/*!
+\page usage.html
+
+The QmlLive system was designed from the ground up to support your needs. It is structured in a modular fashion to be able to support various usage requirements.
+
+In the early phase of a project you normally want to use the \bold{QmlLiveBench}, which has everything included in a typical desktop application. Later in the project you may want to test your UI code on a device. For this we have designed the \bold{QmlLiveRuntime} in combination with the \bold{QmlLiveRemote}. This combi pack offers you a default qml renderer to be run on the device and a small remote application on the desktop to control it. For the C++ developers we also offer the ability to just integrate the QmlLive system into your own custom runtime using our LiveNodeEngine class with a few lines of code and then use the \bold{QmlLiveRemote} to instrument it.
+
+\section1 Workbench
+
+The standard workbench is the all inclusve qml live tool. It allows you to select a workspace to watch over and provides a default qml runtime for the active selected qml document.
+
+\image workbench.png Workbench
+
+You launch it by just executing the \tt{qmllivebench} executable
+\code
+{$(QMLIVEPROJECT)/bin/qmllivebench[.exe]
+\endcode
+
+
+\section2 Creator Integration
+
+You can integrate the QmlLiveBench into creator as an external tool. For this you need to open the Settings/Options dialog from QtCreator and open the \bold{Environment} group. There you will find the \tt{External Tools} tab.
+
+Under exectuble enter the path of your QmlLiveBench executable.
+
+\image creator_tool.png Creator
+
+Now QmlLiveBench is availabe under the menu entry Tool->External->QmlLiveBench. To be able to easier launch QmlLiveBench you can also assign a shortcut to the tool.
+
+\image creator_shortcut.png Creator
+
+Now when you press "Alt-F8" QmlLiveBench will be launched with the current project root folder open as workspace.
+
+\image creator_result.png Creator
+
+
+
+\section2 Default Runtime
+
+The default runtime is meant to be used with the QmlLiveRemote tool. It provides a default qml viewer and listens on a given port for ipc calls from the remote. As such it's ideal to start developing on a target device, when no extra c++ code is required.
+
+\image runtime.png Runtime
+
+Calling the runtime
+
+\code
+$(QMLIVEPROJECT)/bin/qmlliveruntime[.exe]
+\endcode
+
+Usage of the runtime
+
+\code
+ Usage qmlliveruntime [options] <workspace>
+
+ options:
+ -ipcport <port>
+ -no-writes
+\endcode
+
+
+\section1 Remote
+
+The remote controls a runtime running on the same PC or on another device. On changes on the workspace is send the changes over to the runtime and reloads the current active document.
+
+\image remote.png Remote
+
+QmlLiveRemote Execution
+
+\code
+ $(QMLIVEPROJECT)/bin/qmlliveremote[.exe]
+\endcode
+
+Note: Is it possible to disable the publishing of source changes
+
+
+QmlLiveRemote Usage
+
+\code
+ Usage qmlliveremote [options] <workspace>
+
+ options:
+ -activate <qml-document> ....... active document
+ -runtime <ip-address:port> ..... define remote runtime
+ -publishFirst .................. publish initially the workspace
+ -publishChanges ................ allow publishing workspace changes to remote
+\endcode
+
+
+\section2 Custom Runtime
+
+You can create your own custom runtime with the QmlLive features. This allows you to use your qml view setup with your additional c++ code together with the QmlLive system.
+
+For this you need to add \tt{$(QMLLIVEPROJECT)/src/src.pri} to your project folder and use the \bold{LiveNodeEngine} class to be able to receive workspace changes and active document updates. By default the IPC will listen on the port 10234.
+
+Here is a short example of a minimal custom runtime:
+
+\code{.cpp}
+#include <QtGui>
+#include <QtDeclarative>
+
+// use live node header
+#include "livenodeengine.h"
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ QDeclarativeView view;
+
+ LiveNodeEngine node;
+ // let qml live instrument your view
+ node.setView(&view);
+ // where file updates should be stored relative to
+ node.setWorkspace(".");
+ // for local usage use the LocalPublisher
+ RemoteReceiver receiver;
+ receiver.registerNode(node);
+ // listen to ipc call from remote
+ receiver.listen(10234);
+
+ view.setResizeMode(QDeclarativeView::SizeViewToRootObject);
+ view.show();
+ return app.exec();
+}
+\endcode
+
+*/
diff --git a/src/watcher.cpp b/src/watcher.cpp
new file mode 100644
index 0000000..7b827d3
--- /dev/null
+++ b/src/watcher.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "watcher.h"
+
+
+/*!
+ \class Watcher
+ \internal
+ \brief A class which watches Directories and notifies you about changes
+
+ A class which watches Directories and notifies you about every change in this Directory or in it's SubDirectories
+ */
+
+/*!
+ Default Constructor using parent as parent
+ */
+Watcher::Watcher(QObject *parent)
+ : QObject(parent)
+ , m_watcher(new QFileSystemWatcher(this))
+ , m_waitTimer(new QTimer(this))
+{
+ connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(recordChange(QString)));
+ connect(m_waitTimer, SIGNAL(timeout()), this, SLOT(notifyChanges()));
+ m_waitTimer->setInterval(100);
+ m_waitTimer->setSingleShot(true);
+}
+
+/*!
+ Set the watching Directory to path.
+
+ Every change within this Directory and it's sub Directories will be reported by
+ the directoriesChanged() signal
+ */
+void Watcher::setDirectory(const QString &path)
+{
+ m_rootDir = QDir(path);
+ if (!m_watcher->directories().isEmpty()) {
+ m_watcher->removePaths(m_watcher->directories());
+ }
+ if (!m_watcher->files().isEmpty()) {
+ m_watcher->removePaths(m_watcher->files());
+ }
+ addDirectoriesRecursively(m_rootDir.absolutePath());
+}
+
+/*!
+ Returns the Directory watched for changes
+ */
+QString Watcher::directory() const
+{
+ return m_rootDir.absolutePath();
+}
+
+/*!
+ Add path and all it's SubDirectory to the internal used QFileSystemWatcher
+ */
+void Watcher::addDirectoriesRecursively(const QString &path)
+{
+// qDebug() << "scan: " << path;
+ if (!m_watcher->directories().contains(path)) {
+ m_watcher->addPath(path);
+ }
+ QDirIterator iter(path, QDir::Dirs|QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
+ while (iter.hasNext()) {
+ QDir entry(iter.next());
+ if (!m_watcher->directories().contains(entry.absolutePath())) {
+ m_watcher->addPath(entry.absolutePath());
+
+ //If we couldn't add it we reached the filesystem limit
+ if (!m_watcher->directories().contains(entry.absolutePath())) {
+ qWarning() << "Watcher limit reached. Please reduce the number of files you are watching !!!";
+ return;
+ }
+ }
+ }
+
+}
+
+/*!
+ Returns the given path relative to the watcher's Directory
+ /sa setDirectory, directory()
+ */
+QString Watcher::relativeFilePath(const QString &path)
+{
+ return m_rootDir.relativeFilePath(path);
+}
+
+void Watcher::recordChange(const QString &path)
+{
+// qDebug() << "Watcher::recordChange: " << path;
+ m_changes.append(path);
+ m_waitTimer->start();
+}
+
+/*!
+ Filters all the Directory changes.
+
+ It tries to minimize the List of changes to the minimal common path.
+ Example:
+
+ Changes:
+
+ /home/qmllive/test/images
+ /home/qmllive/test
+ /home/user
+
+ Will be filtered to:
+
+ /home/qmllive/test
+ /home/user
+
+ */
+void Watcher::notifyChanges()
+{
+// qDebug() << "changes" << m_changes;
+ // sort to be able to avoid re-scan of recorded sub-folders
+ QStringList final;
+ QString top;
+ // sort changes so top-most dirs stay first
+
+ //TODO: wrong assumption, since "aaa<a-umlaut>/" > "aaa/very/deep/hierarchy"
+ // we need to sort according to the number of sections when split by QDir::Separator
+
+ m_changes.sort();
+ foreach (const QString& entry, m_changes) {
+ if (!QDir(entry).exists()) {
+ // dir was removed
+ if (m_watcher->directories().contains(entry)) {
+ m_watcher->removePath(entry);
+ }
+ } else {
+ if (top.isNull() || !entry.startsWith(top)) {
+ top = entry;
+ final.append(entry);
+ }
+ }
+ }
+ m_changes.clear();
+ // need to rescan these top-most dirs
+ foreach (const QString& entry, final) {
+ addDirectoriesRecursively(entry);
+ }
+ emit directoriesChanged(final);
+// qDebug() << "watcher directories: " << m_watcher->directories();
+}
+
diff --git a/src/watcher.h b/src/watcher.h
new file mode 100644
index 0000000..ad83a6d
--- /dev/null
+++ b/src/watcher.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+
+class Watcher : public QObject
+{
+ Q_OBJECT
+public:
+ explicit Watcher(QObject *parent = 0);
+ void setDirectory(const QString& path);
+ QString directory() const;
+ QString relativeFilePath(const QString& path);
+private Q_SLOTS:
+ void recordChange(const QString &path);
+ void notifyChanges();
+Q_SIGNALS:
+ void directoriesChanged(const QStringList& changes);
+
+private:
+ void addDirectoriesRecursively(const QString& path);
+ QFileSystemWatcher *m_watcher;
+ QDir m_rootDir;
+ QTimer *m_waitTimer;
+ QStringList m_changes;
+};
+
diff --git a/src/widgets/filesystemmodel.cpp b/src/widgets/filesystemmodel.cpp
new file mode 100644
index 0000000..4eec2c7
--- /dev/null
+++ b/src/widgets/filesystemmodel.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "filesystemmodel.h"
+
+FileSystemModel::FileSystemModel(QObject *parent) :
+ QFileSystemModel(parent) ,
+ m_dirSelectable(true)
+{
+}
+
+void FileSystemModel::setAllowedTypesFilter(QStringList allowed)
+{
+ m_allowedTypes = allowed;
+}
+
+QStringList FileSystemModel::allowedTypesFilter() const
+{
+ return m_allowedTypes;
+}
+
+void FileSystemModel::setDirectoriesSelectable(bool enabled)
+{
+ m_dirSelectable = enabled;
+}
+
+bool FileSystemModel::directoriesSelectable() const
+{
+ return m_dirSelectable;
+}
+
+Qt::ItemFlags FileSystemModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags f = QFileSystemModel::flags(index);
+
+ if (isDir(index)) {
+ if (m_dirSelectable)
+ return f;
+ else
+ return f & ~Qt::ItemIsSelectable;
+ }
+
+ QString path = filePath(index);
+
+ foreach (QString type, m_allowedTypes) {
+ if (path.contains(QRegExp(type, Qt::CaseInsensitive, QRegExp::Wildcard)))
+ return f;
+ }
+
+ return f & ~Qt::ItemIsSelectable;
+}
+
+
diff --git a/src/widgets/filesystemmodel.h b/src/widgets/filesystemmodel.h
new file mode 100644
index 0000000..8ff17e9
--- /dev/null
+++ b/src/widgets/filesystemmodel.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QFileSystemModel>
+
+class FileSystemModel : public QFileSystemModel
+{
+ Q_OBJECT
+public:
+ explicit FileSystemModel(QObject *parent = 0);
+
+ void setAllowedTypesFilter(QStringList allowed);
+ QStringList allowedTypesFilter() const;
+
+ void setDirectoriesSelectable(bool enabled);
+ bool directoriesSelectable() const;
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+private:
+ QStringList m_allowedTypes;
+ bool m_dirSelectable;
+};
+
diff --git a/src/widgets/logview.cpp b/src/widgets/logview.cpp
new file mode 100644
index 0000000..3ad4630
--- /dev/null
+++ b/src/widgets/logview.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "logview.h"
+
+LogView::LogView(bool createLogger, QWidget *parent)
+ : QWidget(parent)
+ , m_log(new QPlainTextEdit(this))
+ , m_logger(0)
+{
+ m_log->setReadOnly(true);
+ m_log->setMaximumBlockCount(1000);
+ m_log->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->addWidget(m_log);
+ setLayout(layout);
+
+ if (createLogger) {
+ m_logger = new Logger(this);
+ connect(m_logger, SIGNAL(message(int,QString)), this, SLOT(appendToLog(int,QString)));
+ }
+}
+
+void LogView::setIgnoreMessages(bool ignoreMessages)
+{
+ if (m_logger)
+ m_logger->setIgnoreMessages(ignoreMessages);
+}
+
+void LogView::appendToLog(int type, const QString &msg, const QUrl &url, int line, int column)
+{
+ QMutexLocker l(&m_mutex);
+
+ qreal baseValue = m_log->palette().color(QPalette::Base).valueF();
+ QColor color = m_log->palette().color(QPalette::Text);
+
+ switch (type) {
+ case QtWarningMsg: // yellow
+ color = baseValue < 0.5f ? QColor(255, 255, 128) : QColor(140, 140, 0);
+ break;
+ case QtCriticalMsg: // red
+ color = baseValue < 0.5f ? QColor(255, 64, 64) : QColor(165, 0, 0);
+ break;
+ case QtFatalMsg: // red
+ color = baseValue < 0.5f ? QColor(255, 64, 64) : QColor(165, 0, 0);
+ break;
+ case InternalInfo: // green
+ color = baseValue < 0.5f ? QColor(96, 255, 96) : QColor(128, 0, 0);
+ break;
+ case InternalError: // purple
+ color = baseValue < 0.5f ? QColor(196, 128, 196) : QColor(96, 0, 96);
+ break;
+ default:
+ break;
+ }
+
+ QString s;
+ if (url.isValid()) {
+ s.append(url.isLocalFile() ? url.toLocalFile() : url.toString());
+ s.append(QLatin1Char(':'));
+ }
+ if (line > 0) {
+ s.append(QString::number(line));
+ s.append(QLatin1Char(':'));
+ }
+ Q_UNUSED(column);
+ if (!s.isEmpty())
+ s.append(QLatin1Char(' '));
+
+ s.append(QString::fromLatin1("<b><font color=\"%2\">%1</font></b>")
+ .arg(msg)
+ .arg(color.name()));
+
+ m_log->appendHtml(s);
+}
+
+void LogView::appendToLog(const QList<QQmlError> &errors)
+{
+ foreach (const QQmlError &err, errors) {
+ if (!err.isValid())
+ continue;
+
+ QtMsgType type = QtDebugMsg;
+
+ if (err.description().contains(QString::fromLatin1("error"), Qt::CaseInsensitive) ||
+ err.description().contains(QString::fromLatin1("is not installed"), Qt::CaseInsensitive) ||
+ err.description().contains(QString::fromLatin1("is not a type"), Qt::CaseInsensitive))
+ type = QtCriticalMsg;
+ else if (err.description().contains(QString::fromLatin1("warning"), Qt::CaseInsensitive))
+ type = QtWarningMsg;
+
+ appendToLog(type, err.description(), err.url(), err.line(), err.column());
+ }
+}
+
+void LogView::clear()
+{
+ QMutexLocker l(&m_mutex);
+ m_log->clear();
+}
+
diff --git a/src/widgets/logview.h b/src/widgets/logview.h
new file mode 100644
index 0000000..a5e1d49
--- /dev/null
+++ b/src/widgets/logview.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+#include <QtGui>
+#include <QtQuick>
+#include <QtWidgets>
+
+#include "logger.h"
+
+
+class LogView : public QWidget
+{
+ Q_OBJECT
+public:
+ enum {
+ InternalInfo = QtDebugMsg - 1,
+ InternalError = QtDebugMsg - 2
+ };
+
+ explicit LogView(bool createLogger = true, QWidget *parent = 0);
+public slots:
+ void setIgnoreMessages(bool ignoreMessages);
+ void clear();
+ void appendToLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
+ void appendToLog(const QList<QQmlError> &errors);
+
+private:
+ QPlainTextEdit *m_log;
+
+ QMutex m_mutex;
+ Logger* m_logger;
+};
diff --git a/src/widgets/widgets.pri b/src/widgets/widgets.pri
new file mode 100644
index 0000000..2089397
--- /dev/null
+++ b/src/widgets/widgets.pri
@@ -0,0 +1,15 @@
+QT += network
+
+SOURCES += \
+ $$PWD/logview.cpp \
+ $$PWD/workspaceview.cpp \
+ $$PWD/filesystemmodel.cpp \
+ $$PWD/workspacedelegate.cpp \
+ $$PWD/windowwidget.cpp
+
+HEADERS += \
+ $$PWD/logview.h \
+ $$PWD/workspaceview.h \
+ $$PWD/filesystemmodel.h \
+ $$PWD/workspacedelegate.h \
+ $$PWD/windowwidget.h
diff --git a/src/widgets/windowwidget.cpp b/src/widgets/windowwidget.cpp
new file mode 100644
index 0000000..76bbedc
--- /dev/null
+++ b/src/widgets/windowwidget.cpp
@@ -0,0 +1,279 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "windowwidget.h"
+#include <QQuickView>
+#include <QQuickItem>
+#include <QGuiApplication>
+#include <QDebug>
+#include <QScrollBar>
+#include <QResizeEvent>
+
+WindowWidget::WindowWidget(QWidget *parent) :
+ QAbstractScrollArea(parent), m_hostedWindow(0), m_resizing(false), m_centering(false)
+{
+ setFrameShape(QFrame::NoFrame);
+}
+
+void WindowWidget::setHostedWindow(QQuickView *hostedWindow)
+{
+ QQuickView* oldView = 0;
+ if (m_hostedWindow) {
+ m_hostedWindow->removeEventFilter(this);
+ oldView = m_hostedWindow;
+ }
+
+ m_hostedWindow = hostedWindow;
+ if (m_hostedWindow) {
+ m_hostedWindow->installEventFilter(this);
+
+ // force creation of the TL window in order to get its handle
+ if (!testAttribute(Qt::WA_WState_Created))
+ create(0, true, true);
+
+ if (!windowHandle())
+ qWarning("Could not get a valid windowhandle for our widget based window");
+
+ m_hostedWindow->setFlags(Qt::Tool | Qt::FramelessWindowHint);
+ m_hostedWindow->setParent(windowHandle());
+ m_hostedWindow->setVisible(isVisible());
+
+ // this needs to be done in order to prevent showing uninitialized frames
+ m_hostedWindow->setGeometry(QRect(viewport()->mapToGlobal(QPoint()), viewport()->size()));
+
+ viewport()->setBackgroundRole(backgroundRole());
+ viewport()->setPalette(palette());
+ viewport()->setBackgroundRole(QPalette::Background);
+ setFocusPolicy(Qt::StrongFocus);
+ m_hostedWindow->show();
+ }
+
+ if (oldView) {
+ oldView->hide();
+ oldView->setParent(0);
+ }
+}
+
+QQuickView *WindowWidget::hostedWindow() const
+{
+ return m_hostedWindow;
+}
+
+void WindowWidget::setVisible(bool visible)
+{
+ QAbstractScrollArea::setVisible(visible);
+ if (m_hostedWindow)
+ m_hostedWindow->setVisible(visible);
+}
+
+void WindowWidget::setCenteringEnabled(bool enabled)
+{
+ m_centering = enabled;
+ updateScrollBars();
+}
+
+QSize WindowWidget::sizeHint() const
+{
+ QSize s = qmlSize();
+
+ return s + QSize(frameWidth() * 2, frameWidth() * 2);
+}
+
+void WindowWidget::forceInitialResize()
+{
+ if (m_hostedWindow && m_hostedWindow->resizeMode() == QQuickView::SizeRootObjectToView) {
+ m_hostedWindow->resize(size());
+ }
+ updateGeometry();
+ updateScrollBars();
+ emit widthChanged(width());
+ emit heightChanged(height());
+
+}
+
+bool WindowWidget::event(QEvent *e)
+{
+ bool handled = false;
+
+ if (m_hostedWindow) {
+ switch (e->type()) {
+ case QEvent::Wheel: {
+ QWheelEvent *oe = static_cast<QWheelEvent *>(e);
+ if (!viewport()->geometry().contains(oe->pos()))
+ break;
+
+ QWheelEvent ne(m_hostedWindow->mapFromGlobal(oe->globalPos()),
+ oe->globalPos(),
+ oe->pixelDelta(),
+ oe->angleDelta(),
+ oe->delta(),
+ oe->orientation(),
+ oe->buttons(),
+ oe->modifiers());
+
+ qGuiApp->sendEvent(m_hostedWindow, &ne);
+ handled = true;
+ break;
+ }
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease: {
+ qGuiApp->sendEvent(m_hostedWindow, e);
+ handled = true;
+ break;
+ }
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove: {
+ QMouseEvent *oe = static_cast<QMouseEvent *>(e);
+
+ if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) {
+ if (!viewport()->geometry().contains(oe->pos()))
+ break;
+ }
+
+ QMouseEvent ne(oe->type(),
+ m_hostedWindow->mapFromGlobal(oe->globalPos()),
+ m_hostedWindow->mapFromGlobal(oe->globalPos()),
+ oe->globalPos(),
+ oe->button(),
+ oe->buttons(),
+ oe->modifiers());
+
+ qGuiApp->sendEvent(m_hostedWindow, &ne);
+ handled = true;
+ break;
+ }
+ case QEvent::Resize: {
+ QResizeEvent* re = static_cast<QResizeEvent*>(e);
+ if (m_hostedWindow && m_hostedWindow->resizeMode() == QQuickView::SizeRootObjectToView) {
+ m_hostedWindow->resize(re->size());
+ }
+ updateGeometry();
+ updateScrollBars();
+ if (re->oldSize().width() != re->size().width())
+ emit widthChanged(re->size().width());
+ if (re->oldSize().height() != re->size().height())
+ emit heightChanged(re->size().height());
+ break;
+ }
+ case QEvent::Hide:
+ m_hostedWindow->close();
+ break;
+ default:
+ break;
+ }
+ }
+ return handled ? true : QAbstractScrollArea::event(e);
+}
+
+bool WindowWidget::eventFilter(QObject *o, QEvent *e)
+{
+ if (o && o == m_hostedWindow) {
+ switch (e->type()) {
+ case QEvent::Resize:
+ updateScrollBars();
+ break;
+ default:
+ break;
+ }
+ }
+ return QAbstractScrollArea::eventFilter(o, e);
+}
+
+void WindowWidget::scrollContentsBy(int dx, int dy)
+{
+ Q_UNUSED(dx)
+ Q_UNUSED(dy)
+
+ updateWindowPosition();
+}
+
+#include <QStyle>
+
+void WindowWidget::updateScrollBars()
+{
+ if (!m_hostedWindow)
+ return;
+
+ if (window() && !m_resizing) {
+ m_resizing = true;
+
+ QSize vpSize = viewport()->size();
+ QSize vpMaxSize = maximumViewportSize();
+ QSize wSize = qmlSize();
+
+ // does the window fit without scrollbars?
+ if (vpMaxSize.expandedTo(wSize) == vpMaxSize)
+ vpSize = vpMaxSize;
+
+ // fix scrollbars
+ horizontalScrollBar()->setRange(0, (wSize - vpSize).width());
+ horizontalScrollBar()->setPageStep(vpSize.width());
+ verticalScrollBar()->setRange(0, (wSize - vpSize).height());
+ verticalScrollBar()->setPageStep(vpSize.height());
+
+ //qWarning() << "wSize:" << wSize << "vpSize:" << vpSize << "vpRect" << viewport()->rect();
+ //qWarning() << "Hrange:" << (wSize - vpSize).width() << "Hstep:" << vpSize.width();
+
+ updateWindowPosition();
+ m_resizing = false;
+ }
+}
+void WindowWidget::updateWindowPosition()
+{
+ if (m_hostedWindow && m_hostedWindow->rootObject()) {
+ QSize wSize = qmlSize();
+ Qt::LayoutDirection dir = layoutDirection();
+ QRect scrolled = QStyle::visualRect(dir, viewport()->rect(), QRect(QPoint(-horizontalScrollBar()->value(), -verticalScrollBar()->value()), wSize));
+ QRect aligned = QStyle::alignedRect(dir, m_centering ? Qt::AlignCenter : Qt::AlignTop | Qt::AlignLeft, wSize, viewport()->rect());
+
+ //qWarning() << "xAlign:" << aligned.x() << "xScrolled:" << scrolled.x();
+ m_hostedWindow->setPosition(wSize.width() < viewport()->width() ? aligned.x() : scrolled.x(),
+ wSize.height() < viewport()->height() ? aligned.y() : scrolled.y());
+ }
+}
+
+QSize WindowWidget::qmlSize() const
+{
+ QSize s;
+ if (m_hostedWindow && m_hostedWindow->rootObject()) {
+ s = QSize(m_hostedWindow->rootObject()->width(),
+ m_hostedWindow->rootObject()->height());
+ }
+
+ if (s.width() <= 20)
+ s.setWidth(800);
+ if (s.height() <= 20)
+ s.setHeight(600);
+
+ return s;
+}
+
diff --git a/src/widgets/windowwidget.h b/src/widgets/windowwidget.h
new file mode 100644
index 0000000..23d7900
--- /dev/null
+++ b/src/widgets/windowwidget.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QAbstractScrollArea>
+#include <QPointer>
+
+class QQuickView;
+
+class WindowWidget : public QAbstractScrollArea
+{
+ Q_OBJECT
+public:
+ explicit WindowWidget(QWidget *parent = 0);
+
+ QQuickView *hostedWindow() const;
+ void setHostedWindow(QQuickView *hostedWindow);
+ void setVisible(bool visible);
+ void setCenteringEnabled(bool enabled);
+ QSize sizeHint() const;
+ void forceInitialResize();
+
+Q_SIGNALS:
+ void widthChanged(int w);
+ void heightChanged(int w);
+
+protected:
+ bool event(QEvent *e);
+ bool eventFilter(QObject *o, QEvent *e);
+ void scrollContentsBy(int dx, int dy);
+
+private:
+ void updateScrollBars();
+ void updateWindowPosition();
+ QSize qmlSize() const;
+
+ QPointer<QQuickView> m_hostedWindow;
+ bool m_resizing;
+ bool m_centering;
+};
+
diff --git a/src/widgets/workspacedelegate.cpp b/src/widgets/workspacedelegate.cpp
new file mode 100644
index 0000000..4e05227
--- /dev/null
+++ b/src/widgets/workspacedelegate.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "workspacedelegate.h"
+
+WorkspaceDelegate::WorkspaceDelegate(FileSystemModel* model, QObject *parent) :
+ QStyledItemDelegate(parent),
+ m_model(model)
+{
+}
+
+void WorkspaceDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
+{
+ QStyledItemDelegate::initStyleOption(option, index);
+
+ if (option) {
+ if (m_model->isDir(index))
+ return;
+
+ QString path = m_model->filePath(index);
+ foreach (QString type, m_model->allowedTypesFilter())
+ {
+ if (path.contains(QRegExp(type, Qt::CaseInsensitive, QRegExp::Wildcard)))
+ return;
+ }
+
+ option->state &= ~QStyle::State_Enabled;
+
+ QColor disabled = option->palette.color(QPalette::Disabled, QPalette::Text);
+ QColor enabled = option->palette.color(QPalette::Normal, QPalette::Text);
+
+ if (disabled == enabled) {
+ QColor t = option->palette.color(QPalette::Disabled, QPalette::Text);
+ QColor b = option->palette.color(QPalette::Disabled, QPalette::Background);
+
+ QColor selection = QColor::fromRgb((t.red() + b.red()) / 2, (t.green() + b.green()) / 2, (t.blue() + b.blue()) / 2);
+
+ option->palette.setColor(QPalette::Disabled, QPalette::Text, selection);
+ }
+ }
+}
diff --git a/src/widgets/workspacedelegate.h b/src/widgets/workspacedelegate.h
new file mode 100644
index 0000000..4ccb157
--- /dev/null
+++ b/src/widgets/workspacedelegate.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QStyledItemDelegate>
+#include "filesystemmodel.h"
+
+class WorkspaceDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ explicit WorkspaceDelegate(FileSystemModel* model, QObject *parent = 0);
+
+ virtual void initStyleOption(QStyleOptionViewItem * option, const QModelIndex & index )const;
+
+private:
+
+ FileSystemModel* m_model;
+};
+
diff --git a/src/widgets/workspaceview.cpp b/src/widgets/workspaceview.cpp
new file mode 100644
index 0000000..ae06ca2
--- /dev/null
+++ b/src/widgets/workspaceview.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "workspaceview.h"
+#include "filesystemmodel.h"
+#include "workspacedelegate.h"
+
+/*!
+ \class WorkspaceView
+ \internal
+ \brief A TreeView showing the Local Filesystem.
+
+ The activateDocument() signal can be used to connect to a LiveHubEngine.
+ */
+
+
+/*!
+ Standard constructor using \a parent as parent
+ */
+WorkspaceView::WorkspaceView(QWidget *parent)
+ : QWidget(parent)
+ , m_view(new QTreeView(this))
+ , m_model(new FileSystemModel(this))
+{
+ // setup view
+// m_view->setFocusPolicy(Qt::NoFocus);
+ m_view->setModel(m_model);
+ m_view->hideColumn(1); // size
+ m_view->hideColumn(2); // type
+ m_view->hideColumn(3); // modified time
+
+ m_view->setItemDelegate(new WorkspaceDelegate(m_model, this));
+ connect(m_view, SIGNAL(activated(QModelIndex)), this, SLOT(indexActivated(QModelIndex)));
+
+ m_model->setAllowedTypesFilter(QStringList() << "*.qml" << "*.png" << "*.otf" << "*.ttf");
+
+ // setup layout
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_view);
+ layout->setMargin(1);
+ setLayout(layout);
+
+
+ m_view->setDragEnabled(true);
+ m_view->setDragDropMode(QAbstractItemView::DragOnly);
+}
+
+/*!
+ * Sets the root workspace path to be displayed in the view to \a dirPath
+ */
+void WorkspaceView::setRootPath(const QString &dirPath)
+{
+ m_rootIndex = m_model->setRootPath(dirPath);
+ m_view->setRootIndex(m_model->index(dirPath));
+}
+
+/*!
+ * Activates the document by the given \a path
+ */
+void WorkspaceView::activateDocument(const QString &path)
+{
+ //qDebug() << "WorkspaceView::activateDocument" << path;
+ QModelIndex index = m_model->index(path);
+ selectIndex(index);
+}
+
+void WorkspaceView::activateRootPath()
+{
+ selectIndex(m_rootIndex);
+ emit pathActivated(m_model->rootPath());
+}
+
+void WorkspaceView::goUp()
+{
+ QModelIndex index = m_view->currentIndex().parent();
+ if (!index.isValid() || index == m_rootIndex)
+ return;
+
+ selectIndex(index);
+}
+
+/*!
+ * Returns the active, selected document.
+ */
+QString WorkspaceView::activeDocument() const
+{
+ return m_currentDocument;
+}
+
+QString WorkspaceView::rootPath() const
+{
+ return m_model->rootPath();
+}
+
+void WorkspaceView::setDirectoriesSelectable(bool enabled)
+{
+ m_model->setDirectoriesSelectable(enabled);
+}
+
+bool WorkspaceView::directoriesSelectable() const
+{
+ return m_model->directoriesSelectable();
+}
+
+/*!
+ * Emits a document activated signal based on a given \a index
+ */
+void WorkspaceView::indexActivated(const QModelIndex &index)
+{
+ if (!(m_model->flags(index) & Qt::ItemIsSelectable))
+ return;
+
+ QString path = m_model->filePath(index);
+
+ m_currentDocument = path;
+ emit pathActivated(path);
+}
+
+void WorkspaceView::selectIndex(const QModelIndex &index)
+{
+ QModelIndex parentIndex = index.parent();
+ while (parentIndex.isValid()) {
+ m_view->expand(parentIndex);
+ parentIndex = parentIndex.parent();
+ }
+ m_view->setCurrentIndex(index);
+ indexActivated(index);
+ //m_view->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
+}
diff --git a/src/widgets/workspaceview.h b/src/widgets/workspaceview.h
new file mode 100644
index 0000000..53b7b3b
--- /dev/null
+++ b/src/widgets/workspaceview.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtGui>
+#include <QtWidgets>
+
+class FileSystemModel;
+
+class WorkspaceView : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit WorkspaceView(QWidget *parent = 0);
+ QString activeDocument() const;
+ QString rootPath() const;
+ void setDirectoriesSelectable(bool enabled);
+ bool directoriesSelectable() const;
+
+public Q_SLOTS:
+ void setRootPath(const QString& dirPath);
+ void activateDocument(const QString& path);
+ void activateRootPath();
+ void goUp();
+
+Q_SIGNALS:
+ void pathActivated(const QString& path);
+
+private Q_SLOTS:
+ void indexActivated(const QModelIndex& index);
+
+private:
+ void selectIndex(const QModelIndex& index);
+ QTreeView *m_view;
+ FileSystemModel *m_model;
+ QModelIndex m_rootIndex;
+ QString m_currentDocument;
+};
diff --git a/testData/mixed/radio_0.png b/testData/mixed/radio_0.png
new file mode 100644
index 0000000..fde357d
--- /dev/null
+++ b/testData/mixed/radio_0.png
Binary files differ
diff --git a/testData/mixed/radio_0_ro.png b/testData/mixed/radio_0_ro.png
new file mode 100644
index 0000000..8b30856
--- /dev/null
+++ b/testData/mixed/radio_0_ro.png
Binary files differ
diff --git a/testData/mixed/radio_1.png b/testData/mixed/radio_1.png
new file mode 100644
index 0000000..c5d7d34
--- /dev/null
+++ b/testData/mixed/radio_1.png
Binary files differ
diff --git a/testData/mixed/radio_2.png b/testData/mixed/radio_2.png
new file mode 100644
index 0000000..f7bad20
--- /dev/null
+++ b/testData/mixed/radio_2.png
Binary files differ
diff --git a/testData/mixed/radio_3.png b/testData/mixed/radio_3.png
new file mode 100644
index 0000000..a27f2ca
--- /dev/null
+++ b/testData/mixed/radio_3.png
Binary files differ
diff --git a/testData/mixed/radio_disabled.png b/testData/mixed/radio_disabled.png
new file mode 100644
index 0000000..5b30b10
--- /dev/null
+++ b/testData/mixed/radio_disabled.png
Binary files differ
diff --git a/testData/mixed/radio_disabled_ro.png b/testData/mixed/radio_disabled_ro.png
new file mode 100644
index 0000000..b4fb8ae
--- /dev/null
+++ b/testData/mixed/radio_disabled_ro.png
Binary files differ
diff --git a/testData/mixed/radio_nav_active.png b/testData/mixed/radio_nav_active.png
new file mode 100644
index 0000000..17c7f4c
--- /dev/null
+++ b/testData/mixed/radio_nav_active.png
Binary files differ
diff --git a/testData/mixed/radio_nav_inactive.png b/testData/mixed/radio_nav_inactive.png
new file mode 100644
index 0000000..9ca1bde
--- /dev/null
+++ b/testData/mixed/radio_nav_inactive.png
Binary files differ
diff --git a/testData/mixed/radio_selected.png b/testData/mixed/radio_selected.png
new file mode 100644
index 0000000..629123d
--- /dev/null
+++ b/testData/mixed/radio_selected.png
Binary files differ
diff --git a/testData/qml/explicit-size.qml b/testData/qml/explicit-size.qml
new file mode 100644
index 0000000..88ae8b5
--- /dev/null
+++ b/testData/qml/explicit-size.qml
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Rectangle {
+ color: "#00ff00"
+ width: 100
+ height: 400
+}
diff --git a/testData/qml/no-explicit-size.qml b/testData/qml/no-explicit-size.qml
new file mode 100644
index 0000000..e41462e
--- /dev/null
+++ b/testData/qml/no-explicit-size.qml
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+
+Rectangle {
+ color: "#ffff00"
+// width: 500
+// height: 300
+}
diff --git a/testData/qml/two-windows.qml b/testData/qml/two-windows.qml
new file mode 100644
index 0000000..3ffa5f0
--- /dev/null
+++ b/testData/qml/two-windows.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Window 2.1
+
+Rectangle {
+ width: 400
+ height: 400
+ color: "red"
+
+ Text {
+ anchors.centerIn: parent
+ text: "Window 1"
+ }
+
+ Window {
+ width: 400
+ height: 400
+ visible: true
+ Rectangle {
+ anchors.fill: parent
+ color: "blue"
+
+ Text {
+ anchors.centerIn: parent
+ text: "Window 2"
+ }
+ }
+ }
+}
diff --git a/tests/manual_tests/javascript/lib.js b/tests/manual_tests/javascript/lib.js
new file mode 100644
index 0000000..413eb9b
--- /dev/null
+++ b/tests/manual_tests/javascript/lib.js
@@ -0,0 +1 @@
+var counter = 0
diff --git a/tests/manual_tests/javascript/pragma_main.qml b/tests/manual_tests/javascript/pragma_main.qml
new file mode 100644
index 0000000..353eff4
--- /dev/null
+++ b/tests/manual_tests/javascript/pragma_main.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+import QtQuick 2.0
+import "pragmalib.js" as PragmaLib
+import "lib.js" as Lib
+
+Item {
+
+ Component.onCompleted: {
+ for (var i= 0; i< 10; i++) {
+ print("Pragma Lib " + PragmaLib.counter++)
+ }
+
+ for (var i= 0; i< 10; i++) {
+ print("Lib " + Lib.counter++)
+ }
+ }
+}
diff --git a/tests/manual_tests/javascript/pragmalib.js b/tests/manual_tests/javascript/pragmalib.js
new file mode 100644
index 0000000..512cdf9
--- /dev/null
+++ b/tests/manual_tests/javascript/pragmalib.js
@@ -0,0 +1,3 @@
+.pragma library
+
+var counter = 0
diff --git a/tests/testipc/testipc.pro b/tests/testipc/testipc.pro
new file mode 100644
index 0000000..6670176
--- /dev/null
+++ b/tests/testipc/testipc.pro
@@ -0,0 +1,19 @@
+QT += testlib
+
+QT -= gui
+QT += network
+
+TARGET = tst_testipc
+CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+include(../../src/src.pri)
+
+SOURCES += tst_testipc.cpp
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+include(../../base.pri)
+
diff --git a/tests/testipc/tst_testipc.cpp b/tests/testipc/tst_testipc.cpp
new file mode 100644
index 0000000..ca9f86c
--- /dev/null
+++ b/tests/testipc/tst_testipc.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+#include <QtCore>
+#include <QtTest>
+#include <QtNetwork>
+
+#include "ipc/ipcserver.h"
+#include "ipc/ipcclient.h"
+
+class TestIpc : public QObject
+{
+ Q_OBJECT
+
+public:
+ TestIpc() {}
+public slots:
+ void handleCall(QString method, QByteArray data) {
+ if (method == "echo(QString)") {
+ QDataStream stream(data);
+ QString message;
+ stream >> message;
+ qDebug() << method << ": " << message;
+ }
+ if (method == "sendFile(QString,QByteArray)") {
+ QDataStream stream(data);
+ QString path;
+ stream >> path;
+ QByteArray body;
+ stream >> body;
+ qDebug() << method << ": " << path;
+ }
+ }
+
+private Q_SLOTS:
+ void call() {
+ IpcServer peer1;
+ peer1.listen(10234);
+ connect(&peer1, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
+ IpcClient peer2;
+ peer2.setDestination("127.0.0.1", 10234);
+ QByteArray bytes;
+ QDataStream stream(&bytes, QIODevice::ReadWrite);
+ stream << QString("Hello IPC!");
+ peer2.send("echo(QString)", bytes);
+ QSignalSpy received(&peer1, SIGNAL(received(QString,QByteArray)));
+ QTest::qWait(100);
+ QVERIFY(received.count() == 1);
+ }
+
+ void sendFile() {
+ IpcServer peer1;
+ peer1.listen(10234);
+ connect(&peer1, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
+ IpcClient peer2;
+ peer2.setDestination("127.0.0.1", 10234);
+ QByteArray bytes;
+ QDataStream stream(&bytes, QIODevice::ReadWrite);
+ QString filePath("tst_testipc.cpp");
+ stream << filePath;
+ stream << QString("hello").toLatin1();
+ peer2.send("sendFile(QString,QByteArray)", bytes);
+ QSignalSpy received(&peer1, SIGNAL(received(QString,QByteArray)));
+ QTest::qWait(100);
+ QVERIFY(received.count() == 1);
+ }
+};
+
+QTEST_MAIN(TestIpc)
+
+#include "tst_testipc.moc"
diff --git a/tests/tests.pro b/tests/tests.pro
new file mode 100644
index 0000000..3179cdf
--- /dev/null
+++ b/tests/tests.pro
@@ -0,0 +1,7 @@
+TEMPLATE = subdirs
+
+
+SUBDIRS += \
+ testipc
+ #testsync \
+ #http
diff --git a/tests/testsync/testsync.pro b/tests/testsync/testsync.pro
new file mode 100644
index 0000000..18aa2bb
--- /dev/null
+++ b/tests/testsync/testsync.pro
@@ -0,0 +1,17 @@
+QT += testlib
+
+QT -= gui
+
+TARGET = tst_testsync
+CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+include(../../src/sync/sync.pri)
+
+SOURCES += tst_testsync.cpp
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+include(../../base.pri)
diff --git a/tests/testsync/tst_testsync.cpp b/tests/testsync/tst_testsync.cpp
new file mode 100644
index 0000000..135290a
--- /dev/null
+++ b/tests/testsync/tst_testsync.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Pelagicore AG
+** Contact: http://www.qt.io/ or http://www.pelagicore.com/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$
+** Commercial License Usage
+** Licensees holding valid commercial Pelagicore Application Manager
+** licenses may use this file in accordance with the commercial license
+** agreement provided with the Software or, alternatively, in accordance
+** with the terms contained in a written agreement between you and
+** Pelagicore. For licensing terms and conditions, contact us at:
+** http://www.pelagicore.com.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3 requirements will be
+** met: http://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+#include <QtCore/QString>
+#include <QtTest/QtTest>
+#include "../../src/sync/syncengine.h"
+
+class TestSync : public QObject
+{
+ Q_OBJECT
+
+public:
+ TestSync() {}
+
+private Q_SLOTS:
+ void rsync() {
+ SyncEngine engine;
+ engine.setProgram("/usr/bin/rsync");
+ engine.setLogin("jryannel");
+ engine.setMachine("127.0.0.1");
+ engine.setRemoteBasePath("/Users/jryannel/temp/temp1");
+ engine.setLocalBasePath("/Users/jryannel/temp/temp2");
+// engine.setDryRun(true);
+ engine.start();
+ engine.wait();
+ }
+};
+
+QTEST_APPLESS_MAIN(TestSync)
+#include "tst_testsync.moc"