diff --git a/README.md b/README.md index f8e1028..4aa31b5 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,9 @@ This is a Gui for OpenZWave, intended to replace the open-zwave-control-panel eventually. Work in Progress. Don't expect much right now :) + +If you are using the ozwdaemon docker image, you need to allow remote network access to the Docker Image: + +```docker run -it --security-opt seccomp=unconfined --device=/dev/ttyUSB0 -v /tmp/ozw:/opt/ozw/config -e MQTT_SERVER="10.100.200.102" -e USBPATH=/dev/ttyUSB0 --network host openzwave/ozwdaemon:latest``` + +Then in the OZWAdmin gui, when opening a "Remote Connection" specify the IP address of the Host the Docker Image is running on. diff --git a/osxmakebundle.sh b/osxmakebundle.sh deleted file mode 100755 index e52fea9..0000000 --- a/osxmakebundle.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -if [ $# -lt 3 ]; then - echo "Please Provide the path to the App Bundle and OZW Config Directory and QT Directories" - exit 1 -fi -if [ ! -f $1/Contents/Frameworks/libqt-openzwave.1.dylib ]; then - echo "$1/Contents/Frameworks/libqt-openzwave.1.dylib doens't exist" - exit 1 -fi -if [ ! -f $2/manufacturer_specific.xml ]; then - echo "$2/manufacturer_specific.xml doesn't exist" - exit 1 -fi -if [ ! -f $3/bin/macdeployqt ]; then - echo "$3/bin/macdeployqt does't exist" - exit 1 -fi -PATH=`otool -L $1/Contents/Frameworks/libqt-openzwave.1.dylib | grep libopenzwave | awk '{print $1}'` -/usr/bin/install_name_tool -change $PATH "@rpath/${PATH##*/}" $1/Contents/Frameworks/libqt-openzwave.1.dylib -/bin/cp -r $2 $1/Contents/Resources/config/ -echo "To Finish Please Run '$3/bin/macdeployqt $1 -verbose=2 -always-overwrite'" diff --git a/ozw-admin.pri b/ozw-admin.pri new file mode 100644 index 0000000..83d3ed7 --- /dev/null +++ b/ozw-admin.pri @@ -0,0 +1,172 @@ +top_srcdir=$$PWD +top_builddir=$$shadowed($$PWD) +unix { + macx { + QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.14 + } + !macx: QMAKE_CXXFLAGS += -Wno-deprecated-copy +} + +unix { + CONFIG-= no-pkg-config + CONFIG+= link_pkgconfig + !isEmpty(OZW_LIB_PATH) { + !exists($$OZW_LIB_PATH/libopenzwave.so): error("Can't find libopenzwave.so") + !exists($$OZW_INCLUDE_PATH/Manager.h) { + !exists($$OZW_LIB_PATH/cpp/src/Manager.h) { + error("Can't find Manager.h") + } else { + OZW_INCLUDE_PATH=$$OZW_LIB_PATH/cpp/src/ + } + } + !exists($$OZW_DATABASE_PATH/manufacturer_specific.xml) { + !exists($$OZW_LIB_PATH/config/manufacturer_specific.xml) { + error("Can't find manufacturer_specific.xml") + } else { + OZW_DATABASE_PATH=$$absolute_path($$OZW_LIB_PATH/config/) + } + } + OZW_LIB_PATH=$$absolute_path($$OZW_LIB_PATH) + OZW_INCLUDE_PATH=$$absolute_path($$OZW_INCLUDE_PATH) + OZW_LIBS="-L$$OZW_LIB_PATH" + OZW_LIBS+="-lopenzwave" + OZW_DATABASE_PATH=$$absolute_path($$OZW_DATABASE_PATH) + message(" ") + message("OpenZWave Summary:") + message(" OpenZWave Library Path: $$OZW_LIB_PATH") + message(" OpenZWave Include Path: $$OZW_INCLUDE_PATH") + message(" OpenZWave Libs Command: $$OZW_LIBS") + message(" OpenZWave Database Path: $$OZW_DATABASE_PATH") + message(" ") + INCLUDEPATH+=$$OZW_INCLUDE_PATH + LIBS+=$$OZW_LIBS + } else { + exists( $$top_srcdir/../open-zwave/cpp/src/) { + message("Found OZW in $$absolute_path($$top_srcdir/../open-zwave/)") + OZW_LIB_PATH = "$$absolute_path($$top_srcdir/../open-zwave/)" + OZW_INCLUDE_PATH = $$absolute_path($$top_srcdir/../open-zwave/cpp/src/) + OZW_LIBS="-L$$OZW_LIB_PATH" + OZW_LIBS+="-lopenzwave" + OZW_DATABASE_PATH = $$absolute_path($$top_srcdir/../open-zwave/config/) + message(" ") + message("OpenZWave Summary:") + message(" OpenZWave Library Path: $$OZW_LIB_PATH") + message(" OpenZWave Include Path: $$OZW_INCLUDE_PATH") + message(" OpenZWave Libs Command: $$OZW_LIBS") + message(" OpenZWave Database Path: $$OZW_DATABASE_PATH") + message(" ") + INCLUDEPATH+=$$OZW_INCLUDE_PATH + LIBS+=$$OZW_LIBS + } else { + packagesExist("libopenzwave") { + PKGCONFIG += libopenzwave + OZW_DATABASE_PATH=$$system($$PKG_CONFIG --variable=sysconfdir libopenzwave) + message(" ") + message("OpenZWave Summary:") + message(" Using OpenZWave from pkg-config:") + message(" CXXFLAGS: $$system($$PKG_CONFIG --cflags libopenzwave)") + message(" LDFLAGS: $$system($$PKG_CONFIG --libs libopenzwave)") + message(" DATABASE: $$system($$PKG_CONFIG --variable=sysconfdir libopenzwave)") + message(" ") + } else { + error("Can't find OpenZWave Library and Headers"); + } + } + } + + !isEmpty(QTOZW_LIB_PATH) { + !exists($$QTOZW_LIB_PATH/qt-openzwave/libqt-openzwave.so): error("Can't find libqt-openzwave.so") + !exists($$QTOZW_INCLUDE_PATH/qt-openzwave/qtopenzwave.h) { + !exists($$QTOZW_LIB_PATH/qt-openzwave/include/qt-openzwave/qtopenzwave.h) { + error("Can't find Manager.h") + } else { + QTOZW_INCLUDE_PATH=$$QTOZW_LIB_PATH/qt-openzwave/include/ + } + } + QTOZW_LIB_PATH=$$absolute_path($$QTOZW_LIB_PATH) + QTOZW_INCLUDE_PATH=$$absolute_path($$QTOZW_INCLUDE_PATH) + QTOZW_INCLUDE_PATH+=$$absolute_path($$QTOZW_INCLUDE_PATH/../../qt-openzwavedatabase/include/) + QTOZW_LIBS="-L$$absolute_path($$QTOZW_LIB_PATH/qt-openzwave/)" + QTOZW_LIBS+="-lqt-openzwave" + QTOZW_LIBS+="-L$$absolute_path($$QTOZW_LIB_PATH/qt-openzwavedatabase/)" + QTOZW_LIBS+="-lqt-openzwavedatabase" + message(" ") + message("QT-OpenZWave Summary:") + message(" QT-OpenZWave Library Path: $$QTOZW_LIB_PATH") + message(" QT-OpenZWave Include Path: $$QTOZW_INCLUDE_PATH") + message(" Qt-OpenZWave Libs Command: $$QTOZW_LIBS") + message(" ") + INCLUDEPATH+=$$QTOZW_INCLUDE_PATH + LIBS+=$$QTOZW_LIBS + } else { + exists($$top_srcdir/../qt-openzwave/qt-openzwave/include/qt-openzwave/qtopenzwave.h) { + message("Found QTOZW in $$absolute_path($$top_srcdir/../qt-openzwave/)") + QTOZW_LIB_PATH = "$$absolute_path($$top_srcdir/../qt-openzwave/qt-openzwave/)" + QTOZW_INCLUDE_PATH = $$absolute_path($$top_srcdir/../qt-openzwave/qt-openzwave/include/) + QTOZW_INCLUDE_PATH += $$absolute_path($$top_srcdir/../qt-openzwave/qt-openzwavedatabase/include/) + QTOZW_LIBS="-L$$QTOZW_LIB_PATH" + QTOZW_LIBS+="-lqt-openzwave" + QTOZW_LIBS+="-L$$absolute_path($$QTOZW_LIB_PATH/../qt-openzwavedatabase/)" + QTOZW_LIBS+="-lqt-openzwavedatabase" + message(" ") + message("QT-OpenZWave Summary:") + message(" QT-OpenZWave Library Path: $$QTOZW_LIB_PATH") + message(" QT-OpenZWave Include Path: $$QTOZW_INCLUDE_PATH") + message(" QT-OpenZWave Libs Command: $$QTOZW_LIBS") + message(" ") + INCLUDEPATH+=$$QTOZW_INCLUDE_PATH + LIBS+=$$QTOZW_LIBS + } else { + packagesExist("libqt-openzwave") { + PKGCONFIG += libqt-openzwave + message(" ") + message("QT-OpenZWave Summary:") + message(" Using QT-OpenZWave from pkg-config:") + message(" CXXFLAGS: $$system($$PKG_CONFIG --cflags libqt-openzwave)") + message(" LDFLAGS: $$system($$PKG_CONFIG --libs libqt-openzwave)") + message(" ") + } else { + error("Can't find QT-OpenZWave Library and Headers"); + } + } + } + + +} + +win32 { + CONFIG(debug, debug|release) { + BUILDTYPE = debug + } else { + BUILDTYPE = release + } + message(Checking for $$BUILDTYPE build of OZW) + exists( $$top_srcdir/../open-zwave/cpp/src/) { + message("Found OZW in $$absolute_path($$top_srcdir/../open-zwave/cpp/src)") + INCLUDEPATH += $$absolute_path($$top_srcdir/../open-zwave/cpp/src/)/ + INCLUDEPATH += $$absolute_path($$top_srcdir/../qt-openzwave/qt-openzwave/include/) + INCLUDEPATH += $$absolute_path($$top_srcdir/../qt-openzwave/qt-openzwavedatabase/include/) + equals(BUILDTYPE, "release") { + exists( $$absolute_path($$top_srcdir/../open-zwave/cpp/build/windows/vs2010/ReleaseDLL/OpenZWave.dll ) ) { + LIBS += -L$$absolute_path($$top_srcdir/../open-zwave/cpp/build/windows/vs2010/ReleaseDLL) -lopenzwave + OZW_LIB_PATH = $$absolute_path($$top_srcdir/../open-zwave/cpp/build/windows/vs2010/ReleaseDLL) + } else { + error("Can't find a copy of OpenZWave.dll in the ReleaseDLL Directory"); + } + } else { + equals(BUILDTYPE, "debug") { + exists ( $$absolute_path($$top_srcdir/../open-zwave/cpp/build/windows/vs2010/DebugDLL/OpenZWaved.dll )) { + LIBS += -L$$absolute_path($$top_srcdir/../open-zwave/cpp/build/windows/vs2010/DebugDLL) -lOpenZWaved + OZW_LIB_PATH = $$absolute_path($$top_srcdir/../open-zwave/cpp/build/windows/vs2010/ReleaseDLL) + } else { + error("Can't find a copy of OpenZWaved.dll in the DebugDLL Directory"); + } + } + } + isEmpty(OZW_LIB_PATH) { + error("Can't find a copy of OpenZWave with the right builds"); + } + } else { + error("Can't Find a copy of OpenZwave") + } +} diff --git a/ozwadmin-main/mainwindow.cpp b/ozwadmin-main/mainwindow.cpp index 3b9945c..d8fdfbc 100644 --- a/ozwadmin-main/mainwindow.cpp +++ b/ozwadmin-main/mainwindow.cpp @@ -55,6 +55,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionOpen_Log_Window, SIGNAL(triggered()), this, SLOT(openLogWindow())); connect(ui->actionOpen_Serial_Port, SIGNAL(triggered()), this, SLOT(OpenSerialPort())); + connect(ui->actionOpen_Remote, SIGNAL(triggered()), this, SLOT(OpenRemote())); + connect(ui->action_Close, SIGNAL(triggered()), this, SLOT(CloseConnection())); connect(ui->actionDevice_Database, SIGNAL(triggered()), this, SLOT(OpenDeviceDB())); connect(ui->md_helpwindow, &QPushButton::clicked, this, &MainWindow::openMetaDataWindow); connect(ui->action_Configuration, SIGNAL(triggered()), this, SLOT(openConfigWindow())); @@ -199,7 +201,12 @@ MainWindow::MainWindow(QWidget *parent) : qDebug() << directory.absoluteFilePath(); if (directory.exists()) { #ifndef _WIN32 + QStringList dirs; + dirs << directory.absoluteFilePath().append("/"); + initConfigDatabase(dirs); +#if 0 copyConfigDatabase(directory.absoluteFilePath().append("/")); +#endif #endif m_configpath.setPath(directory.absoluteFilePath().append("/config/")); m_userpath.setPath(directory.absoluteFilePath().append("/config/")); @@ -320,10 +327,36 @@ void MainWindow::QTOZW_Ready() { this->m_statTimer.start(1000); } +void MainWindow::OpenRemote() { + bool ok; + + QString text = QInputDialog::getText(this, tr("Enter Remote Host"), + tr("Hostname/IP Address:"), QLineEdit::Normal, + "localhost", &ok); + if (!ok) + return; + + QUrl server; + server.setHost(text); + server.setPort(1983); + server.setScheme("tcp"); + qDebug() << "Connecting to " << server; + this->m_qtozwmanager->initilizeReplica(server); + +} +void MainWindow::CloseConnection() { + +} + void MainWindow::OpenSerialPort() { bool ok; + + QMessageBox::warning(this, tr("OZW-Admin"), + tr("This is Work In Progress!"), + QMessageBox::Ok); + QString text = QInputDialog::getText(this, tr("Select Serial Port"), tr("Serial Port:"), QLineEdit::Normal, this->m_serialport, &ok); diff --git a/ozwadmin-main/mainwindow.h b/ozwadmin-main/mainwindow.h index 88f4016..4733eac 100644 --- a/ozwadmin-main/mainwindow.h +++ b/ozwadmin-main/mainwindow.h @@ -42,6 +42,8 @@ public: Q_PROPERTY(QString SerialPort MEMBER m_serialport) public slots: void OpenSerialPort(); + void OpenRemote(); + void CloseConnection(); void resizeColumns(); void NodeSelected(QModelIndex,QModelIndex); void openLogWindow(); diff --git a/ozwadmin-main/mainwindow.ui b/ozwadmin-main/mainwindow.ui index 222005a..bf97c32 100644 --- a/ozwadmin-main/mainwindow.ui +++ b/ozwadmin-main/mainwindow.ui @@ -907,7 +907,7 @@ 0 0 - 98 + 85 71 @@ -1086,6 +1086,8 @@ false + + @@ -1120,6 +1122,22 @@ &Device Database + + + Open &Remote + + + Open Remote + + + + + &Close + + + Close Local or Remote Connection + + diff --git a/ozwadmin-main/ozwadmin-main.pro b/ozwadmin-main/ozwadmin-main.pro index 6c9edc7..8c02adf 100644 --- a/ozwadmin-main/ozwadmin-main.pro +++ b/ozwadmin-main/ozwadmin-main.pro @@ -5,7 +5,7 @@ #------------------------------------------------- QT += core gui widgets xml remoteobjects websockets svg -CONFIG += silent +#CONFIG += silent TARGET = ../ozwadmin TEMPLATE = app @@ -31,18 +31,18 @@ FORMS += mainwindow.ui \ RESOURCES += \ ozwadmin-main.qrc \ +include(../ozw-admin.pri) - -#LIBS += ../devicedb-lib/libdevicedb-lib.a ../ozwadmin-widgets/libozwadmin-widgets.a unix { + target.path = /usr/local/bin + INSTALLS += target LIBS += -L../devicedb-lib/ -ldevicedb-lib -L../ozwadmin-widgets/ -lozwadmin-widgets - LIBS += -L../../qt-openzwave/qt-openzwave/ -lqt-openzwave -L../../qt-openzwave/qt-openzwavedatabase -lqt-openzwavedatabase } windows { CONFIG(debug, debug|release) { LIBS += -L..\devicedb-lib\debug\ -L..\ozwadmin-widgets\debug\ -L..\..\qt-openzwave\qt-openzwave\debug\ } else { - LIBS += -L..\devicedb-lib\release\ -L..\ozwadmin-widgets\release\ -L..\..\qt-openzwave\qt-openzwave\release\ + LIBS += -L..\devicedb-lib\release\ -L..\ozwadmin-widgets\release\ -L..\..\qt-openzwave\qt-openzwave\release\ } LIBS += -ldevicedb-lib -lozwadmin-widgets -lqt-openzwave1 message($$LIBS) @@ -51,14 +51,15 @@ windows { INCLUDEPATH += ../devicedb-lib ../ozwadmin-widgets -INCLUDEPATH += ../../qt-openzwave/qt-openzwave/include/ ../../qt-openzwave/qt-openzwavedatabase/include/ - macx: { LIBS += -framework IOKit -framework CoreFoundation - BUNDLE.files = ../../qt-openzwave/qt-openzwave/libqt-openzwave.1.dylib ../../open-zwave/libopenzwave-1.6.dylib ../../qt-openzwave/qt-openzwavedatabase/libqt-openzwavedatabase.1.dylib + BUNDLE.files = $$OZW_LIB_PATH/libopenzwave-1.6.dylib $$QTOZW_LIB_PATH/libqt-openzwave.1.dylib $$QTOZW_LIB_PATH/../qt-openzwavedatabase/libqt-openzwavedatabase.1.dylib BUNDLE.path = Contents/Frameworks/ QMAKE_BUNDLE_DATA += BUNDLE + MakeBundle.commands = $$[QT_HOST_BINS]/macdeployqt ../ozwadmin.app && $$top_srcdir/scripts/macdeployqtfix.py ../ozwadmin.app/Contents/MacOS/ozwadmin $$[QT_INSTALL_PREFIX] + QMAKE_EXTRA_TARGETS += MakeBundle + QMAKE_POST_LINK += $$MakeBundle.commands ICON = res/ozw_logo.icns } diff --git a/ozwadmin-widgets/ozwadmin-widgets.pro b/ozwadmin-widgets/ozwadmin-widgets.pro index 4899d2e..afe396f 100644 --- a/ozwadmin-widgets/ozwadmin-widgets.pro +++ b/ozwadmin-widgets/ozwadmin-widgets.pro @@ -44,7 +44,9 @@ FORMS += HelpEditorDlg.ui \ bitsetwidget.ui \ nodeflagswidget.ui -INCLUDEPATH += ../devicedb-lib ../ozwadmin-main ../../qt-openzwave/qt-openzwave/include/ +include(../ozw-admin.pri) + +INCLUDEPATH += ../devicedb-lib ../ozwadmin-main macx: { diff --git a/qt-openzwave.pri b/qt-openzwave.pri deleted file mode 100644 index b303d71..0000000 --- a/qt-openzwave.pri +++ /dev/null @@ -1,2 +0,0 @@ -top_srcdir=$$PWD -top_builddir=$$shadowed($$PWD) diff --git a/scripts/Dockerfile b/scripts/Dockerfile new file mode 100644 index 0000000..829b075 --- /dev/null +++ b/scripts/Dockerfile @@ -0,0 +1,11 @@ +#DockerFile to build a image capabile of Building AppImages. See build.sh for details +FROM ubuntu:xenial +WORKDIR /opt + +RUN apt update && apt-get install -y software-properties-common && add-apt-repository ppa:beineri/opt-qt-5.12.6-xenial && \ +apt update && apt-get install -y qt512-meta-minimal qt512remoteobjects rapidjson-dev git g++ cmake make pkgconf bash python wget joe mc libunwind-dev libcurl4-openssl-dev qt512svg qt512websockets mesa-common-dev libgl1-mesa-dev fuse appstream && \ +wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage && \ +wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage && \ +chmod +x linuxdeploy*.AppImage +VOLUME /opt/buildfiles +ENTRYPOINT /opt/buildfiles/build.sh \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..4906acd --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,16 @@ +#!/bin/bash +#Build File for Docker Image. +#Run docker in this directory with: docker run -it --rm --device /dev/fuse --privileged -v`pwd`:/opt/buildfiles -e DOCKERUSERID=`id -u` -e DOCKERGROUPID=`id -g` +cd /opt +git clone https://github.com/OpenZWave/open-zwave.git && cd open-zwave && make -j4 && make install +cd /opt +git clone https://github.com/OpenZWave/qt-openzwave.git && cd qt-openzwave && /opt/qt512/bin/qmake -r && make -j4 && make install +cd /opt +git clone https://github.com/OpenZWave/ozw-admin.git && cd ozw-admin && git checkout buildfixes && /opt/qt512/bin/qmake -r && make -j4 && make install +cd /opt +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib64 +export QMAKE=/opt/qt512/bin/qmake +export VERSION=0.1 +cd ozw-admin && ../linuxdeploy-x86_64.AppImage --appdir AppDir -e ozwadmin --plugin qt --output appimage -d scripts/ozwadmin.desktop -i scripts/ozwadmin.png +cp /opt/ozw-admin/OZWAdmin-*.AppImage /opt/buildfiles/ +chown $DOCKERUSERID:$DOCKERGROUPID /opt/buildfiles/OZWAdmin-*.AppImage diff --git a/scripts/dmgbuild.py b/scripts/dmgbuild.py new file mode 100644 index 0000000..d1af1ca --- /dev/null +++ b/scripts/dmgbuild.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import biplist +import os.path + +# +# Example settings file for dmgbuild +# + +# Use like this: dmgbuild -s settings.py "Test Volume" test.dmg + +# You can actually use this file for your own application (not just TextEdit) +# by doing e.g. +# +# dmgbuild -s settings.py -D app=/path/to/My.app "My Application" MyApp.dmg + +# .. Useful stuff .............................................................. + +application = defines.get('app', '../ozwadmin.app') +appname = os.path.basename(application) + +def icon_from_app(app_path): + plist_path = os.path.join(app_path, 'Contents', 'Info.plist') + plist = biplist.readPlist(plist_path) + icon_name = plist['CFBundleIconFile'] + icon_root,icon_ext = os.path.splitext(icon_name) + if not icon_ext: + icon_ext = '.icns' + icon_name = icon_root + icon_ext + return os.path.join(app_path, 'Contents', 'Resources', icon_name) + +# .. Basics .................................................................... + +# Uncomment to override the output filename +# filename = 'test.dmg' + +# Uncomment to override the output volume name +# volume_name = 'Test' + +# Volume format (see hdiutil create -help) +format = defines.get('format', 'UDBZ') + +# Compression level (if relevant) +# compression_level = 9 + +# Volume size +size = defines.get('size', None) + +# Files to include +files = [ application ] + +# Symlinks to create +symlinks = { 'Applications': '/Applications' } + +# Volume icon +# +# You can either define icon, in which case that icon file will be copied to the +# image, *or* you can define badge_icon, in which case the icon file you specify +# will be used to badge the system's Removable Disk icon. Badge icons require +# pyobjc-framework-Quartz. +# +#icon = '/path/to/icon.icns' +badge_icon = icon_from_app(application) + +# Where to put the icons +icon_locations = { + appname: (140, 120), + 'Applications': (500, 120) + } + +# .. Window configuration ...................................................... + +# Background +# +# This is a STRING containing any of the following: +# +# #3344ff - web-style RGB color +# #34f - web-style RGB color, short form (#34f == #3344ff) +# rgb(1,0,0) - RGB color, each value is between 0 and 1 +# hsl(120,1,.5) - HSL (hue saturation lightness) color +# hwb(300,0,0) - HWB (hue whiteness blackness) color +# cmyk(0,1,0,0) - CMYK color +# goldenrod - X11/SVG named color +# builtin-arrow - A simple built-in background with a blue arrow +# /foo/bar/baz.png - The path to an image file +# +# The hue component in hsl() and hwb() may include a unit; it defaults to +# degrees ('deg'), but also supports radians ('rad') and gradians ('grad' +# or 'gon'). +# +# Other color components may be expressed either in the range 0 to 1, or +# as percentages (e.g. 60% is equivalent to 0.6). +background = 'builtin-arrow' + +show_status_bar = False +show_tab_view = False +show_toolbar = False +show_pathbar = False +show_sidebar = False +sidebar_width = 180 + +# Window position in ((x, y), (w, h)) format +window_rect = ((100, 100), (640, 280)) + +# Select the default view; must be one of +# +# 'icon-view' +# 'list-view' +# 'column-view' +# 'coverflow' +# +default_view = 'icon-view' + +# General view configuration +show_icon_preview = False + +# Set these to True to force inclusion of icon/list view settings (otherwise +# we only include settings for the default view) +include_icon_view_settings = 'auto' +include_list_view_settings = 'auto' + +# .. Icon view configuration ................................................... + +arrange_by = None +grid_offset = (0, 0) +grid_spacing = 100 +scroll_position = (0, 0) +label_pos = 'bottom' # or 'right' +text_size = 16 +icon_size = 128 + +# .. List view configuration ................................................... + +# Column names are as follows: +# +# name +# date-modified +# date-created +# date-added +# date-last-opened +# size +# kind +# label +# version +# comments +# +list_icon_size = 16 +list_text_size = 12 +list_scroll_position = (0, 0) +list_sort_by = 'name' +list_use_relative_dates = True +list_calculate_all_sizes = False, +list_columns = ('name', 'date-modified', 'size', 'kind', 'date-added') +list_column_widths = { + 'name': 300, + 'date-modified': 181, + 'date-created': 181, + 'date-added': 181, + 'date-last-opened': 181, + 'size': 97, + 'kind': 115, + 'label': 100, + 'version': 75, + 'comments': 300, + } +list_column_sort_directions = { + 'name': 'ascending', + 'date-modified': 'descending', + 'date-created': 'descending', + 'date-added': 'descending', + 'date-last-opened': 'descending', + 'size': 'descending', + 'kind': 'ascending', + 'label': 'ascending', + 'version': 'ascending', + 'comments': 'ascending', + } + +# .. License configuration ..................................................... + +# Text in the license configuration is stored in the resources, which means +# it gets stored in a legacy Mac encoding according to the language. dmgbuild +# will *try* to convert Unicode strings to the appropriate encoding, *but* +# you should be aware that Python doesn't support all of the necessary encodings; +# in many cases you will need to encode the text yourself and use byte strings +# instead here. + +# Recognized language names are: +# +# af_ZA, ar, be_BY, bg_BG, bn, bo, br, ca_ES, cs_CZ, cy, da_DK, de_AT, de_CH, +# de_DE, dz_BT, el_CY, el_GR, en_AU, en_CA, en_GB, en_IE, en_SG, en_US, eo, +# es_419, es_ES, et_EE, fa_IR, fi_FI, fo_FO, fr_001, fr_BE, fr_CA, fr_CH, +# fr_FR, ga-Latg_IE, ga_IE, gd, grc, gu_IN, gv, he_IL, hi_IN, hr_HR, hu_HU, +# hy_AM, is_IS, it_CH, it_IT, iu_CA, ja_JP, ka_GE, kl, ko_KR, lt_LT, lv_LV, +# mk_MK, mr_IN, mt_MT, nb_NO, ne_NP, nl_BE, nl_NL, nn_NO, pa, pl_PL, pt_BR, +# pt_PT, ro_RO, ru_RU, se, sk_SK, sl_SI, sr_RS, sv_SE, th_TH, to_TO, tr_TR, +# uk_UA, ur_IN, ur_PK, uz_UZ, vi_VN, zh_CN, zh_TW + +license = { + 'default-language': 'en_US', + 'licenses': { + 'en_US': './LICENSE' + }, + } diff --git a/scripts/macdeployqtfix.py b/scripts/macdeployqtfix.py new file mode 100755 index 0000000..29d3810 --- /dev/null +++ b/scripts/macdeployqtfix.py @@ -0,0 +1,395 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +finish the job started by macdeployqtfix +""" + +from subprocess import Popen, PIPE +from string import Template +import os +import sys +import logging +import argparse +import re +from collections import namedtuple + + +QTLIB_NAME_REGEX = r'^(?:@executable_path)?/.*/(Qt[a-zA-Z]*).framework/(?:Versions/\d/)?\1$' +QTLIB_NORMALIZED = r'$prefix/Frameworks/$qtlib.framework/Versions/$qtversion/$qtlib' + +QTPLUGIN_NAME_REGEX = r'^(?:@executable_path)?/.*/[pP]lug[iI]ns/(.*)/(.*).dylib$' +QTPLUGIN_NORMALIZED = r'$prefix/PlugIns/$plugintype/$pluginname.dylib' + +#BREWLIB_REGEX = r'^//usr/local/.*//(.*)' +BREWLIB_REGEX =r'.*(lib.*openzwave.*dylib)' +BREWLIB_NORMALIZED = r'$prefix/Frameworks/$brewlib' + + +class GlobalConfig(object): + logger = None + qtpath = None + exepath = None + + +def run_and_get_output(popen_args): + """Run process and get all output""" + process_output = namedtuple('ProcessOutput', ['stdout', 'stderr', 'retcode']) + try: + GlobalConfig.logger.debug('run_and_get_output({0})'.format(repr(popen_args))) + + proc = Popen(popen_args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = proc.communicate(b'') + proc_out = process_output(stdout, stderr, proc.returncode) + + GlobalConfig.logger.debug('\tprocess_output: {0}'.format(proc_out)) + return proc_out + except Exception as exc: + GlobalConfig.logger.error('\texception: {0}'.format(exc)) + return process_output('', exc.message, -1) + + +def get_dependencies(filename): + """ + input: filename must be an absolute path + Should call `otool` and returns the list of dependencies, unsorted, + unmodified, just the raw list so then we could eventually re-use in other + more specialized functions + """ + GlobalConfig.logger.debug('get_dependencies({0})'.format(filename)) + popen_args = ['otool', '-L', filename] + proc_out = run_and_get_output(popen_args) + deps = [] + if proc_out.retcode == 0: + # some string splitting + deps = [s.strip().split(' ')[0] for s in proc_out.stdout.splitlines()[1:] if s] + # prevent infinite recursion when a binary depends on itself (seen with QtWidgets)... + deps = [s for s in deps if os.path.basename(filename) not in s] + return deps + + +def is_qt_plugin(filename): + """ + Checks if a given file is a qt plugin. + Accepts absolute path as well as path containing @executable_path + """ + qtlib_name_rgx = re.compile(QTPLUGIN_NAME_REGEX) + return qtlib_name_rgx.match(filename) is not None + + +def is_qt_lib(filename): + """ + Checks if a given file is a qt library. + Accepts absolute path as well as path containing @executable_path + """ + qtlib_name_rgx = re.compile(QTLIB_NAME_REGEX) + return qtlib_name_rgx.match(filename) is not None + + +def is_brew_lib(filename): + """ + Checks if a given file is a brew library + Accepts absolute path as well as path containing @executable_path + """ + qtlib_name_rgx = re.compile(BREWLIB_REGEX) + return qtlib_name_rgx.match(filename) is not None + + +def normalize_qtplugin_name(filename): + """ + input: a path to a qt plugin, as returned by otool, that can have this form : + - an absolute path /../plugins/PLUGINTYPE/PLUGINNAME.dylib + - @executable_path/../plugins/PLUGINTYPE/PLUGINNAME.dylib + output: + a tuple (qtlib, abspath, rpath) where: + - qtname is the name of the plugin (libqcocoa.dylib, etc.) + - abspath is the absolute path of the qt lib inside the app bundle of exepath + - relpath is the correct rpath to a qt lib inside the app bundle + """ + + GlobalConfig.logger.debug('normalize_plugin_name({0})'.format(filename)) + + qtplugin_name_rgx = re.compile(QTPLUGIN_NAME_REGEX) + rgxret = qtplugin_name_rgx.match(filename) + if not rgxret: + msg = 'couldn\'t normalize a non-qt plugin filename: {0}'.format(filename) + GlobalConfig.logger.critical(msg) + raise Exception(msg) + + # qtplugin normalization settings + qtplugintype = rgxret.groups()[0] + qtpluginname = rgxret.groups()[1] + + templ = Template(QTPLUGIN_NORMALIZED) + + # from qtlib, forge 2 path : + # - absolute path of qt lib in bundle, + abspath = os.path.normpath(templ.safe_substitute( + prefix=os.path.dirname(GlobalConfig.exepath) + '/..', + plugintype=qtplugintype, + pluginname=qtpluginname)) + + # - and rpath containing @executable_path, relative to exepath + rpath = templ.safe_substitute( + prefix='@executable_path/..', + plugintype=qtplugintype, + pluginname=qtpluginname) + + GlobalConfig.logger.debug('\treturns({0})'.format((qtpluginname, abspath, rpath))) + return qtpluginname, abspath, rpath + + +def normalize_qtlib_name(filename): + """ + input: a path to a qt library, as returned by otool, that can have this form : + - an absolute path /lib/xxx/yyy + - @executable_path/../Frameworks/QtSerialPort.framework/Versions/5/QtSerialPort + output: + a tuple (qtlib, abspath, rpath) where: + - qtlib is the name of the qtlib (QtCore, QtWidgets, etc.) + - abspath is the absolute path of the qt lib inside the app bundle of exepath + - relpath is the correct rpath to a qt lib inside the app bundle + """ + GlobalConfig.logger.debug('normalize_qtlib_name({0})'.format(filename)) + + qtlib_name_rgx = re.compile(QTLIB_NAME_REGEX) + rgxret = qtlib_name_rgx.match(filename) + if not rgxret: + msg = 'couldn\'t normalize a non-qt lib filename: {0}'.format(filename) + GlobalConfig.logger.critical(msg) + raise Exception(msg) + + # qtlib normalization settings + qtlib = rgxret.groups()[0] + qtversion = 5 + + templ = Template(QTLIB_NORMALIZED) + + # from qtlib, forge 2 path : + # - absolute path of qt lib in bundle, + abspath = os.path.normpath(templ.safe_substitute( + prefix=os.path.dirname(GlobalConfig.exepath) + '/..', + qtlib=qtlib, + qtversion=qtversion)) + + # - and rpath containing @executable_path, relative to exepath + rpath = templ.safe_substitute( + prefix='@executable_path/..', + qtlib=qtlib, + qtversion=qtversion) + + GlobalConfig.logger.debug('\treturns({0})'.format((qtlib, abspath, rpath))) + return qtlib, abspath, rpath + + +def normalize_brew_name(filename): + """ + input: a path to a brew library, as returned by otool, that can have this form : + - an absolute path /usr/local/lib/yyy + output: + a tuple (brewlib, abspath, rpath) where: + - brewlib is the name of the brew lib + - abspath is the absolute path of the qt lib inside the app bundle of exepath + - relpath is the correct rpath to a qt lib inside the app bundle + """ + GlobalConfig.logger.debug('normalize_brew_name({0})'.format(filename)) + + brewlib_name_rgx = re.compile(BREWLIB_REGEX) + rgxret = brewlib_name_rgx.match(filename) + if not rgxret: + msg = 'couldn\'t normalize a brew lib filename: {0}'.format(filename) + GlobalConfig.logger.critical(msg) + raise Exception(msg) + + # brewlib normalization settings + brewlib = rgxret.groups()[0] + templ = Template(BREWLIB_NORMALIZED) + + # from brewlib, forge 2 path : + # - absolute path of qt lib in bundle, + abspath = os.path.normpath(templ.safe_substitute( + prefix=os.path.dirname(GlobalConfig.exepath) + '/..', + brewlib=brewlib)) + + # - and rpath containing @executable_path, relative to exepath + rpath = templ.safe_substitute( + prefix='@executable_path/..', + brewlib=brewlib) + + GlobalConfig.logger.debug('\treturns({0})'.format((brewlib, abspath, rpath))) + return brewlib, abspath, rpath + + +def fix_dependency(binary, dep): + """ + fix 'dep' dependency of 'binary'. 'dep' is a qt library + """ + if is_qt_lib(dep): + qtname, dep_abspath, dep_rpath = normalize_qtlib_name(dep) + elif is_qt_plugin(dep): + qtname, dep_abspath, dep_rpath = normalize_qtplugin_name(dep) + elif is_brew_lib(dep): + qtname, dep_abspath, dep_rpath = normalize_brew_name(dep) + else: + return True + + dep_ok = True + # check that rpath of 'dep' inside binary has been correctly set + # (ie: relative to exepath using '@executable_path' syntax) + if dep != dep_rpath: + # dep rpath is not ok + GlobalConfig.logger.info('changing rpath \'{0}\' in binary {1}'.format(dep, binary)) + + # call install_name_tool -change on binary + popen_args = ['install_name_tool', '-change', dep, dep_rpath, binary] + proc_out = run_and_get_output(popen_args) + if proc_out.retcode != 0: + GlobalConfig.logger.error(proc_out.stderr) + dep_ok = False + else: + # call install_name_tool -id on binary + popen_args = ['install_name_tool', '-id', dep_rpath, binary] + proc_out = run_and_get_output(popen_args) + if proc_out.retcode != 0: + GlobalConfig.logger.error(proc_out.stderr) + dep_ok = False + + # now ensure that 'dep' exists at the specified path, relative to bundle + if False and dep_ok and not os.path.exists(dep_abspath): + + # ensure destination directory exists + GlobalConfig.logger.info('ensuring directory \'{0}\' exists: {0}'. + format(os.path.dirname(dep_abspath))) + popen_args = ['mkdir', '-p', os.path.dirname(dep_abspath)] + proc_out = run_and_get_output(popen_args) + if proc_out.retcode != 0: + GlobalConfig.logger.info(proc_out.stderr) + dep_ok = False + else: + # copy missing dependency into bundle + qtnamesrc = os.path.join(GlobalConfig.qtpath, 'lib', '{0}.framework'. + format(qtname), qtname) + GlobalConfig.logger.info('copying missing dependency in bundle: {0}'. + format(qtname)) + popen_args = ['cp', qtnamesrc, dep_abspath] + proc_out = run_and_get_output(popen_args) + if proc_out.retcode != 0: + GlobalConfig.logger.info(proc_out.stderr) + dep_ok = False + else: + # ensure permissions are correct if we ever have to change its rpath + GlobalConfig.logger.info('ensuring 755 perm to {0}'.format(dep_abspath)) + popen_args = ['chmod', '755', dep_abspath] + proc_out = run_and_get_output(popen_args) + if proc_out.retcode != 0: + GlobalConfig.logger.info(proc_out.stderr) + dep_ok = False + else: + GlobalConfig.logger.debug('{0} is at correct location in bundle'.format(qtname)) + + if dep_ok: + return fix_binary(dep_abspath) + return False + + +def fix_binary(binary): + """ + input: + binary: relative or absolute path (no @executable_path syntax) + process: + - first fix the rpath for the qt libs on which 'binary' depend + - copy into the bundle of exepath the eventual libraries that are missing + - (create the soft links) needed ? + - do the same for all qt dependencies of binary (recursive) + """ + GlobalConfig.logger.debug('fix_binary({0})'.format(binary)) + + # loop on 'binary' dependencies + for dep in get_dependencies(binary): + if not fix_dependency(binary, dep): + GlobalConfig.logger.error('quitting early: couldn\'t fix dependency {0} of {1}'.format(dep, binary)) + return False + return True + + +def fix_main_binaries(): + """ + list the main binaries of the app bundle and fix them + """ + # deduce bundle path + bundlepath = os.path.sep.join(GlobalConfig.exepath.split(os.path.sep)[0:-3]) + + # fix main binary + GlobalConfig.logger.info('fixing executable \'{0}\''.format(GlobalConfig.exepath)) + if fix_binary(GlobalConfig.exepath): + GlobalConfig.logger.info('fixing plugins') + for root, dummy, files in os.walk(bundlepath): + for name in [f for f in files if os.path.splitext(f)[1] == '.dylib']: + GlobalConfig.logger.info('fixing plugin {0}'.format(name)) + if not fix_binary(os.path.join(root, name)): + return False + return True + + +def main(): + descr = """finish the job started by macdeployqt! + - find dependencies/rpaths with otool + - copy missed dependencies with cp and mkdir + - fix missed rpaths with install_name_tool + + exit codes: + - 0 : success + - 1 : error + """ + + parser = argparse.ArgumentParser(description=descr, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('exepath', + help='path to the binary depending on Qt') + parser.add_argument('qtpath', + help='path of Qt libraries used to build the Qt application') + parser.add_argument('-q', '--quiet', action='store_true', default=False, + help='do not create log on standard output') + parser.add_argument('-nl', '--no-log-file', action='store_true', default=False, + help='do not create log file \'./macdeployqtfix.log\'') + parser.add_argument('-v', '--verbose', action='store_true', default=False, + help='produce more log messages(debug log)') + args = parser.parse_args() + + # globals + GlobalConfig.qtpath = os.path.normpath(args.qtpath) + GlobalConfig.exepath = args.exepath + GlobalConfig.logger = logging.getLogger() + + # configure logging + ################### + + # create formatter + formatter = logging.Formatter('%(levelname)s | %(message)s') + # create console GlobalConfig.logger + if not args.quiet: + chdlr = logging.StreamHandler(sys.stdout) + chdlr.setFormatter(formatter) + GlobalConfig.logger.addHandler(chdlr) + + # create file GlobalConfig.logger + if not args.no_log_file: + fhdlr = logging.FileHandler('./macdeployqtfix.log', mode='w') + fhdlr.setFormatter(formatter) + GlobalConfig.logger.addHandler(fhdlr) + + if args.no_log_file and args.quiet: + GlobalConfig.logger.addHandler(logging.NullHandler()) + else: + GlobalConfig.logger.setLevel(logging.DEBUG if args.verbose else logging.INFO) + + if fix_main_binaries(): + GlobalConfig.logger.info('macdeployqtfix terminated with success') + ret = 0 + else: + GlobalConfig.logger.error('macdeployqtfix terminated with error') + ret = 1 + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/ozwadmin.desktop b/scripts/ozwadmin.desktop new file mode 100644 index 0000000..8e70a72 --- /dev/null +++ b/scripts/ozwadmin.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=OZWAdmin +Comment=OpenZWave Administration Gui +Exec=ozwadmin +Type=Application +Icon=ozwadmin +Categories=System; +MimeType=application/x-iso9660-appimage; \ No newline at end of file diff --git a/scripts/ozwadmin.png b/scripts/ozwadmin.png new file mode 100644 index 0000000..c5c5450 Binary files /dev/null and b/scripts/ozwadmin.png differ diff --git a/scripts/win32build.bat b/scripts/win32build.bat index 9a9fd89..3049fb1 100644 --- a/scripts/win32build.bat +++ b/scripts/win32build.bat @@ -1,6 +1,7 @@ @echo off cd ..\open-zwave msbuild /p:Configuration=ReleaseDLL /p:Platform=Win32 cpp\build\windows\vs2010\OpenZWave.sln +msbuild /p:Configuration=DebugDLL /p:Platform=Win32 cpp\build\windows\vs2010\OpenZWave.sln cd ..\qt-openzwave qmake -r -tp vc msbuild /p:Configuration=Release /p:Platform=Win32 qt-openzwave.sln