Adding upstream version 0.8.0.

Signed-off-by: Alf Gaida <agaida@siduction.org>
upstream/0.8.0
Alf Gaida 7 years ago
parent 3dd6a3a09b
commit 40a821452c
No known key found for this signature in database
GPG Key ID: CD280A0B4D72827C

2
.gitignore vendored

@ -1,2 +0,0 @@
*.pro.user*
src/translations/qterminal

@ -1,7 +1,53 @@
qterminal-0.7.1 / 2016-12-21 qterminal-0.8.0 / 2017-10-21
============================ ============================
* Set version to 0.8.0
* Update information on distribution package
* Added legacy font setting support
* Made font in settings file human readable
* Fix action inconsistency when switching tabs
* Lithuanian translation
* Added Lithuanian language
* Don't export github templates
* correct spelling mistake
* Adapt to QTermWidget API changes after DECSCUSR handling
* liblxqt dont make sense here
* Copied issue template
* Drops Qt5Core_VERSION_STRING
* Update qterminal_drop.desktop
* Update qterminal.desktop
* Make disabled actions consistent at all times (#331)
* DBus DropMode (#325)
* Change subterminal shortcuts to avoid breaking qtermwidget scrolling (#327)
* Update main.cpp (#322)
* Fix toggle menu action.
* Focus highlight (#266)
* Replace numbered terminals with directional navigation (#255)
* Fix '1 Terminal' preset (#324)
* Change "Clear Current Tab" into "Clear Active Terminal" (#268)
* Fix duplicated items, rework MainWindow memory-management (#313)
* Fixed comment - needless compiler warnings are annoying (#321)
* DBus integration (#307)
* Restore filter actions (#310)
* New features: trim \n from pasted strings, confirm multiline pastes (#309)
* Support custom QSS styles
* Call QApp destructor (#306)
* Fixes (#318)
* Refactor dangling actions, delete windows on close
* Adds superbuild support
* Improve translation (.ts) handling
* Removes Qt5X11Extras_DEFINITIONS
* Stops adding not exist entries to CMAKE_MODULE_PATH
* Use the LXQtCompilerSettings module
* Adapt to QTermWidget improved CMake
* Fix a copy/paste error from 4afcc4d0d0922f526f89aadf16ec0517f6b5267e
* Update dependencies and cleanup trailing spaces
0.7.1 / 2016-12-21
==================
* Release 0.7.1: Update changelog
* Bump patch version (#294) * Bump patch version (#294)
* Add common shortcuts for switching tabs (#275) * Add common shortcuts for switching tabs (#275)
* Fix tabstop order in properties dialog & add buddy relations for labels. (#290) * Fix tabstop order in properties dialog & add buddy relations for labels. (#290)

@ -4,29 +4,16 @@ project(qterminal)
include(GNUInstallDirs) include(GNUInstallDirs)
set(STR_VERSION "0.7.1") # qterminal version
set(LXQTBT_MINIMUM_VERSION "0.3.0") set(STR_VERSION "0.8.0")
set(LXQTBT_MINIMUM_VERSION "0.4.0")
option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF)
# additional cmake files
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
endif() endif()
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(FATAL "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. C++11 support is required")
endif()
# we need qpa/qplatformnativeinterface.h for global shortcut # we need qpa/qplatformnativeinterface.h for global shortcut
find_package(Qt5Gui REQUIRED) find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED) find_package(Qt5Widgets REQUIRED)
@ -34,13 +21,13 @@ find_package(Qt5LinguistTools REQUIRED)
if(APPLE) if(APPLE)
elseif(UNIX) elseif(UNIX)
find_package(Qt5X11Extras REQUIRED) find_package(Qt5X11Extras REQUIRED)
find_package(Qt5DBus)
endif() endif()
find_package(QTermWidget5 REQUIRED) find_package(QTermWidget5 REQUIRED)
find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED) find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED)
include(LXQtTranslateTs) include(LXQtTranslateTs)
message(STATUS "Qt version: ${Qt5Core_VERSION_STRING}") include(LXQtCompilerSettings NO_POLICY_SCOPE)
message(STATUS "Qt version: ${Qt5Core_VERSION}")
include(${QTERMWIDGET_USE_FILE})
# TODO remove Qxt # TODO remove Qxt
message(STATUS "Using bundled Qxt...") message(STATUS "Using bundled Qxt...")
@ -56,8 +43,6 @@ elseif(UNIX)
endif() endif()
add_definitions(-DSTR_VERSION=\"${STR_VERSION}\") add_definitions(-DSTR_VERSION=\"${STR_VERSION}\")
add_definitions(${Qt5X11Extras_DEFINITIONS})
set(EXE_NAME qterminal) set(EXE_NAME qterminal)
@ -67,13 +52,16 @@ set(QTERM_SRC
src/tabwidget.cpp src/tabwidget.cpp
src/termwidget.cpp src/termwidget.cpp
src/termwidgetholder.cpp src/termwidgetholder.cpp
src/terminalconfig.cpp
src/properties.cpp src/properties.cpp
src/propertiesdialog.cpp src/propertiesdialog.cpp
src/bookmarkswidget.cpp src/bookmarkswidget.cpp
src/fontdialog.cpp src/fontdialog.cpp
src/dbusaddressable.cpp
) )
set(QTERM_MOC_SRC set(QTERM_MOC_SRC
src/qterminalapp.h
src/mainwindow.h src/mainwindow.h
src/tabwidget.h src/tabwidget.h
src/termwidget.h src/termwidget.h
@ -83,6 +71,17 @@ set(QTERM_MOC_SRC
src/fontdialog.h src/fontdialog.h
) )
if (Qt5DBus_FOUND)
add_definitions(-DHAVE_QDBUS)
QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Window.xml mainwindow.h MainWindow)
QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Tab.xml termwidgetholder.h TermWidgetHolder)
QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Terminal.xml termwidget.h TermWidget)
QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Process.xml qterminalapp.h QTerminalApp)
set(QTERM_MOC_SRC ${QTERM_MOC_SRC} src/dbusaddressable.h)
message(STATUS "Building with Qt5DBus support")
endif()
if(NOT QXT_FOUND) if(NOT QXT_FOUND)
set(QTERM_SRC ${QTERM_SRC} src/third-party/qxtglobalshortcut.cpp) set(QTERM_SRC ${QTERM_SRC} src/third-party/qxtglobalshortcut.cpp)
set(QTERM_MOC_SRC ${QTERM_MOC_SRC} src/third-party/qxtglobalshortcut.h) set(QTERM_MOC_SRC ${QTERM_MOC_SRC} src/third-party/qxtglobalshortcut.h)
@ -111,6 +110,12 @@ qt5_wrap_ui( QTERM_UI ${QTERM_UI_SRC} )
qt5_wrap_cpp( QTERM_MOC ${QTERM_MOC_SRC} ) qt5_wrap_cpp( QTERM_MOC ${QTERM_MOC_SRC} )
qt5_add_resources( QTERM_RCC ${QTERM_RCC_SRC} ) qt5_add_resources( QTERM_RCC ${QTERM_RCC_SRC} )
lxqt_translate_ts(QTERM_QM lxqt_translate_ts(QTERM_QM
UPDATE_TRANSLATIONS
${UPDATE_TRANSLATIONS}
SOURCES
${QTERM_SRC}
${QTERM_UI_SRC}
${QTERM_MOC_SRC}
TRANSLATION_DIR "src/translations" TRANSLATION_DIR "src/translations"
PULL_TRANSLATIONS PULL_TRANSLATIONS
${PULL_TRANSLATIONS} ${PULL_TRANSLATIONS}
@ -123,10 +128,9 @@ lxqt_translate_ts(QTERM_QM
) )
include_directories( include_directories(
"${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/src" "${PROJECT_SOURCE_DIR}/src"
"${CMAKE_BINARY_DIR}" "${PROJECT_BINARY_DIR}"
${QTERMWIDGET_INCLUDE_DIRS}
${QXT_INCLUDE_DIRS} ${QXT_INCLUDE_DIRS}
) )
if(X11_FOUND) if(X11_FOUND)
@ -170,14 +174,18 @@ add_executable(${EXE_NAME} ${GUI_TYPE}
${QTERM_QM} ${QTERM_QM}
) )
target_link_libraries(${EXE_NAME} target_link_libraries(${EXE_NAME}
${QTERMWIDGET_QT_LIBRARIES} Qt5::Gui
${QTERMWIDGET_LIBRARIES} qtermwidget5
util util
) )
if(QXT_FOUND) if(QXT_FOUND)
target_link_libraries(${EXE_NAME} ${QXT_CORE_LIB} ${QXT_GUI_LIB}) target_link_libraries(${EXE_NAME} ${QXT_CORE_LIB} ${QXT_GUI_LIB})
endif() endif()
if (Qt5DBus_FOUND)
target_link_libraries(${EXE_NAME} ${Qt5DBus_LIBRARIES})
endif()
if(APPLE) if(APPLE)
target_link_libraries(${EXE_NAME} ${CARBON_LIBRARY}) target_link_libraries(${EXE_NAME} ${CARBON_LIBRARY})
elseif(UNIX) elseif(UNIX)
@ -226,12 +234,3 @@ else()
install(FILES ${QTERM_QM} DESTINATION ${CMAKE_INSTALL_PREFIX}/${EXE_NAME}.app/Contents/translations) install(FILES ${QTERM_QM} DESTINATION ${CMAKE_INSTALL_PREFIX}/${EXE_NAME}.app/Contents/translations)
endif() endif()
# make lupdate
# it generates new translation files
add_custom_target(lupdate
${QT_QMAKE_EXECUTABLE} -project -o "${CMAKE_CURRENT_BINARY_DIR}/qterminal.pro"
COMMAND ${QT_LUPDATE_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/qterminal.pro"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)

@ -282,7 +282,7 @@ TYPEDEF_HIDES_STRUCT = NO
# causing a significant performance penality. # causing a significant performance penality.
# If the system has enough physical memory increasing the cache will improve the # 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 # performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will rougly double the # a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula: # 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, # 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 # corresponding to a cache size of 2^16 = 65536 symbols

@ -2,24 +2,24 @@
## Overview ## Overview
QTerminal is a lightweight Qt terminal emulator based on [QTermWidget](https://github.com/lxde/qtermwidget). QTerminal is a lightweight Qt terminal emulator based on [QTermWidget](https://github.com/lxde/qtermwidget).
It is maintained by the LXQt project but can be used independently from this desktop environment. The only bonds are [liblxqt](https://github.com/lxde/liblxqt) representing a build dependency and the localization files which were outsourced to LXQt repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n). It is maintained by the LXQt project but can be used independently from this desktop environment. The only bonds are [lxqt-build-tools](https://github.com/lxde/lxqt-build-tools) representing a build dependency and the localization files which were outsourced to LXQt repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n).
This project is licensed under the terms of the [GPLv2](https://www.gnu.org/licenses/gpl-2.0.en.html) or any later version. See the LICENSE file for the full text of the license. This project is licensed under the terms of the [GPLv2](https://www.gnu.org/licenses/gpl-2.0.en.html) or any later version. See the LICENSE file for the full text of the license.
## Installation ## Installation
### Compiling sources ### Compiling sources
Runtime dependencies are qtx11extras ≥ 5.2 and [QTermWidget](https://github.com/lxde/qtermwidget). Dependencies are qtx11extras ≥ 5.2 and [QTermWidget](https://github.com/lxde/qtermwidget).
In order to build CMake ≥ 3.0.2 and [liblxqt](https://github.com/lxde/liblxqt) are needed as well as optionally Git to pull latest VCS checkouts. The localization files were outsourced to repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n) so the corresponding dependencies are needed, too. Please refer to this repository's `README.md` for further information. In order to build CMake ≥ 3.0.2 and [lxqt-build-tools](https://github.com/lxde/lxqt-build-tools) are needed as well as optionally Git to pull latest VCS checkouts. The localization files were outsourced to repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n) so the corresponding dependencies are needed, too. Please refer to this repository's `README.md` for further information.
Code configuration is handled by CMake. Building out of source is strongly recommended. CMake variable `CMAKE_INSTALL_PREFIX` will normally have to be set to `/usr`. Code configuration is handled by CMake. Building out of source is strongly recommended. CMake variable `CMAKE_INSTALL_PREFIX` will normally have to be set to `/usr`.
To build run `make`, to install `make install` which accepts variable `DESTDIR` as usual. To build run `make`, to install `make install` which accepts variable `DESTDIR` as usual.
### Binary packages ### Binary packages
QTerminal is provided by all major Linux distributions like Arch Linux ([AUR](https://aur.archlinux.org) only so far), Debian (as of Debian stretch), Fedora and openSUSE (Tumbleweed only so far). QTerminal is provided by all major Linux distributions like [Arch Linux](https://www.archlinux.org/packages/?q=qterminal), Debian (as of Debian stretch), Fedora and openSUSE.
Just use the distributions' package managers to search for string `qterminal`. Just use the distributions' package managers to search for string `qterminal`.

@ -7,6 +7,8 @@ Comment=Terminal emulator
Comment[de]=Befehlszeile verwenden Comment[de]=Befehlszeile verwenden
Comment[el]=Προσομοιωτής τερματικού Comment[el]=Προσομοιωτής τερματικού
Comment[fr]=Terminal Comment[fr]=Terminal
Comment[lt]=Terminalo emuliatorius
Comment[pl]=Emulator terminala
Comment[pt]=Emulador de terminal Comment[pt]=Emulador de terminal
Comment[pt_BR]=Emulador de terminal Comment[pt_BR]=Emulador de terminal
Comment[ru_RU]=Эмулятор терминала Comment[ru_RU]=Эмулятор терминала
@ -40,10 +42,12 @@ Name[it]=Terminale a discesa
Name[ja]=ドロップダウン式ターミナル Name[ja]=ドロップダウン式ターミナル
Name[km]=ស្ថានីយ​ទម្លាក់​ចុះ Name[km]=ស្ថានីយ​ទម្លាក់​ចុះ
Name[ko]=위에서 내려오는 터미널 Name[ko]=위에서 내려오는 터미널
Name[lt]=Išskleidžiamasis terminalas
Name[nb]=Nedtrekksterminal Name[nb]=Nedtrekksterminal
Name[nds]=Utklapp-Konsool Name[nds]=Utklapp-Konsool
Name[nl]=Uitvouwbare terminalemulator Name[nl]=Uitvouwbare terminalemulator
Name[pa]=ਲਟਕਦਾ ਟਰਮੀਨਲ Name[pa]=ਲਟਕਦਾ ਟਰਮੀਨਲ
Name[pl]=Rozwijany emulator terminala
Name[pt]=Terminal suspenso Name[pt]=Terminal suspenso
Name[pt_BR]=Terminal suspenso Name[pt_BR]=Terminal suspenso
Name[ro]=Terminal derulant Name[ro]=Terminal derulant

@ -8,6 +8,8 @@ Icon=utilities-terminal
Name=QTerminal drop down Name=QTerminal drop down
Name[de]=QTerminal herabhängend Name[de]=QTerminal herabhängend
Name[el]=QTerminal αναπτυσσόμενο Name[el]=QTerminal αναπτυσσόμενο
Name[lt]=QTerminal išskleidžiamasis
Name[pl]=QTerminal (tryb rozwijany)
Name[pt]=QTerminal suspenso Name[pt]=QTerminal suspenso
Name[pt_BR]=QTerminal suspenso Name[pt_BR]=QTerminal suspenso
Name[ja]=QTerminal ドロップダウン Name[ja]=QTerminal ドロップダウン
@ -30,10 +32,12 @@ GenericName[it]=Terminale a discesa
GenericName[ja]=ドロップダウン式ターミナル GenericName[ja]=ドロップダウン式ターミナル
GenericName[km]=ស្ថានីយ​ទម្លាក់​ចុះ GenericName[km]=ស្ថានីយ​ទម្លាក់​ចុះ
GenericName[ko]=위에서 내려오는 터미널 GenericName[ko]=위에서 내려오는 터미널
GenericName[lt]=Išskleidžiamasis terminalas
GenericName[nb]=Nedtrekksterminal GenericName[nb]=Nedtrekksterminal
GenericName[nds]=Utklapp-Konsool GenericName[nds]=Utklapp-Konsool
GenericName[nl]=Uitvouwbare terminalemulator GenericName[nl]=Uitvouwbare terminalemulator
GenericName[pa]=ਲਟਕਦਾ ਟਰਮੀਨਲ GenericName[pa]=ਲਟਕਦਾ ਟਰਮੀਨਲ
GenericName[pl]=Rozwijany emulator terminala
GenericName[pt]=Terminal suspenso GenericName[pt]=Terminal suspenso
GenericName[pt_BR]=Terminal suspenso GenericName[pt_BR]=Terminal suspenso
GenericName[ro]=Terminal derulant GenericName[ro]=Terminal derulant
@ -50,6 +54,7 @@ GenericName[zh_TW]=下拉式終端機
Comment=A drop-down terminal emulator. Comment=A drop-down terminal emulator.
Comment[de]=Ein Ausklapp-Terminalemulator. Comment[de]=Ein Ausklapp-Terminalemulator.
Comment[el]=Ένας αναπτυσσόμενος προσομοιωτής τερματικού. Comment[el]=Ένας αναπτυσσόμενος προσομοιωτής τερματικού.
Comment[lt]=Išskleidžiamasis terminalo emuliatorius.
Comment[pt]=Um emulador de terminal suspenso. Comment[pt]=Um emulador de terminal suspenso.
Comment[pt_BR]=Um emulador de terminal suspenso. Comment[pt_BR]=Um emulador de terminal suspenso.
Comment[ru]=Вападающий эмулятор терминала. Comment[ru]=Вападающий эмулятор терминала.

@ -140,7 +140,7 @@ public:
// system env - include dirs in the tree // system env - include dirs in the tree
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
foreach (QString i, env.keys()) foreach (const QString &i, env.keys())
{ {
path = env.value(i); path = env.value(i);
if (!d.exists(path) || !QFileInfo(path).isDir()) if (!d.exists(path) || !QFileInfo(path).isDir())
@ -217,7 +217,7 @@ public:
break; break;
} }
case QXmlStreamReader::Invalid: case QXmlStreamReader::Invalid:
qDebug() << "XML error: " << xml.errorString().data() qDebug() << "XML error: " << xml.errorString().constData()
<< xml.lineNumber() << xml.columnNumber(); << xml.lineNumber() << xml.columnNumber();
m_map.clear(); m_map.clear();
return; return;

@ -37,8 +37,10 @@
#define SPLIT_VERTICAL "Split Terminal Vertically" #define SPLIT_VERTICAL "Split Terminal Vertically"
#define SUB_COLLAPSE "Collapse Subterminal" #define SUB_COLLAPSE "Collapse Subterminal"
#define SUB_NEXT "Next Subterminal" #define SUB_LEFT "Left Subterminal"
#define SUB_PREV "Previous Subterminal" #define SUB_RIGHT "Right Subterminal"
#define SUB_TOP "Top Subterminal"
#define SUB_BOTTOM "Bottom Subterminal"
#define MOVE_LEFT "Move Tab Left" #define MOVE_LEFT "Move Tab Left"
#define MOVE_RIGHT "Move Tab Right" #define MOVE_RIGHT "Move Tab Right"
@ -69,10 +71,13 @@
// ACTIONS // ACTIONS
#define CLEAR_TERMINAL_SHORTCUT "Ctrl+Shift+X" #define CLEAR_TERMINAL_SHORTCUT "Ctrl+Shift+X"
#define TAB_PREV_SHORTCUT "Shift+Left|Ctrl+PgUp|Ctrl+Shift+Tab"
#define TAB_NEXT_SHORTCUT "Shift+Right|Ctrl+PgDown|Ctrl+Tab" #define TAB_PREV_SHORTCUT "Ctrl+PgUp|Ctrl+Shift+Tab"
#define SUB_PREV_SHORTCUT "Shift+Down" #define TAB_NEXT_SHORTCUT "Ctrl+PgDown|Ctrl+Tab"
#define SUB_NEXT_SHORTCUT "Shift+Up" #define SUB_BOTTOM_SHORTCUT "Alt+Down"
#define SUB_TOP_SHORTCUT "Alt+Up"
#define SUB_LEFT_SHORTCUT "Alt+Left"
#define SUB_RIGHT_SHORTCUT "Alt+Right"
#ifdef Q_WS_MAC #ifdef Q_WS_MAC
// It's tricky - Ctrl is "command" key on mac's keyboards // It's tricky - Ctrl is "command" key on mac's keyboards

@ -0,0 +1,25 @@
#include "dbusaddressable.h"
#ifdef HAVE_QDBUS
Q_DECLARE_METATYPE(QList<QDBusObjectPath>)
QString DBusAddressable::getDbusPathString()
{
return m_path;
}
QDBusObjectPath DBusAddressable::getDbusPath()
{
return QDBusObjectPath(m_path);
}
#endif
DBusAddressable::DBusAddressable(QString prefix)
{
#ifdef HAVE_QDBUS
QString uuidString = QUuid::createUuid().toString();
m_path = prefix + "/" + uuidString.replace(QRegExp("[\\{\\}\\-]"), "");
#endif
}

@ -0,0 +1,34 @@
#ifndef DBUSADDRESSABLE_H
#define DBUSADDRESSABLE_H
#include <QString>
#ifdef HAVE_QDBUS
#include <QtDBus/QtDBus>
#include <QUuid>
#endif
class DBusAddressable
{
#ifdef HAVE_QDBUS
private:
QString m_path;
#endif
public:
#ifdef HAVE_QDBUS
QDBusObjectPath getDbusPath();
QString getDbusPathString();
#endif
DBusAddressable(QString prefix);
};
#ifdef HAVE_QDBUS
template <class AClass, class WClass> void registerAdapter(WClass *obj)
{
new AClass(obj);
QString path = dynamic_cast<DBusAddressable*>(obj)->getDbusPathString();
QDBusConnection::sessionBus().registerObject(path, obj);
}
#endif
#endif

@ -423,6 +423,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="confirmMultilinePasteCheckBox">
<property name="text">
<string>Confirm multiline paste</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QCheckBox" name="trimPastedTrailingNewlinesCheckBox">
<property name="text">
<string>Trim trailing newlines in pasted text</string>
</property>
</widget>
</item>
<item row="0" column="2"> <item row="0" column="2">
<widget class="QSpinBox" name="historyLimitedTo"> <widget class="QSpinBox" name="historyLimitedTo">
<property name="minimum"> <property name="minimum">
@ -436,7 +450,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="9" column="1">
<spacer name="verticalSpacer_4"> <spacer name="verticalSpacer_4">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@ -449,28 +463,28 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="6" column="0" colspan="3"> <item row="8" column="0" colspan="3">
<widget class="QCheckBox" name="useCwdCheckBox"> <widget class="QCheckBox" name="useCwdCheckBox">
<property name="text"> <property name="text">
<string>Open new terminals in current working directory</string> <string>Open new terminals in current working directory</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="3"> <item row="7" column="0" colspan="3">
<widget class="QCheckBox" name="saveSizeOnExitCheckBox"> <widget class="QCheckBox" name="saveSizeOnExitCheckBox">
<property name="text"> <property name="text">
<string>Save Size when closing</string> <string>Save Size when closing</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="3"> <item row="6" column="0" colspan="3">
<widget class="QCheckBox" name="savePosOnExitCheckBox"> <widget class="QCheckBox" name="savePosOnExitCheckBox">
<property name="text"> <property name="text">
<string>Save Position when closing</string> <string>Save Position when closing</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="3"> <item row="5" column="0" colspan="3">
<widget class="QCheckBox" name="askOnExitCheckBox"> <widget class="QCheckBox" name="askOnExitCheckBox">
<property name="text"> <property name="text">
<string>Ask for confirmation when closing</string> <string>Ask for confirmation when closing</string>

@ -111,21 +111,6 @@
<string>About &amp;Qt...</string> <string>About &amp;Qt...</string>
</property> </property>
</action> </action>
<action name="actProperties">
<property name="text">
<string>&amp;Preferences...</string>
</property>
</action>
<action name="actQuit">
<property name="icon">
<iconset theme="application-exit">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>&amp;Quit</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

@ -19,11 +19,20 @@
#include <QApplication> #include <QApplication>
#include <QtGlobal> #include <QtGlobal>
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <getopt.h> #include <getopt.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_QDBUS
#include <QtDBus/QtDBus>
#include <unistd.h>
#include "processadaptor.h"
#endif
#include "mainwindow.h" #include "mainwindow.h"
#include "qterminalapp.h"
#include "terminalconfig.h"
#define out #define out
@ -39,6 +48,8 @@ const struct option long_options[] = {
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
QTerminalApp * QTerminalApp::m_instance = NULL;
void print_usage_and_exit(int code) void print_usage_and_exit(int code)
{ {
printf("QTerminal %s\n", STR_VERSION); printf("QTerminal %s\n", STR_VERSION);
@ -111,16 +122,35 @@ int main(int argc, char *argv[])
// Warning: do not change settings format. It can screw bookmarks later. // Warning: do not change settings format. It can screw bookmarks later.
QSettings::setDefaultFormat(QSettings::IniFormat); QSettings::setDefaultFormat(QSettings::IniFormat);
QApplication app(argc, argv); QTerminalApp *app = QTerminalApp::Instance(argc, argv);
#ifdef HAVE_QDBUS
app->registerOnDbus();
#endif
QString workdir, shell_command; QString workdir, shell_command;
bool dropMode; bool dropMode;
parse_args(argc, argv, workdir, shell_command, dropMode); parse_args(argc, argv, workdir, shell_command, dropMode);
if (workdir.isEmpty()) if (workdir.isEmpty())
workdir = QDir::currentPath(); workdir = QDir::currentPath();
app->setWorkingDirectory(workdir);
const QSettings settings;
const QFileInfo customStyle = QFileInfo(
QFileInfo(settings.fileName()).canonicalPath() +
"/style.qss"
);
if (customStyle.isFile() && customStyle.isReadable())
{
QFile style(customStyle.canonicalFilePath());
style.open(QFile::ReadOnly);
QString styleString = QLatin1String(style.readAll());
app->setStyleSheet(styleString);
}
// icons // icons
/* setup our custom icon theme if there is no system theme (OS X, Windows) */ /* setup our custom icon theme if there is no system theme (OS X, Windows) */
QCoreApplication::instance()->setAttribute(Qt::AA_UseHighDpiPixmaps); //Fix for High-DPI systems
if (QIcon::themeName().isEmpty()) if (QIcon::themeName().isEmpty())
QIcon::setThemeName("QTerminal"); QIcon::setThemeName("QTerminal");
@ -135,25 +165,151 @@ int main(int argc, char *argv[])
qDebug() << "APPLE_BUNDLE: Loading translator file" << fname << "from dir" << QApplication::applicationDirPath()+"../translations"; qDebug() << "APPLE_BUNDLE: Loading translator file" << fname << "from dir" << QApplication::applicationDirPath()+"../translations";
qDebug() << "load success:" << translator.load(fname, QApplication::applicationDirPath()+"../translations", "_"); qDebug() << "load success:" << translator.load(fname, QApplication::applicationDirPath()+"../translations", "_");
#endif #endif
app.installTranslator(&translator); app->installTranslator(&translator);
MainWindow *window; TerminalConfig initConfig = TerminalConfig(workdir, shell_command);
app->newWindow(dropMode, initConfig);
int ret = app->exec();
delete Properties::Instance();
app->cleanup();
return ret;
}
MainWindow *QTerminalApp::newWindow(bool dropMode, TerminalConfig &cfg)
{
MainWindow *window = NULL;
if (dropMode) if (dropMode)
{ {
QWidget *hiddenPreviewParent = new QWidget(0, Qt::Tool); QWidget *hiddenPreviewParent = new QWidget(0, Qt::Tool);
window = new MainWindow(workdir, shell_command, dropMode, hiddenPreviewParent); window = new MainWindow(cfg, dropMode, hiddenPreviewParent);
if (Properties::Instance()->dropShowOnStart) if (Properties::Instance()->dropShowOnStart)
window->show(); window->show();
} }
else else
{ {
window = new MainWindow(workdir, shell_command, dropMode); window = new MainWindow(cfg, dropMode);
window->show(); window->show();
} }
return window;
}
int ret = app.exec(); QTerminalApp *QTerminalApp::Instance()
delete Properties::Instance(); {
delete window; assert(m_instance != NULL);
return m_instance;
}
return ret; QTerminalApp *QTerminalApp::Instance(int &argc, char **argv)
{
assert(m_instance == NULL);
m_instance = new QTerminalApp(argc, argv);
return m_instance;
}
QTerminalApp::QTerminalApp(int &argc, char **argv)
:QApplication(argc, argv)
{
}
QString &QTerminalApp::getWorkingDirectory()
{
return m_workDir;
} }
void QTerminalApp::setWorkingDirectory(const QString &wd)
{
m_workDir = wd;
}
void QTerminalApp::cleanup() {
delete m_instance;
m_instance = NULL;
}
void QTerminalApp::addWindow(MainWindow *window)
{
m_windowList.append(window);
}
void QTerminalApp::removeWindow(MainWindow *window)
{
m_windowList.removeOne(window);
}
QList<MainWindow *> QTerminalApp::getWindowList()
{
return m_windowList;
}
#ifdef HAVE_QDBUS
void QTerminalApp::registerOnDbus()
{
if (!QDBusConnection::sessionBus().isConnected())
{
fprintf(stderr, "Cannot connect to the D-Bus session bus.\n"
"To start it, run:\n"
"\teval `dbus-launch --auto-syntax`\n");
return;
}
QString serviceName = QStringLiteral("org.lxqt.QTerminal-%1").arg(getpid());
if (!QDBusConnection::sessionBus().registerService(serviceName))
{
fprintf(stderr, "%s\n", qPrintable(QDBusConnection::sessionBus().lastError().message()));
return;
}
new ProcessAdaptor(this);
QDBusConnection::sessionBus().registerObject("/", this);
}
QList<QDBusObjectPath> QTerminalApp::getWindows()
{
QList<QDBusObjectPath> windows;
foreach (MainWindow *wnd, m_windowList)
{
windows.push_back(wnd->getDbusPath());
}
return windows;
}
QDBusObjectPath QTerminalApp::newWindow(const QHash<QString,QVariant> &termArgs)
{
TerminalConfig cfg = TerminalConfig::fromDbus(termArgs);
MainWindow *wnd = newWindow(false, cfg);
assert(wnd != NULL);
return wnd->getDbusPath();
}
QDBusObjectPath QTerminalApp::getActiveWindow()
{
QWidget *aw = activeWindow();
if (aw == NULL)
return QDBusObjectPath("/");
return qobject_cast<MainWindow*>(aw)->getDbusPath();
}
bool QTerminalApp::isDropMode() {
if (m_windowList.count() == 0) {
return false;
}
MainWindow *wnd = m_windowList.at(0);
return wnd->dropMode();
}
bool QTerminalApp::toggleDropdown() {
if (m_windowList.count() == 0) {
return false;
}
MainWindow *wnd = m_windowList.at(0);
if (!wnd->dropMode()) {
return false;
}
wnd->showHide();
return true;
}
#endif

@ -22,6 +22,12 @@
#include <QMessageBox> #include <QMessageBox>
#include <functional> #include <functional>
#ifdef HAVE_QDBUS
#include <QtDBus/QtDBus>
#include "windowadaptor.h"
#endif
#include "terminalconfig.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "tabwidget.h" #include "tabwidget.h"
#include "termwidgetholder.h" #include "termwidgetholder.h"
@ -29,7 +35,8 @@
#include "properties.h" #include "properties.h"
#include "propertiesdialog.h" #include "propertiesdialog.h"
#include "bookmarkswidget.h" #include "bookmarkswidget.h"
#include "qterminalapp.h"
#include "dbusaddressable.h"
typedef std::function<bool(MainWindow&)> checkfn; typedef std::function<bool(MainWindow&)> checkfn;
Q_DECLARE_METATYPE(checkfn) Q_DECLARE_METATYPE(checkfn)
@ -37,18 +44,30 @@ Q_DECLARE_METATYPE(checkfn)
// TODO/FXIME: probably remove. QSS makes it unusable on mac... // TODO/FXIME: probably remove. QSS makes it unusable on mac...
#define QSS_DROP "MainWindow {border: 1px solid rgba(0, 0, 0, 50%);}\n" #define QSS_DROP "MainWindow {border: 1px solid rgba(0, 0, 0, 50%);}\n"
MainWindow::MainWindow(const QString& work_dir, MainWindow::MainWindow(TerminalConfig &cfg,
const QString& command,
bool dropMode, bool dropMode,
QWidget * parent, QWidget * parent,
Qt::WindowFlags f) Qt::WindowFlags f)
: QMainWindow(parent,f), : QMainWindow(parent,f),
m_initShell(command), DBusAddressable("/windows"),
m_initWorkDir(work_dir), tabPosition(NULL),
scrollBarPosition(NULL),
keyboardCursorShape(NULL),
tabPosMenu(NULL),
scrollPosMenu(NULL),
keyboardCursorShapeMenu(NULL),
settingOwner(NULL),
presetsMenu(NULL),
m_config(cfg),
m_dropLockButton(0), m_dropLockButton(0),
m_dropMode(dropMode) m_dropMode(dropMode)
{ {
#ifdef HAVE_QDBUS
registerAdapter<WindowAdaptor, MainWindow>(this);
#endif
QTerminalApp::Instance()->addWindow(this);
setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_DeleteOnClose);
setupUi(this); setupUi(this);
Properties::Instance()->migrate_settings(); Properties::Instance()->migrate_settings();
@ -88,26 +107,39 @@ MainWindow::MainWindow(const QString& work_dir,
consoleTabulator->setAutoFillBackground(true); consoleTabulator->setAutoFillBackground(true);
connect(consoleTabulator, SIGNAL(closeTabNotification()), SLOT(close())); connect(consoleTabulator, SIGNAL(closeTabNotification()), SLOT(close()));
consoleTabulator->setWorkDirectory(work_dir);
consoleTabulator->setTabPosition((QTabWidget::TabPosition)Properties::Instance()->tabsPos); consoleTabulator->setTabPosition((QTabWidget::TabPosition)Properties::Instance()->tabsPos);
//consoleTabulator->setShellProgram(command); //consoleTabulator->setShellProgram(command);
setup_FileMenu_Actions(); // apply props
setup_ActionsMenu_Actions(); propertiesChanged();
setup_ViewMenu_Actions();
setupCustomDirs(); setupCustomDirs();
connect(consoleTabulator, &TabWidget::currentTitleChanged, this, &MainWindow::onCurrentTitleChanged); connect(consoleTabulator, &TabWidget::currentTitleChanged, this, &MainWindow::onCurrentTitleChanged);
connect(menu_Actions, SIGNAL(aboutToShow()), this, SLOT(aboutToShowActionsMenu())); connect(menu_Actions, SIGNAL(aboutToShow()), this, SLOT(updateDisabledActions()));
/* The tab should be added after all changes are made to /* The tab should be added after all changes are made to
the main window; otherwise, the initial prompt might the main window; otherwise, the initial prompt might
get jumbled because of changes in internal geometry. */ get jumbled because of changes in internal geometry. */
consoleTabulator->addNewTab(command); consoleTabulator->addNewTab(m_config);
}
void MainWindow::rebuildActions()
{
// Delete all setting-related QObjects
delete settingOwner;
settingOwner = new QWidget(this);
settingOwner->setGeometry(0,0,0,0);
// Then create them again
setup_FileMenu_Actions();
setup_ActionsMenu_Actions();
setup_ViewMenu_Actions();
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
QTerminalApp::Instance()->removeWindow(this);
} }
void MainWindow::enableDropMode() void MainWindow::enableDropMode()
@ -145,22 +177,22 @@ void MainWindow::setup_Action(const char *name, QAction *action, const char *def
QList<QKeySequence> shortcuts; QList<QKeySequence> shortcuts;
Properties::Instance()->actions[name] = action; actions[name] = action;
foreach (const QString &sequenceString, settings.value(name, defaultShortcut).toString().split('|')) foreach (const QString &sequenceString, settings.value(name, defaultShortcut).toString().split('|'))
shortcuts.append(QKeySequence::fromString(sequenceString)); shortcuts.append(QKeySequence::fromString(sequenceString));
Properties::Instance()->actions[name]->setShortcuts(shortcuts); actions[name]->setShortcuts(shortcuts);
if (receiver) if (receiver)
{ {
connect(Properties::Instance()->actions[name], SIGNAL(triggered(bool)), receiver, slot); connect(actions[name], SIGNAL(triggered(bool)), receiver, slot);
addAction(Properties::Instance()->actions[name]); addAction(actions[name]);
} }
if (menu) if (menu)
menu->addAction(Properties::Instance()->actions[name]); menu->addAction(actions[name]);
if (!data.isNull()) if (!data.isNull())
Properties::Instance()->actions[name]->setData(data); actions[name]->setData(data);
} }
void MainWindow::setup_ActionsMenu_Actions() void MainWindow::setup_ActionsMenu_Actions()
@ -170,68 +202,77 @@ void MainWindow::setup_ActionsMenu_Actions()
const checkfn checkTabs = &MainWindow::hasMultipleTabs; const checkfn checkTabs = &MainWindow::hasMultipleTabs;
const checkfn checkSubterminals = &MainWindow::hasMultipleSubterminals; const checkfn checkSubterminals = &MainWindow::hasMultipleSubterminals;
setup_Action(CLEAR_TERMINAL, new QAction(QIcon::fromTheme("edit-clear"), tr("&Clear Current Tab"), this), menu_Actions->clear();
setup_Action(CLEAR_TERMINAL, new QAction(QIcon::fromTheme("edit-clear"), tr("&Clear Active Terminal"), settingOwner),
CLEAR_TERMINAL_SHORTCUT, consoleTabulator, SLOT(clearActiveTerminal()), menu_Actions); CLEAR_TERMINAL_SHORTCUT, consoleTabulator, SLOT(clearActiveTerminal()), menu_Actions);
menu_Actions->addSeparator(); menu_Actions->addSeparator();
data.setValue(checkTabs); data.setValue(checkTabs);
setup_Action(TAB_NEXT, new QAction(QIcon::fromTheme("go-next"), tr("&Next Tab"), this), setup_Action(TAB_NEXT, new QAction(QIcon::fromTheme("go-next"), tr("&Next Tab"), settingOwner),
TAB_NEXT_SHORTCUT, consoleTabulator, SLOT(switchToRight()), menu_Actions, data); TAB_NEXT_SHORTCUT, consoleTabulator, SLOT(switchToRight()), menu_Actions, data);
setup_Action(TAB_PREV, new QAction(QIcon::fromTheme("go-previous"), tr("&Previous Tab"), this), setup_Action(TAB_PREV, new QAction(QIcon::fromTheme("go-previous"), tr("&Previous Tab"), settingOwner),
TAB_PREV_SHORTCUT, consoleTabulator, SLOT(switchToLeft()), menu_Actions, data); TAB_PREV_SHORTCUT, consoleTabulator, SLOT(switchToLeft()), menu_Actions, data);
setup_Action(MOVE_LEFT, new QAction(tr("Move Tab &Left"), this), setup_Action(MOVE_LEFT, new QAction(tr("Move Tab &Left"), settingOwner),
MOVE_LEFT_SHORTCUT, consoleTabulator, SLOT(moveLeft()), menu_Actions, data); MOVE_LEFT_SHORTCUT, consoleTabulator, SLOT(moveLeft()), menu_Actions, data);
setup_Action(MOVE_RIGHT, new QAction(tr("Move Tab &Right"), this), setup_Action(MOVE_RIGHT, new QAction(tr("Move Tab &Right"), settingOwner),
MOVE_RIGHT_SHORTCUT, consoleTabulator, SLOT(moveRight()), menu_Actions, data); MOVE_RIGHT_SHORTCUT, consoleTabulator, SLOT(moveRight()), menu_Actions, data);
menu_Actions->addSeparator(); menu_Actions->addSeparator();
setup_Action(SPLIT_HORIZONTAL, new QAction(tr("Split Terminal &Horizontally"), this), setup_Action(SPLIT_HORIZONTAL, new QAction(tr("Split Terminal &Horizontally"), settingOwner),
NULL, consoleTabulator, SLOT(splitHorizontally()), menu_Actions); NULL, consoleTabulator, SLOT(splitHorizontally()), menu_Actions);
setup_Action(SPLIT_VERTICAL, new QAction(tr("Split Terminal &Vertically"), this), setup_Action(SPLIT_VERTICAL, new QAction(tr("Split Terminal &Vertically"), settingOwner),
NULL, consoleTabulator, SLOT(splitVertically()), menu_Actions); NULL, consoleTabulator, SLOT(splitVertically()), menu_Actions);
data.setValue(checkSubterminals); data.setValue(checkSubterminals);
setup_Action(SUB_COLLAPSE, new QAction(tr("&Collapse Subterminal"), this), setup_Action(SUB_COLLAPSE, new QAction(tr("&Collapse Subterminal"), settingOwner),
NULL, consoleTabulator, SLOT(splitCollapse()), menu_Actions, data); NULL, consoleTabulator, SLOT(splitCollapse()), menu_Actions, data);
setup_Action(SUB_NEXT, new QAction(QIcon::fromTheme("go-up"), tr("N&ext Subterminal"), this), setup_Action(SUB_TOP, new QAction(QIcon::fromTheme("go-up"), tr("&Top Subterminal"), settingOwner),
SUB_NEXT_SHORTCUT, consoleTabulator, SLOT(switchNextSubterminal()), menu_Actions, data); SUB_TOP_SHORTCUT, consoleTabulator, SLOT(switchTopSubterminal()), menu_Actions, data);
setup_Action(SUB_BOTTOM, new QAction(QIcon::fromTheme("go-down"), tr("&Bottom Subterminal"), settingOwner),
SUB_BOTTOM_SHORTCUT, consoleTabulator, SLOT(switchBottomSubterminal()), menu_Actions, data);
setup_Action(SUB_LEFT, new QAction(QIcon::fromTheme("go-previous"), tr("L&eft Subterminal"), settingOwner),
SUB_LEFT_SHORTCUT, consoleTabulator, SLOT(switchLeftSubterminal()), menu_Actions, data);
setup_Action(SUB_RIGHT, new QAction(QIcon::fromTheme("go-next"), tr("R&ight Subterminal"), settingOwner),
SUB_RIGHT_SHORTCUT, consoleTabulator, SLOT(switchRightSubterminal()), menu_Actions, data);
setup_Action(SUB_PREV, new QAction(QIcon::fromTheme("go-down"), tr("P&revious Subterminal"), this),
SUB_PREV_SHORTCUT, consoleTabulator, SLOT(switchPrevSubterminal()), menu_Actions, data);
menu_Actions->addSeparator(); menu_Actions->addSeparator();
// Copy and Paste are only added to the table for the sake of bindings at the moment; there is no Edit menu, only a context menu. // Copy and Paste are only added to the table for the sake of bindings at the moment; there is no Edit menu, only a context menu.
setup_Action(COPY_SELECTION, new QAction(QIcon::fromTheme("edit-copy"), tr("Copy &Selection"), this), setup_Action(COPY_SELECTION, new QAction(QIcon::fromTheme("edit-copy"), tr("Copy &Selection"), settingOwner),
COPY_SELECTION_SHORTCUT, consoleTabulator, SLOT(copySelection()), menu_Edit); COPY_SELECTION_SHORTCUT, consoleTabulator, SLOT(copySelection()), menu_Edit);
setup_Action(PASTE_CLIPBOARD, new QAction(QIcon::fromTheme("edit-paste"), tr("Paste Clip&board"), this), setup_Action(PASTE_CLIPBOARD, new QAction(QIcon::fromTheme("edit-paste"), tr("Paste Clip&board"), settingOwner),
PASTE_CLIPBOARD_SHORTCUT, consoleTabulator, SLOT(pasteClipboard()), menu_Edit); PASTE_CLIPBOARD_SHORTCUT, consoleTabulator, SLOT(pasteClipboard()), menu_Edit);
setup_Action(PASTE_SELECTION, new QAction(QIcon::fromTheme("edit-paste"), tr("Paste S&election"), this), setup_Action(PASTE_SELECTION, new QAction(QIcon::fromTheme("edit-paste"), tr("Paste S&election"), settingOwner),
PASTE_SELECTION_SHORTCUT, consoleTabulator, SLOT(pasteSelection()), menu_Edit); PASTE_SELECTION_SHORTCUT, consoleTabulator, SLOT(pasteSelection()), menu_Edit);
setup_Action(ZOOM_IN, new QAction(QIcon::fromTheme("zoom-in"), tr("Zoom &in"), this), setup_Action(ZOOM_IN, new QAction(QIcon::fromTheme("zoom-in"), tr("Zoom &in"), settingOwner),
ZOOM_IN_SHORTCUT, consoleTabulator, SLOT(zoomIn()), menu_Edit); ZOOM_IN_SHORTCUT, consoleTabulator, SLOT(zoomIn()), menu_Edit);
setup_Action(ZOOM_OUT, new QAction(QIcon::fromTheme("zoom-out"), tr("Zoom &out"), this), setup_Action(ZOOM_OUT, new QAction(QIcon::fromTheme("zoom-out"), tr("Zoom &out"), settingOwner),
ZOOM_OUT_SHORTCUT, consoleTabulator, SLOT(zoomOut()), menu_Edit); ZOOM_OUT_SHORTCUT, consoleTabulator, SLOT(zoomOut()), menu_Edit);
setup_Action(ZOOM_RESET, new QAction(QIcon::fromTheme("zoom-original"), tr("Zoom rese&t"), this), setup_Action(ZOOM_RESET, new QAction(QIcon::fromTheme("zoom-original"), tr("Zoom rese&t"), settingOwner),
ZOOM_RESET_SHORTCUT, consoleTabulator, SLOT(zoomReset()), menu_Edit); ZOOM_RESET_SHORTCUT, consoleTabulator, SLOT(zoomReset()), menu_Edit);
menu_Actions->addSeparator(); menu_Actions->addSeparator();
setup_Action(FIND, new QAction(QIcon::fromTheme("edit-find"), tr("&Find..."), this), setup_Action(FIND, new QAction(QIcon::fromTheme("edit-find"), tr("&Find..."), settingOwner),
FIND_SHORTCUT, this, SLOT(find()), menu_Actions); FIND_SHORTCUT, this, SLOT(find()), menu_Actions);
#if 0 #if 0
@ -252,63 +293,66 @@ void MainWindow::setup_ActionsMenu_Actions()
connect(act, SIGNAL(triggered()), consoleTabulator, SLOT(loadSession())); connect(act, SIGNAL(triggered()), consoleTabulator, SLOT(loadSession()));
#endif #endif
setup_Action(TOGGLE_MENU, new QAction(tr("&Toggle Menu"), this), setup_Action(TOGGLE_MENU, new QAction(tr("&Toggle Menu"), settingOwner),
TOGGLE_MENU_SHORTCUT, this, SLOT(find())); TOGGLE_MENU_SHORTCUT, this, SLOT(toggleMenu()));
// this is correct - add action to main window - not to menu to keep toggle working // this is correct - add action to main window - not to menu to keep toggle working
// Add global rename current session shortcut // Add global rename current session shortcut
setup_Action(RENAME_SESSION, new QAction(tr("Rename session"), this), setup_Action(RENAME_SESSION, new QAction(tr("Rename session"), settingOwner),
RENAME_SESSION_SHORTCUT, consoleTabulator, SLOT(renameCurrentSession())); RENAME_SESSION_SHORTCUT, consoleTabulator, SLOT(renameCurrentSession()));
// this is correct - add action to main window - not to menu // this is correct - add action to main window - not to menu
// apply props
propertiesChanged();
} }
void MainWindow::setup_FileMenu_Actions() void MainWindow::setup_FileMenu_Actions()
{ {
setup_Action(ADD_TAB, new QAction(QIcon::fromTheme("list-add"), tr("&New Tab"), this), menu_File->clear();
setup_Action(ADD_TAB, new QAction(QIcon::fromTheme("list-add"), tr("&New Tab"), settingOwner),
ADD_TAB_SHORTCUT, this, SLOT(addNewTab()), menu_File); ADD_TAB_SHORTCUT, this, SLOT(addNewTab()), menu_File);
QMenu *presetsMenu = new QMenu(tr("New Tab From &Preset"), this); if (presetsMenu == NULL) {
presetsMenu->addAction(QIcon(), tr("1 &Terminal"), presetsMenu = new QMenu(tr("New Tab From &Preset"), this);
consoleTabulator, SLOT(addNewTab())); presetsMenu->addAction(QIcon(), tr("1 &Terminal"),
presetsMenu->addAction(QIcon(), tr("2 &Horizontal Terminals"), this, SLOT(addNewTab()));
consoleTabulator, SLOT(preset2Horizontal())); presetsMenu->addAction(QIcon(), tr("2 &Horizontal Terminals"),
presetsMenu->addAction(QIcon(), tr("2 &Vertical Terminals"), consoleTabulator, SLOT(preset2Horizontal()));
consoleTabulator, SLOT(preset2Vertical())); presetsMenu->addAction(QIcon(), tr("2 &Vertical Terminals"),
presetsMenu->addAction(QIcon(), tr("4 Terminal&s"), consoleTabulator, SLOT(preset2Vertical()));
consoleTabulator, SLOT(preset4Terminals())); presetsMenu->addAction(QIcon(), tr("4 Terminal&s"),
consoleTabulator, SLOT(preset4Terminals()));
}
menu_File->addMenu(presetsMenu); menu_File->addMenu(presetsMenu);
setup_Action(CLOSE_TAB, new QAction(QIcon::fromTheme("list-remove"), tr("&Close Tab"), this), setup_Action(CLOSE_TAB, new QAction(QIcon::fromTheme("list-remove"), tr("&Close Tab"), settingOwner),
CLOSE_TAB_SHORTCUT, consoleTabulator, SLOT(removeCurrentTab()), menu_File); CLOSE_TAB_SHORTCUT, consoleTabulator, SLOT(removeCurrentTab()), menu_File);
setup_Action(NEW_WINDOW, new QAction(QIcon::fromTheme("window-new"), tr("&New Window"), this), setup_Action(NEW_WINDOW, new QAction(QIcon::fromTheme("window-new"), tr("&New Window"), settingOwner),
NEW_WINDOW_SHORTCUT, this, SLOT(newTerminalWindow()), menu_File); NEW_WINDOW_SHORTCUT, this, SLOT(newTerminalWindow()), menu_File);
menu_File->addSeparator(); menu_File->addSeparator();
setup_Action(PREFERENCES, actProperties, "", this, SLOT(actProperties_triggered()), menu_File); setup_Action(PREFERENCES, new QAction(tr("&Preferences..."), settingOwner), "", this, SLOT(actProperties_triggered()), menu_File);
menu_File->addSeparator(); menu_File->addSeparator();
setup_Action(QUIT, actQuit, "", this, SLOT(close()), menu_File); setup_Action(QUIT, new QAction(QIcon::fromTheme("application-exit"), tr("&Quit"), settingOwner), "", this, SLOT(close()), menu_File);
} }
void MainWindow::setup_ViewMenu_Actions() void MainWindow::setup_ViewMenu_Actions()
{ {
QAction *hideBordersAction = new QAction(tr("&Hide Window Borders"), this); menu_Window->clear();
QAction *hideBordersAction = new QAction(tr("&Hide Window Borders"), settingOwner);
hideBordersAction->setCheckable(true); hideBordersAction->setCheckable(true);
hideBordersAction->setVisible(!m_dropMode); hideBordersAction->setVisible(!m_dropMode);
setup_Action(HIDE_WINDOW_BORDERS, hideBordersAction, setup_Action(HIDE_WINDOW_BORDERS, hideBordersAction,
NULL, this, SLOT(toggleBorderless()), menu_Window); NULL, this, SLOT(toggleBorderless()), menu_Window);
//Properties::Instance()->actions[HIDE_WINDOW_BORDERS]->setObjectName("toggle_Borderless"); //Properties::Instance()->actions[HIDE_WINDOW_BORDERS]->setObjectName("toggle_Borderless");
// TODO/FIXME: it's broken somehow. When I call toggleBorderless() here the non-responsive window appear // TODO/FIXME: it's broken somehow. When I call toggleBorderless() here the non-responsive window appear
// Properties::Instance()->actions[HIDE_WINDOW_BORDERS]->setChecked(Properties::Instance()->borderless); // actions[HIDE_WINDOW_BORDERS]->setChecked(Properties::Instance()->borderless);
// if (Properties::Instance()->borderless) // if (Properties::Instance()->borderless)
// toggleBorderless(); // toggleBorderless();
QAction *showTabBarAction = new QAction(tr("&Show Tab Bar"), this); QAction *showTabBarAction = new QAction(tr("&Show Tab Bar"), settingOwner);
//toggleTabbar->setObjectName("toggle_TabBar"); //toggleTabbar->setObjectName("toggle_TabBar");
showTabBarAction->setCheckable(true); showTabBarAction->setCheckable(true);
showTabBarAction->setChecked(!Properties::Instance()->tabBarless); showTabBarAction->setChecked(!Properties::Instance()->tabBarless);
@ -316,30 +360,33 @@ void MainWindow::setup_ViewMenu_Actions()
NULL, this, SLOT(toggleTabBar()), menu_Window); NULL, this, SLOT(toggleTabBar()), menu_Window);
toggleTabBar(); toggleTabBar();
QAction *toggleFullscreen = new QAction(tr("Fullscreen"), this); QAction *toggleFullscreen = new QAction(tr("Fullscreen"), settingOwner);
toggleFullscreen->setCheckable(true); toggleFullscreen->setCheckable(true);
toggleFullscreen->setChecked(false); toggleFullscreen->setChecked(false);
setup_Action(FULLSCREEN, toggleFullscreen, setup_Action(FULLSCREEN, toggleFullscreen,
FULLSCREEN_SHORTCUT, this, SLOT(showFullscreen(bool)), menu_Window); FULLSCREEN_SHORTCUT, this, SLOT(showFullscreen(bool)), menu_Window);
setup_Action(TOGGLE_BOOKMARKS, m_bookmarksDock->toggleViewAction(), setup_Action(TOGGLE_BOOKMARKS, new QAction(tr("Toggle Bookmarks"), settingOwner),
TOGGLE_BOOKMARKS_SHORTCUT, NULL, NULL, menu_Window); TOGGLE_BOOKMARKS_SHORTCUT, NULL, NULL, menu_Window);
menu_Window->addSeparator(); menu_Window->addSeparator();
/* tabs position */ /* tabs position */
tabPosition = new QActionGroup(this); if (tabPosition == NULL) {
QAction *tabBottom = new QAction(tr("&Bottom"), this); tabPosition = new QActionGroup(this);
QAction *tabTop = new QAction(tr("&Top"), this); QAction *tabBottom = new QAction(tr("&Bottom"), this);
QAction *tabRight = new QAction(tr("&Right"), this); QAction *tabTop = new QAction(tr("&Top"), this);
QAction *tabLeft = new QAction(tr("&Left"), this); QAction *tabRight = new QAction(tr("&Right"), this);
tabPosition->addAction(tabTop); QAction *tabLeft = new QAction(tr("&Left"), this);
tabPosition->addAction(tabBottom); tabPosition->addAction(tabTop);
tabPosition->addAction(tabLeft); tabPosition->addAction(tabBottom);
tabPosition->addAction(tabRight); tabPosition->addAction(tabLeft);
tabPosition->addAction(tabRight);
for(int i = 0; i < tabPosition->actions().size(); ++i)
tabPosition->actions().at(i)->setCheckable(true); for(int i = 0; i < tabPosition->actions().size(); ++i)
tabPosition->actions().at(i)->setCheckable(true);
}
if( tabPosition->actions().count() > Properties::Instance()->tabsPos ) if( tabPosition->actions().count() > Properties::Instance()->tabsPos )
tabPosition->actions().at(Properties::Instance()->tabsPos)->setChecked(true); tabPosition->actions().at(Properties::Instance()->tabsPos)->setChecked(true);
@ -347,96 +394,84 @@ void MainWindow::setup_ViewMenu_Actions()
connect(tabPosition, SIGNAL(triggered(QAction *)), connect(tabPosition, SIGNAL(triggered(QAction *)),
consoleTabulator, SLOT(changeTabPosition(QAction *)) ); consoleTabulator, SLOT(changeTabPosition(QAction *)) );
tabPosMenu = new QMenu(tr("&Tabs Layout"), menu_Window); if (tabPosMenu == NULL) {
tabPosMenu->setObjectName("tabPosMenu"); tabPosMenu = new QMenu(tr("&Tabs Layout"), menu_Window);
tabPosMenu->setObjectName("tabPosMenu");
for(int i=0; i < tabPosition->actions().size(); ++i) { for(int i=0; i < tabPosition->actions().size(); ++i) {
tabPosMenu->addAction(tabPosition->actions().at(i)); tabPosMenu->addAction(tabPosition->actions().at(i));
} }
connect(menu_Window, SIGNAL(hovered(QAction *)), connect(menu_Window, SIGNAL(hovered(QAction *)),
this, SLOT(updateActionGroup(QAction *))); this, SLOT(updateActionGroup(QAction *)));
}
menu_Window->addMenu(tabPosMenu); menu_Window->addMenu(tabPosMenu);
/* */ /* */
/* Scrollbar */ /* Scrollbar */
scrollBarPosition = new QActionGroup(this); if (scrollBarPosition == NULL) {
QAction *scrollNone = new QAction(tr("&None"), this); scrollBarPosition = new QActionGroup(this);
QAction *scrollRight = new QAction(tr("&Right"), this); QAction *scrollNone = new QAction(tr("&None"), this);
QAction *scrollLeft = new QAction(tr("&Left"), this); QAction *scrollRight = new QAction(tr("&Right"), this);
QAction *scrollLeft = new QAction(tr("&Left"), this);
/* order of insertion is dep. on QTermWidget::ScrollBarPosition enum */ /* order of insertion is dep. on QTermWidget::ScrollBarPosition enum */
scrollBarPosition->addAction(scrollNone); scrollBarPosition->addAction(scrollNone);
scrollBarPosition->addAction(scrollLeft); scrollBarPosition->addAction(scrollLeft);
scrollBarPosition->addAction(scrollRight); scrollBarPosition->addAction(scrollRight);
for(int i = 0; i < scrollBarPosition->actions().size(); ++i) for(int i = 0; i < scrollBarPosition->actions().size(); ++i)
scrollBarPosition->actions().at(i)->setCheckable(true); scrollBarPosition->actions().at(i)->setCheckable(true);
if( Properties::Instance()->scrollBarPos < scrollBarPosition->actions().size() ) if( Properties::Instance()->scrollBarPos < scrollBarPosition->actions().size() )
scrollBarPosition->actions().at(Properties::Instance()->scrollBarPos)->setChecked(true); scrollBarPosition->actions().at(Properties::Instance()->scrollBarPos)->setChecked(true);
connect(scrollBarPosition, SIGNAL(triggered(QAction *)),
connect(scrollBarPosition, SIGNAL(triggered(QAction *)),
consoleTabulator, SLOT(changeScrollPosition(QAction *)) ); consoleTabulator, SLOT(changeScrollPosition(QAction *)) );
scrollPosMenu = new QMenu(tr("S&crollbar Layout"), menu_Window); }
scrollPosMenu->setObjectName("scrollPosMenu"); if (scrollPosMenu == NULL) {
scrollPosMenu = new QMenu(tr("S&crollbar Layout"), menu_Window);
scrollPosMenu->setObjectName("scrollPosMenu");
for(int i=0; i < scrollBarPosition->actions().size(); ++i) { for(int i=0; i < scrollBarPosition->actions().size(); ++i) {
scrollPosMenu->addAction(scrollBarPosition->actions().at(i)); scrollPosMenu->addAction(scrollBarPosition->actions().at(i));
}
} }
menu_Window->addMenu(scrollPosMenu); menu_Window->addMenu(scrollPosMenu);
/* Keyboard cursor shape */ /* Keyboard cursor shape */
keyboardCursorShape = new QActionGroup(this); if (keyboardCursorShape == NULL) {
QAction *block = new QAction(tr("&BlockCursor"), this); keyboardCursorShape = new QActionGroup(this);
QAction *underline = new QAction(tr("&UnderlineCursor"), this); QAction *block = new QAction(tr("&BlockCursor"), this);
QAction *ibeam = new QAction(tr("&IBeamCursor"), this); QAction *underline = new QAction(tr("&UnderlineCursor"), this);
QAction *ibeam = new QAction(tr("&IBeamCursor"), this);
/* order of insertion is dep. on QTermWidget::KeyboardCursorShape enum */
keyboardCursorShape->addAction(block); /* order of insertion is dep. on QTermWidget::KeyboardCursorShape enum */
keyboardCursorShape->addAction(underline); keyboardCursorShape->addAction(block);
keyboardCursorShape->addAction(ibeam); keyboardCursorShape->addAction(underline);
keyboardCursorShape->addAction(ibeam);
for(int i = 0; i < keyboardCursorShape->actions().size(); ++i) for(int i = 0; i < keyboardCursorShape->actions().size(); ++i)
keyboardCursorShape->actions().at(i)->setCheckable(true); keyboardCursorShape->actions().at(i)->setCheckable(true);
if( Properties::Instance()->keyboardCursorShape < keyboardCursorShape->actions().size() ) if( Properties::Instance()->keyboardCursorShape < keyboardCursorShape->actions().size() )
keyboardCursorShape->actions().at(Properties::Instance()->keyboardCursorShape)->setChecked(true); keyboardCursorShape->actions().at(Properties::Instance()->keyboardCursorShape)->setChecked(true);
connect(keyboardCursorShape, SIGNAL(triggered(QAction *)), connect(keyboardCursorShape, SIGNAL(triggered(QAction *)),
consoleTabulator, SLOT(changeKeyboardCursorShape(QAction *)) ); consoleTabulator, SLOT(changeKeyboardCursorShape(QAction *)) );
}
keyboardCursorShapeMenu = new QMenu(tr("&Keyboard Cursor Shape"), menu_Window); if (keyboardCursorShapeMenu == NULL) {
keyboardCursorShapeMenu->setObjectName("keyboardCursorShapeMenu"); keyboardCursorShapeMenu = new QMenu(tr("&Keyboard Cursor Shape"), menu_Window);
keyboardCursorShapeMenu->setObjectName("keyboardCursorShapeMenu");
for(int i=0; i < keyboardCursorShape->actions().size(); ++i) { for(int i=0; i < keyboardCursorShape->actions().size(); ++i) {
keyboardCursorShapeMenu->addAction(keyboardCursorShape->actions().at(i)); keyboardCursorShapeMenu->addAction(keyboardCursorShape->actions().at(i));
}
} }
menu_Window->addMenu(keyboardCursorShapeMenu); menu_Window->addMenu(keyboardCursorShapeMenu);
} }
void MainWindow::setup_ContextMenu_Actions(QMenu* contextMenu) const
{
contextMenu->addAction(Properties::Instance()->actions[COPY_SELECTION]);
contextMenu->addAction(Properties::Instance()->actions[PASTE_CLIPBOARD]);
contextMenu->addAction(Properties::Instance()->actions[PASTE_SELECTION]);
contextMenu->addAction(Properties::Instance()->actions[ZOOM_IN]);
contextMenu->addAction(Properties::Instance()->actions[ZOOM_OUT]);
contextMenu->addAction(Properties::Instance()->actions[ZOOM_RESET]);
contextMenu->addSeparator();
contextMenu->addAction(Properties::Instance()->actions[CLEAR_TERMINAL]);
contextMenu->addAction(Properties::Instance()->actions[SPLIT_HORIZONTAL]);
contextMenu->addAction(Properties::Instance()->actions[SPLIT_VERTICAL]);
#warning TODO/FIXME: disable the action when there is only one terminal
contextMenu->addAction(Properties::Instance()->actions[SUB_COLLAPSE]);
contextMenu->addSeparator();
contextMenu->addAction(Properties::Instance()->actions[TOGGLE_MENU]);
contextMenu->addAction(Properties::Instance()->actions[PREFERENCES]);
}
void MainWindow::setupCustomDirs() void MainWindow::setupCustomDirs()
{ {
const QSettings settings; const QSettings settings;
@ -451,7 +486,7 @@ void MainWindow::on_consoleTabulator_currentChanged(int)
void MainWindow::toggleTabBar() void MainWindow::toggleTabBar()
{ {
Properties::Instance()->tabBarless Properties::Instance()->tabBarless
= !Properties::Instance()->actions[SHOW_TAB_BAR]->isChecked(); = !actions[SHOW_TAB_BAR]->isChecked();
consoleTabulator->showHideTabBar(); consoleTabulator->showHideTabBar();
} }
@ -461,7 +496,7 @@ void MainWindow::toggleBorderless()
show(); show();
setWindowState(Qt::WindowActive); /* don't loose focus on the window */ setWindowState(Qt::WindowActive); /* don't loose focus on the window */
Properties::Instance()->borderless Properties::Instance()->borderless
= Properties::Instance()->actions[HIDE_WINDOW_BORDERS]->isChecked(); realign(); = actions[HIDE_WINDOW_BORDERS]->isChecked(); realign();
} }
void MainWindow::toggleMenu() void MainWindow::toggleMenu()
@ -478,6 +513,12 @@ void MainWindow::showFullscreen(bool fullscreen)
setWindowState(windowState() & ~Qt::WindowFullScreen); setWindowState(windowState() & ~Qt::WindowFullScreen);
} }
void MainWindow::toggleBookmarks()
{
m_bookmarksDock->toggleViewAction()->trigger();
}
void MainWindow::closeEvent(QCloseEvent *ev) void MainWindow::closeEvent(QCloseEvent *ev)
{ {
if (!Properties::Instance()->askOnExit if (!Properties::Instance()->askOnExit
@ -550,6 +591,8 @@ void MainWindow::actProperties_triggered()
void MainWindow::propertiesChanged() void MainWindow::propertiesChanged()
{ {
rebuildActions();
QApplication::setStyle(Properties::Instance()->guiStyle); QApplication::setStyle(Properties::Instance()->guiStyle);
setWindowOpacity(1.0 - Properties::Instance()->appTransparency/100.0); setWindowOpacity(1.0 - Properties::Instance()->appTransparency/100.0);
consoleTabulator->setTabPosition((QTabWidget::TabPosition)Properties::Instance()->tabsPos); consoleTabulator->setTabPosition((QTabWidget::TabPosition)Properties::Instance()->tabsPos);
@ -560,7 +603,7 @@ void MainWindow::propertiesChanged()
m_bookmarksDock->setVisible(Properties::Instance()->useBookmarks m_bookmarksDock->setVisible(Properties::Instance()->useBookmarks
&& Properties::Instance()->bookmarksVisible); && Properties::Instance()->bookmarksVisible);
m_bookmarksDock->toggleViewAction()->setVisible(Properties::Instance()->useBookmarks); actions[TOGGLE_BOOKMARKS]->setVisible(Properties::Instance()->useBookmarks);
if (Properties::Instance()->useBookmarks) if (Properties::Instance()->useBookmarks)
{ {
@ -569,7 +612,6 @@ void MainWindow::propertiesChanged()
onCurrentTitleChanged(consoleTabulator->currentIndex()); onCurrentTitleChanged(consoleTabulator->currentIndex());
Properties::Instance()->saveSettings();
realign(); realign();
} }
@ -585,8 +627,9 @@ void MainWindow::realign()
geometry.moveCenter(desktop.center()); geometry.moveCenter(desktop.center());
// do not use 0 here - we need to calculate with potential panel on top // do not use 0 here - we need to calculate with potential panel on top
geometry.setTop(desktop.top()); geometry.setTop(desktop.top());
if (geometry != this->geometry()) {
setGeometry(geometry); setGeometry(geometry);
}
} }
} }
@ -645,7 +688,12 @@ bool MainWindow::event(QEvent *event)
void MainWindow::newTerminalWindow() void MainWindow::newTerminalWindow()
{ {
MainWindow *w = new MainWindow(m_initWorkDir, m_initShell, false); TerminalConfig cfg;
TermWidgetHolder *ch = consoleTabulator->terminalHolder();
if (ch)
cfg.provideCurrentDirectory(ch->currentTerminal()->impl()->workingDirectory());
MainWindow *w = new MainWindow(cfg, false);
w->show(); w->show();
} }
@ -662,6 +710,7 @@ void MainWindow::bookmarksDock_visibilityChanged(bool visible)
void MainWindow::addNewTab() void MainWindow::addNewTab()
{ {
TerminalConfig cfg;
if (Properties::Instance()->terminalsPreset == 3) if (Properties::Instance()->terminalsPreset == 3)
consoleTabulator->preset4Terminals(); consoleTabulator->preset4Terminals();
else if (Properties::Instance()->terminalsPreset == 2) else if (Properties::Instance()->terminalsPreset == 2)
@ -669,7 +718,8 @@ void MainWindow::addNewTab()
else if (Properties::Instance()->terminalsPreset == 1) else if (Properties::Instance()->terminalsPreset == 1)
consoleTabulator->preset2Horizontal(); consoleTabulator->preset2Horizontal();
else else
consoleTabulator->addNewTab(); consoleTabulator->addNewTab(cfg);
updateDisabledActions();
} }
void MainWindow::onCurrentTitleChanged(int index) void MainWindow::onCurrentTitleChanged(int index)
@ -695,7 +745,7 @@ bool MainWindow::hasMultipleSubterminals()
return consoleTabulator->terminalHolder()->findChildren<TermWidget*>().count() > 1; return consoleTabulator->terminalHolder()->findChildren<TermWidget*>().count() > 1;
} }
void MainWindow::aboutToShowActionsMenu() void MainWindow::updateDisabledActions()
{ {
const QList<QAction*> actions = menu_Actions->actions(); const QList<QAction*> actions = menu_Actions->actions();
for (QAction *action : actions) { for (QAction *action : actions) {
@ -705,3 +755,39 @@ void MainWindow::aboutToShowActionsMenu()
} }
} }
} }
QMap< QString, QAction * >& MainWindow::leaseActions() {
return actions;
}
#ifdef HAVE_QDBUS
QDBusObjectPath MainWindow::getActiveTab()
{
return qobject_cast<TermWidgetHolder*>(consoleTabulator->currentWidget())->getDbusPath();
}
QList<QDBusObjectPath> MainWindow::getTabs()
{
QList<QDBusObjectPath> tabs;
for (int i = 0; i<consoleTabulator->count(); ++i)
{
tabs.push_back(qobject_cast<TermWidgetHolder*>(consoleTabulator->widget(i))->getDbusPath());
}
return tabs;
}
QDBusObjectPath MainWindow::newTab(const QHash<QString,QVariant> &termArgs)
{
TerminalConfig cfg = TerminalConfig::fromDbus(termArgs);
int idx = consoleTabulator->addNewTab(cfg);
return qobject_cast<TermWidgetHolder*>(consoleTabulator->widget(idx))->getDbusPath();
}
void MainWindow::closeWindow()
{
close();
}
#endif

@ -22,22 +22,34 @@
#include "ui_qterminal.h" #include "ui_qterminal.h"
#include <QMainWindow> #include <QMainWindow>
#include <QAction>
#include "qxtglobalshortcut.h" #include "qxtglobalshortcut.h"
#include "terminalconfig.h"
#include "dbusaddressable.h"
class QToolButton; class QToolButton;
class MainWindow : public QMainWindow , private Ui::mainWindow class MainWindow : public QMainWindow, private Ui::mainWindow, public DBusAddressable
{ {
Q_OBJECT Q_OBJECT
public: public:
MainWindow(const QString& work_dir, const QString& command, MainWindow(TerminalConfig& cfg,
bool dropMode, bool dropMode,
QWidget * parent = 0, Qt::WindowFlags f = 0); QWidget * parent = 0, Qt::WindowFlags f = 0);
~MainWindow(); ~MainWindow();
bool dropMode() const { return m_dropMode; } bool dropMode() { return m_dropMode; }
void setup_ContextMenu_Actions(QMenu* contextMenu) const; QMap<QString, QAction*> & leaseActions();
#ifdef HAVE_QDBUS
QDBusObjectPath getActiveTab();
QList<QDBusObjectPath> getTabs();
QDBusObjectPath newTab(const QHash<QString,QVariant> &termArgs);
void closeWindow();
#endif
protected: protected:
bool event(QEvent* event); bool event(QEvent* event);
@ -46,16 +58,26 @@ private:
QActionGroup *tabPosition, *scrollBarPosition, *keyboardCursorShape; QActionGroup *tabPosition, *scrollBarPosition, *keyboardCursorShape;
QMenu *tabPosMenu, *scrollPosMenu, *keyboardCursorShapeMenu; QMenu *tabPosMenu, *scrollPosMenu, *keyboardCursorShapeMenu;
QString m_initWorkDir; // A parent object for QObjects that are created dynamically based on settings
QString m_initShell; // Used to simplify the setting cleanup on reconfiguration: deleting settingOwner frees all related QObjects
QWidget *settingOwner;
QMenu *presetsMenu;
TerminalConfig m_config;
QDockWidget *m_bookmarksDock; QDockWidget *m_bookmarksDock;
void setup_Action(const char *name, QAction *action, const char *defaultShortcut, const QObject *receiver, void setup_Action(const char *name, QAction *action, const char *defaultShortcut, const QObject *receiver,
const char *slot, QMenu *menu = NULL, const QVariant &data = QVariant()); const char *slot, QMenu *menu = NULL, const QVariant &data = QVariant());
QMap< QString, QAction * > actions;
void rebuildActions();
void setup_FileMenu_Actions(); void setup_FileMenu_Actions();
void setup_ActionsMenu_Actions(); void setup_ActionsMenu_Actions();
void setup_ViewMenu_Actions(); void setup_ViewMenu_Actions();
void setup_ContextMenu_Actions();
void setupCustomDirs(); void setupCustomDirs();
void closeEvent(QCloseEvent*); void closeEvent(QCloseEvent*);
@ -70,6 +92,10 @@ private:
bool hasMultipleTabs(); bool hasMultipleTabs();
bool hasMultipleSubterminals(); bool hasMultipleSubterminals();
public slots:
void showHide();
void updateDisabledActions();
private slots: private slots:
void on_consoleTabulator_currentChanged(int); void on_consoleTabulator_currentChanged(int);
void propertiesChanged(); void propertiesChanged();
@ -77,12 +103,12 @@ private slots:
void actProperties_triggered(); void actProperties_triggered();
void updateActionGroup(QAction *); void updateActionGroup(QAction *);
void toggleBookmarks();
void toggleBorderless(); void toggleBorderless();
void toggleTabBar(); void toggleTabBar();
void toggleMenu(); void toggleMenu();
void showFullscreen(bool fullscreen); void showFullscreen(bool fullscreen);
void showHide();
void setKeepOpen(bool value); void setKeepOpen(bool value);
void find(); void find();
@ -93,6 +119,5 @@ private slots:
void addNewTab(); void addNewTab();
void onCurrentTitleChanged(int index); void onCurrentTitleChanged(int index);
void aboutToShowActionsMenu();
}; };
#endif //MAINWINDOW_H #endif //MAINWINDOW_H

@ -0,0 +1,23 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.lxqt.QTerminal.Process">
<method name="getWindows">
<arg name="windows" type="ao" direction="out"/>
</method>
<method name="newWindow">
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QHash&lt;QString,QVariant&gt;"/>
<arg name="termArgs" type="a{sv}" direction="in"/>
</method>
<method name="getActiveWindow">
<arg name="window" type="o" direction="out"/>
</method>
<method name="isDropMode">
<arg name="isDropMode" type="b" direction="out"/>
</method>
<method name="toggleDropdown">
<arg name="success" type="b" direction="out"/>
</method>
</interface>
</node>

@ -0,0 +1,17 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.lxqt.QTerminal.Tab">
<method name="getActiveTerminal">
<arg name="terminal" type="o" direction="out"/>
</method>
<method name="getTerminals">
<arg name="terminals" type="ao" direction="out"/>
</method>
<method name="getWindow">
<arg name="window" type="o" direction="out"/>
</method>
<method name="closeTab"/>
</interface>
</node>

@ -0,0 +1,24 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.lxqt.QTerminal.Terminal">
<method name="splitVertical">
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QHash&lt;QString,QVariant&gt;"/>
<arg name="termArgs" type="a{sv}" direction="in"/>
<arg name="newTerminal" type="o" direction="out"/>
</method>
<method name="splitHorizontal">
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QHash&lt;QString,QVariant&gt;"/>
<arg name="termArgs" type="a{sv}" direction="in"/>
<arg name="newTerminal" type="o" direction="out"/>
</method>
<method name="getTab">
<arg name="tab" type="o" direction="out"/>
</method>
<method name="sendText">
<arg name="text" type="s" direction="in"/>
</method>
<method name="closeTerminal"/>
</interface>
</node>

@ -0,0 +1,20 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.lxqt.QTerminal.Window">
<method name="getTabs">
<arg name="tabs" type="ao" direction="out"/>
</method>
<method name="getActiveTab">
<arg name="tab" type="o" direction="out"/>
</method>
<method name="newTab">
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QHash&lt;QString,QVariant&gt;"/>
<arg name="termArgs" type="a{sv}" direction="in"/>
<arg name="newTerminal" type="o" direction="out"/>
</method>
<method name="closeWindow"/>
<method name="activateWindow"/>
</interface>
</node>

@ -17,10 +17,12 @@
***************************************************************************/ ***************************************************************************/
#include <qtermwidget.h> #include <qtermwidget.h>
#include <assert.h>
#include "properties.h" #include "properties.h"
#include "config.h" #include "config.h"
#include "mainwindow.h"
#include "qterminalapp.h"
Properties * Properties::m_instance = 0; Properties * Properties::m_instance = 0;
@ -45,7 +47,6 @@ Properties::Properties(const QString& filename)
Properties::~Properties() Properties::~Properties()
{ {
qDebug("Properties destructor called"); qDebug("Properties destructor called");
saveSettings();
delete m_settings; delete m_settings;
m_instance = 0; m_instance = 0;
} }
@ -69,17 +70,10 @@ void Properties::loadSettings()
highlightCurrentTerminal = m_settings->value("highlightCurrentTerminal", true).toBool(); highlightCurrentTerminal = m_settings->value("highlightCurrentTerminal", true).toBool();
font = qvariant_cast<QFont>(m_settings->value("font", defaultFont())); font = QFont(qvariant_cast<QString>(m_settings->value("fontFamily", defaultFont().family())),
qvariant_cast<int>(m_settings->value("fontSize", defaultFont().pointSize())));
m_settings->beginGroup("Shortcuts"); //Legacy font setting
QStringList keys = m_settings->childKeys(); font = qvariant_cast<QFont>(m_settings->value("font", font));
foreach( QString key, keys )
{
QKeySequence sequence = QKeySequence( m_settings->value( key ).toString() );
if( Properties::Instance()->actions.contains( key ) )
Properties::Instance()->actions[ key ]->setShortcut( sequence );
}
m_settings->endGroup();
mainWindowSize = m_settings->value("MainWindow/size").toSize(); mainWindowSize = m_settings->value("MainWindow/size").toSize();
mainWindowPosition = m_settings->value("MainWindow/pos").toPoint(); mainWindowPosition = m_settings->value("MainWindow/pos").toPoint();
@ -127,7 +121,8 @@ void Properties::loadSettings()
// bookmarks // bookmarks
useBookmarks = m_settings->value("UseBookmarks", false).toBool(); useBookmarks = m_settings->value("UseBookmarks", false).toBool();
bookmarksVisible = m_settings->value("BookmarksVisible", true).toBool(); bookmarksVisible = m_settings->value("BookmarksVisible", true).toBool();
bookmarksFile = m_settings->value("BookmarksFile", QFileInfo(m_settings->fileName()).canonicalPath()+"/qterminal_bookmarks.xml").toString(); const QString s = QFileInfo(m_settings->fileName()).canonicalPath() + QString::fromLatin1("/qterminal_bookmarks.xml");
bookmarksFile = m_settings->value("BookmarksFile", s).toString();
terminalsPreset = m_settings->value("TerminalsPreset", 0).toInt(); terminalsPreset = m_settings->value("TerminalsPreset", 0).toInt();
@ -141,6 +136,9 @@ void Properties::loadSettings()
changeWindowTitle = m_settings->value("ChangeWindowTitle", true).toBool(); changeWindowTitle = m_settings->value("ChangeWindowTitle", true).toBool();
changeWindowIcon = m_settings->value("ChangeWindowIcon", true).toBool(); changeWindowIcon = m_settings->value("ChangeWindowIcon", true).toBool();
confirmMultilinePaste = m_settings->value("ConfirmMultilinePaste", false).toBool();
trimPastedTrailingNewlines = m_settings->value("TrimPastedTrailingNewlines", false).toBool();
} }
void Properties::saveSettings() void Properties::saveSettings()
@ -148,15 +146,21 @@ void Properties::saveSettings()
m_settings->setValue("guiStyle", guiStyle); m_settings->setValue("guiStyle", guiStyle);
m_settings->setValue("colorScheme", colorScheme); m_settings->setValue("colorScheme", colorScheme);
m_settings->setValue("highlightCurrentTerminal", highlightCurrentTerminal); m_settings->setValue("highlightCurrentTerminal", highlightCurrentTerminal);
m_settings->setValue("font", font); m_settings->setValue("fontFamily", font.family());
m_settings->setValue("fontSize", font.pointSize());
//Clobber legacy setting
m_settings->remove("font");
m_settings->beginGroup("Shortcuts"); m_settings->beginGroup("Shortcuts");
QMapIterator< QString, QAction * > it(actions); MainWindow *mainWindow = QTerminalApp::Instance()->getWindowList()[0];
assert(mainWindow != NULL);
QMapIterator< QString, QAction * > it(mainWindow->leaseActions());
while( it.hasNext() ) while( it.hasNext() )
{ {
it.next(); it.next();
QStringList sequenceStrings; QStringList sequenceStrings;
foreach (QKeySequence shortcut, it.value()->shortcuts()) foreach (const QKeySequence &shortcut, it.value()->shortcuts())
sequenceStrings.append(shortcut.toString()); sequenceStrings.append(shortcut.toString());
m_settings->setValue(it.key(), sequenceStrings.join('|')); m_settings->setValue(it.key(), sequenceStrings.join('|'));
} }
@ -218,6 +222,10 @@ void Properties::saveSettings()
m_settings->setValue("ChangeWindowTitle", changeWindowTitle); m_settings->setValue("ChangeWindowTitle", changeWindowTitle);
m_settings->setValue("ChangeWindowIcon", changeWindowIcon); m_settings->setValue("ChangeWindowIcon", changeWindowIcon);
m_settings->setValue("ConfirmMultilinePaste", confirmMultilinePaste);
m_settings->setValue("TrimPastedTrailingNewlines", trimPastedTrailingNewlines);
} }
void Properties::migrate_settings() void Properties::migrate_settings()

@ -22,7 +22,6 @@
#include <QApplication> #include <QApplication>
#include <QtCore> #include <QtCore>
#include <QFont> #include <QFont>
#include <QAction>
typedef QString Session; typedef QString Session;
@ -95,8 +94,8 @@ class Properties
bool changeWindowTitle; bool changeWindowTitle;
bool changeWindowIcon; bool changeWindowIcon;
QMap< QString, QAction * > actions; bool confirmMultilinePaste;
bool trimPastedTrailingNewlines;
private: private:

@ -26,6 +26,7 @@
#include "properties.h" #include "properties.h"
#include "fontdialog.h" #include "fontdialog.h"
#include "config.h" #include "config.h"
#include "qterminalapp.h"
PropertiesDialog::PropertiesDialog(QWidget *parent) PropertiesDialog::PropertiesDialog(QWidget *parent)
@ -136,6 +137,10 @@ PropertiesDialog::PropertiesDialog(QWidget *parent)
changeWindowTitleCheckBox->setChecked(Properties::Instance()->changeWindowTitle); changeWindowTitleCheckBox->setChecked(Properties::Instance()->changeWindowTitle);
changeWindowIconCheckBox->setChecked(Properties::Instance()->changeWindowIcon); changeWindowIconCheckBox->setChecked(Properties::Instance()->changeWindowIcon);
trimPastedTrailingNewlinesCheckBox->setChecked(Properties::Instance()->trimPastedTrailingNewlines);
confirmMultilinePasteCheckBox->setChecked(Properties::Instance()->confirmMultilinePaste);
} }
@ -203,6 +208,9 @@ void PropertiesDialog::apply()
Properties::Instance()->changeWindowTitle = changeWindowTitleCheckBox->isChecked(); Properties::Instance()->changeWindowTitle = changeWindowTitleCheckBox->isChecked();
Properties::Instance()->changeWindowIcon = changeWindowIconCheckBox->isChecked(); Properties::Instance()->changeWindowIcon = changeWindowIconCheckBox->isChecked();
Properties::Instance()->trimPastedTrailingNewlines = trimPastedTrailingNewlinesCheckBox->isChecked();
Properties::Instance()->confirmMultilinePaste = confirmMultilinePasteCheckBox->isChecked();
emit propertiesChanged(); emit propertiesChanged();
} }
@ -226,7 +234,7 @@ void PropertiesDialog::changeFontButton_clicked()
void PropertiesDialog::chooseBackgroundImageButton_clicked() void PropertiesDialog::chooseBackgroundImageButton_clicked()
{ {
QString filename = QFileDialog::getOpenFileName( QString filename = QFileDialog::getOpenFileName(
this, tr("Open or create bookmarks file"), this, tr("Choose a background image"),
QString(), tr("Images (*.bmp *.png *.xpm *.jpg)")); QString(), tr("Images (*.bmp *.png *.xpm *.jpg)"));
if (!filename.isNull()) if (!filename.isNull())
backgroundImageLineEdit->setText(filename); backgroundImageLineEdit->setText(filename);
@ -234,7 +242,8 @@ void PropertiesDialog::chooseBackgroundImageButton_clicked()
void PropertiesDialog::saveShortcuts() void PropertiesDialog::saveShortcuts()
{ {
QList< QString > shortcutKeys = Properties::Instance()->actions.keys(); QMap<QString, QAction*> actions = QTerminalApp::Instance()->getWindowList()[0]->leaseActions();
QList< QString > shortcutKeys = actions.keys();
int shortcutCount = shortcutKeys.count(); int shortcutCount = shortcutKeys.count();
shortcutsWidget->setRowCount( shortcutCount ); shortcutsWidget->setRowCount( shortcutCount );
@ -242,7 +251,7 @@ void PropertiesDialog::saveShortcuts()
for( int x=0; x < shortcutCount; x++ ) for( int x=0; x < shortcutCount; x++ )
{ {
QString keyValue = shortcutKeys.at(x); QString keyValue = shortcutKeys.at(x);
QAction *keyAction = Properties::Instance()->actions[keyValue]; QAction *keyAction = actions[keyValue];
QTableWidgetItem *item = shortcutsWidget->item(x, 1); QTableWidgetItem *item = shortcutsWidget->item(x, 1);
QKeySequence sequence = QKeySequence(item->text()); QKeySequence sequence = QKeySequence(item->text());
@ -253,11 +262,13 @@ void PropertiesDialog::saveShortcuts()
shortcuts.append(QKeySequence(sequenceString)); shortcuts.append(QKeySequence(sequenceString));
keyAction->setShortcuts(shortcuts); keyAction->setShortcuts(shortcuts);
} }
Properties::Instance()->saveSettings();
} }
void PropertiesDialog::setupShortcuts() void PropertiesDialog::setupShortcuts()
{ {
QList< QString > shortcutKeys = Properties::Instance()->actions.keys(); QMap<QString, QAction*> actions = QTerminalApp::Instance()->getWindowList()[0]->leaseActions();
QList< QString > shortcutKeys = actions.keys();
int shortcutCount = shortcutKeys.count(); int shortcutCount = shortcutKeys.count();
shortcutsWidget->setRowCount( shortcutCount ); shortcutsWidget->setRowCount( shortcutCount );
@ -265,10 +276,10 @@ void PropertiesDialog::setupShortcuts()
for( int x=0; x < shortcutCount; x++ ) for( int x=0; x < shortcutCount; x++ )
{ {
QString keyValue = shortcutKeys.at(x); QString keyValue = shortcutKeys.at(x);
QAction *keyAction = Properties::Instance()->actions[keyValue]; QAction *keyAction = actions[keyValue];
QStringList sequenceStrings; QStringList sequenceStrings;
foreach (QKeySequence shortcut, keyAction->shortcuts()) foreach (const QKeySequence &shortcut, keyAction->shortcuts())
sequenceStrings.append(shortcut.toString()); sequenceStrings.append(shortcut.toString());
QTableWidgetItem *itemName = new QTableWidgetItem( tr(keyValue.toStdString().c_str()) ); QTableWidgetItem *itemName = new QTableWidgetItem( tr(keyValue.toStdString().c_str()) );

@ -0,0 +1,62 @@
#ifndef QTERMINALAPP_H
#define QTERMINALAPP_H
#include <QApplication>
#ifdef HAVE_QDBUS
#include <QtDBus/QtDBus>
#endif
#include "mainwindow.h"
class QTerminalApp : public QApplication
{
Q_OBJECT
public:
MainWindow *newWindow(bool dropMode, TerminalConfig &cfg);
QList<MainWindow*> getWindowList();
void addWindow(MainWindow *window);
void removeWindow(MainWindow *window);
static QTerminalApp *Instance(int &argc, char **argv);
static QTerminalApp *Instance();
QString &getWorkingDirectory();
void setWorkingDirectory(const QString &wd);
#ifdef HAVE_QDBUS
void registerOnDbus();
QList<QDBusObjectPath> getWindows();
QDBusObjectPath newWindow(const QHash<QString,QVariant> &termArgs);
QDBusObjectPath getActiveWindow();
bool isDropMode();
bool toggleDropdown();
#endif
static void cleanup();
private:
QString m_workDir;
QList<MainWindow *> m_windowList;
static QTerminalApp *m_instance;
QTerminalApp(int &argc, char **argv);
~QTerminalApp(){};
};
template <class T> T* findParent(QObject *child)
{
QObject *maybeT = child;
while (true)
{
if (maybeT == NULL)
{
return NULL;
}
T *holder = qobject_cast<T*>(maybeT);
if (holder)
return holder;
maybeT = maybeT->parent();
}
}
#endif

@ -21,10 +21,12 @@
#include <QMouseEvent> #include <QMouseEvent>
#include <QMenu> #include <QMenu>
#include "mainwindow.h"
#include "termwidgetholder.h" #include "termwidgetholder.h"
#include "tabwidget.h" #include "tabwidget.h"
#include "config.h" #include "config.h"
#include "properties.h" #include "properties.h"
#include "qterminalapp.h"
#define TAB_INDEX_PROPERTY "tab_index" #define TAB_INDEX_PROPERTY "tab_index"
@ -59,26 +61,17 @@ TermWidgetHolder * TabWidget::terminalHolder()
return reinterpret_cast<TermWidgetHolder*>(widget(currentIndex())); return reinterpret_cast<TermWidgetHolder*>(widget(currentIndex()));
} }
void TabWidget::setWorkDirectory(const QString& dir)
{
this->work_dir = dir;
}
int TabWidget::addNewTab(const QString & shell_program) int TabWidget::addNewTab(TerminalConfig config)
{ {
tabNumerator++; tabNumerator++;
QString label = QString(tr("Shell No. %1")).arg(tabNumerator); QString label = QString(tr("Shell No. %1")).arg(tabNumerator);
TermWidgetHolder *ch = terminalHolder(); TermWidgetHolder *ch = terminalHolder();
QString cwd(work_dir); if (ch)
if (Properties::Instance()->useCWD && ch) config.provideCurrentDirectory(ch->currentTerminal()->impl()->workingDirectory());
{
cwd = ch->currentTerminal()->impl()->workingDirectory();
if (cwd.isEmpty())
cwd = work_dir;
}
TermWidgetHolder *console = new TermWidgetHolder(cwd, shell_program, this); TermWidgetHolder *console = new TermWidgetHolder(config, this);
console->setWindowTitle(label); console->setWindowTitle(label);
connect(console, SIGNAL(finished()), SLOT(removeFinished())); connect(console, SIGNAL(finished()), SLOT(removeFinished()));
connect(console, SIGNAL(lastTerminalClosed()), this, SLOT(removeFinished())); connect(console, SIGNAL(lastTerminalClosed()), this, SLOT(removeFinished()));
@ -96,29 +89,40 @@ int TabWidget::addNewTab(const QString & shell_program)
return index; return index;
} }
void TabWidget::switchNextSubterminal() void TabWidget::switchLeftSubterminal()
{ {
terminalHolder()->switchNextSubterminal(); terminalHolder()->directionalNavigation(NavigationDirection::Left);
} }
void TabWidget::switchPrevSubterminal() void TabWidget::switchRightSubterminal()
{ {
terminalHolder()->switchPrevSubterminal(); terminalHolder()->directionalNavigation(NavigationDirection::Right);
}
void TabWidget::switchTopSubterminal() {
terminalHolder()->directionalNavigation(NavigationDirection::Top);
}
void TabWidget::switchBottomSubterminal() {
terminalHolder()->directionalNavigation(NavigationDirection::Bottom);
} }
void TabWidget::splitHorizontally() void TabWidget::splitHorizontally()
{ {
terminalHolder()->splitHorizontal(terminalHolder()->currentTerminal()); terminalHolder()->splitHorizontal(terminalHolder()->currentTerminal());
findParent<MainWindow>(this)->updateDisabledActions();
} }
void TabWidget::splitVertically() void TabWidget::splitVertically()
{ {
terminalHolder()->splitVertical(terminalHolder()->currentTerminal()); terminalHolder()->splitVertical(terminalHolder()->currentTerminal());
findParent<MainWindow>(this)->updateDisabledActions();
} }
void TabWidget::splitCollapse() void TabWidget::splitCollapse()
{ {
terminalHolder()->splitCollapse(terminalHolder()->currentTerminal()); terminalHolder()->splitCollapse(terminalHolder()->currentTerminal());
findParent<MainWindow>(this)->updateDisabledActions();
} }
void TabWidget::copySelection() void TabWidget::copySelection()
@ -206,10 +210,11 @@ void TabWidget::renameTabsAfterRemove()
void TabWidget::contextMenuEvent(QContextMenuEvent *event) void TabWidget::contextMenuEvent(QContextMenuEvent *event)
{ {
QMenu menu(this); QMenu menu(this);
QMap< QString, QAction * > actions = findParent<MainWindow>(this)->leaseActions();
QAction *close = menu.addAction(QIcon::fromTheme("document-close"), tr("Close session")); QAction *close = menu.addAction(QIcon::fromTheme("document-close"), tr("Close session"));
QAction *rename = menu.addAction(Properties::Instance()->actions[RENAME_SESSION]->text()); QAction *rename = menu.addAction(actions[RENAME_SESSION]->text());
rename->setShortcut(Properties::Instance()->actions[RENAME_SESSION]->shortcut()); rename->setShortcut(actions[RENAME_SESSION]->shortcut());
rename->blockSignals(true); rename->blockSignals(true);
int tabIndex = tabBar()->tabAt(event->pos()); int tabIndex = tabBar()->tabAt(event->pos());
@ -230,7 +235,10 @@ bool TabWidget::eventFilter(QObject *obj, QEvent *event)
// clicks on free space - open new tab // clicks on free space - open new tab
int index = tabBar()->tabAt(e->pos()); int index = tabBar()->tabAt(e->pos());
if (index == -1) if (index == -1)
addNewTab(); {
TerminalConfig defaultConfig;
addNewTab(defaultConfig);
}
else else
renameSession(index); renameSession(index);
return true; return true;
@ -299,6 +307,7 @@ int TabWidget::switchToRight()
setCurrentIndex(next_pos); setCurrentIndex(next_pos);
else else
setCurrentIndex(0); setCurrentIndex(0);
findParent<MainWindow>(this)->updateDisabledActions();
return currentIndex(); return currentIndex();
} }
@ -309,6 +318,7 @@ int TabWidget::switchToLeft()
setCurrentIndex(count() - 1); setCurrentIndex(count() - 1);
else else
setCurrentIndex(previous_pos); setCurrentIndex(previous_pos);
findParent<MainWindow>(this)->updateDisabledActions();
return currentIndex(); return currentIndex();
} }
@ -426,33 +436,36 @@ void TabWidget::loadSession()
void TabWidget::preset2Horizontal() void TabWidget::preset2Horizontal()
{ {
int ix = TabWidget::addNewTab(); TerminalConfig defaultConfig;
int ix = TabWidget::addNewTab(defaultConfig);
TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix)); TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix));
term->splitHorizontal(term->currentTerminal()); term->splitHorizontal(term->currentTerminal());
// switch to the 1st terminal // switch to the 1st terminal
term->switchNextSubterminal(); term->directionalNavigation(NavigationDirection::Left);
} }
void TabWidget::preset2Vertical() void TabWidget::preset2Vertical()
{ {
int ix = TabWidget::addNewTab(); TerminalConfig defaultConfig;
int ix = TabWidget::addNewTab(defaultConfig);
TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix)); TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix));
term->splitVertical(term->currentTerminal()); term->splitVertical(term->currentTerminal());
// switch to the 1st terminal // switch to the 1st terminal
term->switchNextSubterminal(); term->directionalNavigation(NavigationDirection::Left);
} }
void TabWidget::preset4Terminals() void TabWidget::preset4Terminals()
{ {
int ix = TabWidget::addNewTab(); TerminalConfig defaultConfig;
int ix = TabWidget::addNewTab(defaultConfig);
TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix)); TermWidgetHolder* term = reinterpret_cast<TermWidgetHolder*>(widget(ix));
term->splitVertical(term->currentTerminal()); term->splitVertical(term->currentTerminal());
term->splitHorizontal(term->currentTerminal()); term->splitHorizontal(term->currentTerminal());
term->switchNextSubterminal(); term->directionalNavigation(NavigationDirection::Left);
term->switchNextSubterminal();
term->splitHorizontal(term->currentTerminal()); term->splitHorizontal(term->currentTerminal());
// switch to the 1st terminal // switch to the 1st terminal
term->switchNextSubterminal(); term->directionalNavigation(NavigationDirection::Top);
} }
void TabWidget::showHideTabBar() void TabWidget::showHideTabBar()

@ -21,7 +21,14 @@
#include <QTabWidget> #include <QTabWidget>
#include <QMap> #include <QMap>
#include <QAction>
#ifdef HAVE_QDBUS
#include <QtDBus/QtDBus>
#include "dbusaddressable.h"
#endif
#include "terminalconfig.h"
#include "properties.h" #include "properties.h"
class TermWidgetHolder; class TermWidgetHolder;
@ -40,7 +47,7 @@ public:
void showHideTabBar(); void showHideTabBar();
public slots: public slots:
int addNewTab(const QString& shell_program = QString()); int addNewTab(TerminalConfig cfg);
void removeTab(int); void removeTab(int);
void removeCurrentTab(); void removeCurrentTab();
int switchToRight(); int switchToRight();
@ -50,10 +57,12 @@ public slots:
void moveRight(); void moveRight();
void renameSession(int); void renameSession(int);
void renameCurrentSession(); void renameCurrentSession();
void setWorkDirectory(const QString&);
void switchNextSubterminal(); void switchLeftSubterminal();
void switchPrevSubterminal(); void switchRightSubterminal();
void switchTopSubterminal();
void switchBottomSubterminal();
void splitHorizontally(); void splitHorizontally();
void splitVertically(); void splitVertically();
void splitCollapse(); void splitCollapse();
@ -100,7 +109,6 @@ protected slots:
private: private:
int tabNumerator; int tabNumerator;
QString work_dir;
/* re-order naming of the tabs then removeCurrentTab() */ /* re-order naming of the tabs then removeCurrentTab() */
void renameTabsAfterRemove(); void renameTabsAfterRemove();
}; };

@ -0,0 +1,105 @@
#include <QHash>
#include <QString>
#include "qterminalapp.h"
#include "terminalconfig.h"
#include "properties.h"
#include "termwidget.h"
TerminalConfig::TerminalConfig(const QString & wdir, const QString & shell)
{
m_workingDirectory = wdir;
m_shell = shell;
}
TerminalConfig::TerminalConfig()
{
}
TerminalConfig::TerminalConfig(const TerminalConfig &cfg)
: m_currentDirectory(cfg.m_currentDirectory),
m_workingDirectory(cfg.m_workingDirectory),
m_shell(cfg.m_shell) {}
QString TerminalConfig::getWorkingDirectory()
{
if (!m_workingDirectory.isEmpty())
return m_workingDirectory;
if (Properties::Instance()->useCWD && !m_currentDirectory.isEmpty())
return m_currentDirectory;
return QTerminalApp::Instance()->getWorkingDirectory();
}
QString TerminalConfig::getShell()
{
if (!m_shell.isEmpty())
return m_shell;
if (!Properties::Instance()->shell.isEmpty())
return Properties::Instance()->shell;
QByteArray envShell = qgetenv("SHELL");
if (envShell.constData() != NULL)
{
QString shellString = QString(envShell);
if (!shellString.isEmpty())
return shellString;
}
return QString();
}
void TerminalConfig::setWorkingDirectory(const QString &val)
{
m_workingDirectory = val;
}
void TerminalConfig::setShell(const QString &val)
{
m_shell = val;
}
void TerminalConfig::provideCurrentDirectory(const QString &val)
{
m_currentDirectory = val;
}
#if HAVE_QDBUS
#define DBUS_ARG_WORKDIR "workingDirectory"
#define DBUS_ARG_SHELL "shell"
TerminalConfig TerminalConfig::fromDbus(const QHash<QString,QVariant> &termArgsConst, TermWidget *toSplit)
{
QHash<QString,QVariant> termArgs(termArgsConst);
if (toSplit != NULL && !termArgs.contains(DBUS_ARG_WORKDIR))
{
termArgs[DBUS_ARG_WORKDIR] = QVariant(toSplit->impl()->workingDirectory());
}
return TerminalConfig::fromDbus(termArgs);
}
static QString variantToString(QVariant variant, QString &defaultVal)
{
if (variant.type() == QVariant::String)
return qvariant_cast<QString>(variant);
return defaultVal;
}
TerminalConfig TerminalConfig::fromDbus(const QHash<QString,QVariant> &termArgs)
{
QString wdir("");
QString shell(Properties::Instance()->shell);
if (termArgs.contains(DBUS_ARG_WORKDIR))
{
wdir = variantToString(termArgs[DBUS_ARG_WORKDIR], wdir);
}
if (termArgs.contains(DBUS_ARG_SHELL)) {
shell = variantToString(termArgs[DBUS_ARG_SHELL], shell);
}
return TerminalConfig(wdir, shell);
}
#endif

@ -0,0 +1,38 @@
#ifndef TERMINALCONFIG_H
#define TERMINALCONFIG_H
#include <QHash>
#include <QString>
#include <QVariant>
class TermWidget;
class TerminalConfig
{
public:
TerminalConfig(const QString & wdir, const QString & shell);
TerminalConfig(const TerminalConfig &cfg);
TerminalConfig();
QString getWorkingDirectory();
QString getShell();
void setWorkingDirectory(const QString &val);
void setShell(const QString &val);
void provideCurrentDirectory(const QString &val);
#ifdef HAVE_QDBUS
static TerminalConfig fromDbus(const QHash<QString,QVariant> &termArgs);
static TerminalConfig fromDbus(const QHash<QString,QVariant> &termArgs, TermWidget *toSplit);
#endif
private:
// True when
QString m_currentDirectory;
QString m_workingDirectory;
QString m_shell;
};
#endif

@ -20,16 +20,28 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QPainter> #include <QPainter>
#include <QDesktopServices> #include <QDesktopServices>
#include <QMessageBox>
#include <QAbstractButton>
#include <QMouseEvent>
#include <assert.h>
#ifdef HAVE_QDBUS
#include <QtDBus/QtDBus>
#include "termwidgetholder.h"
#include "terminaladaptor.h"
#endif
#include "mainwindow.h"
#include "termwidget.h" #include "termwidget.h"
#include "config.h" #include "config.h"
#include "properties.h" #include "properties.h"
#include "mainwindow.h" #include "qterminalapp.h"
static int TermWidgetCount = 0; static int TermWidgetCount = 0;
TermWidgetImpl::TermWidgetImpl(const QString & wdir, const QString & shell, QWidget * parent) TermWidgetImpl::TermWidgetImpl(TerminalConfig &cfg, QWidget * parent)
: QTermWidget(0, parent) : QTermWidget(0, parent)
{ {
TermWidgetCount++; TermWidgetCount++;
@ -43,17 +55,12 @@ TermWidgetImpl::TermWidgetImpl(const QString & wdir, const QString & shell, QWid
setHistorySize(5000); setHistorySize(5000);
if (!wdir.isNull()) setWorkingDirectory(cfg.getWorkingDirectory());
setWorkingDirectory(wdir);
if (shell.isNull()) QString shell = cfg.getShell();
{ if (!shell.isEmpty())
if (!Properties::Instance()->shell.isNull())
setShellProgram(Properties::Instance()->shell);
}
else
{ {
qDebug() << "Settings custom shell program:" << shell; qDebug() << "Shell program:" << shell;
QStringList parts = shell.split(QRegExp("\\s+"), QString::SkipEmptyParts); QStringList parts = shell.split(QRegExp("\\s+"), QString::SkipEmptyParts);
qDebug() << parts; qDebug() << parts;
setShellProgram(parts.at(0)); setShellProgram(parts.at(0));
@ -109,14 +116,14 @@ void TermWidgetImpl::propertiesChanged()
switch(Properties::Instance()->keyboardCursorShape) { switch(Properties::Instance()->keyboardCursorShape) {
case 1: case 1:
setKeyboardCursorShape(QTermWidget::UnderlineCursor); setKeyboardCursorShape(QTermWidget::KeyboardCursorShape::UnderlineCursor);
break; break;
case 2: case 2:
setKeyboardCursorShape(QTermWidget::IBeamCursor); setKeyboardCursorShape(QTermWidget::KeyboardCursorShape::IBeamCursor);
break; break;
default: default:
case 0: case 0:
setKeyboardCursorShape(QTermWidget::BlockCursor); setKeyboardCursorShape(QTermWidget::KeyboardCursorShape::BlockCursor);
break; break;
} }
@ -125,20 +132,36 @@ void TermWidgetImpl::propertiesChanged()
void TermWidgetImpl::customContextMenuCall(const QPoint & pos) void TermWidgetImpl::customContextMenuCall(const QPoint & pos)
{ {
QMenu* contextMenu = new QMenu(this); QMenu menu;
QMap<QString, QAction*> actions = findParent<MainWindow>(this)->leaseActions();
QList<QAction*> actions = filterActions(pos); QList<QAction*> extraActions = filterActions(pos);
for (auto& action : actions) for (auto& action : extraActions)
{ {
contextMenu->addAction(action); menu.addAction(action);
} }
contextMenu->addSeparator(); if (!actions.isEmpty())
{
const MainWindow *main = qobject_cast<MainWindow*>(window()); menu.addSeparator();
main->setup_ContextMenu_Actions(contextMenu); }
contextMenu->exec(mapToGlobal(pos)); menu.addAction(actions[COPY_SELECTION]);
menu.addAction(actions[PASTE_CLIPBOARD]);
menu.addAction(actions[PASTE_SELECTION]);
menu.addAction(actions[ZOOM_IN]);
menu.addAction(actions[ZOOM_OUT]);
menu.addAction(actions[ZOOM_RESET]);
menu.addSeparator();
menu.addAction(actions[CLEAR_TERMINAL]);
menu.addAction(actions[SPLIT_HORIZONTAL]);
menu.addAction(actions[SPLIT_VERTICAL]);
// warning TODO/FIXME: disable the action when there is only one terminal
menu.addAction(actions[SUB_COLLAPSE]);
menu.addSeparator();
menu.addAction(actions[TOGGLE_MENU]);
menu.addAction(actions[PREFERENCES]);
menu.exec(mapToGlobal(pos));
} }
void TermWidgetImpl::zoomIn() void TermWidgetImpl::zoomIn()
@ -171,17 +194,106 @@ void TermWidgetImpl::activateUrl(const QUrl & url, bool fromContextMenu) {
} }
} }
TermWidget::TermWidget(const QString & wdir, const QString & shell, QWidget * parent) void TermWidgetImpl::pasteSelection()
: QWidget(parent) {
paste(QClipboard::Selection);
}
void TermWidgetImpl::pasteClipboard()
{
paste(QClipboard::Clipboard);
}
void TermWidgetImpl::paste(QClipboard::Mode mode)
{
// Paste Clipboard by simulating keypress events
QString text = QApplication::clipboard()->text(mode);
if ( ! text.isEmpty() )
{
text.replace("\r\n", "\n");
text.replace('\n', '\r');
QString trimmedTrailingNl(text);
trimmedTrailingNl.replace(QRegExp("\\r+$"), "");
bool isMultiline = trimmedTrailingNl.contains('\r');
if (!isMultiline && Properties::Instance()->trimPastedTrailingNewlines)
{
text = trimmedTrailingNl;
}
if (Properties::Instance()->confirmMultilinePaste)
{
if (text.contains('\r') && Properties::Instance()->confirmMultilinePaste)
{
QMessageBox confirmation(this);
confirmation.setWindowTitle(tr("Paste multiline text"));
confirmation.setText(tr("Are you sure you want to paste this text?"));
confirmation.setDetailedText(text);
confirmation.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
// Click "Show details..." to show those by default
foreach( QAbstractButton * btn, confirmation.buttons() )
{
if (confirmation.buttonRole(btn) == QMessageBox::ActionRole && btn->text() == QMessageBox::tr("Show Details..."))
{
btn->clicked();
break;
}
}
confirmation.setDefaultButton(QMessageBox::Yes);
confirmation.exec();
if (confirmation.standardButton(confirmation.clickedButton()) != QMessageBox::Yes)
{
return;
}
}
}
/* TODO: Support bracketedPasteMode
if (bracketedPasteMode())
{
text.prepend("\e[200~");
text.append("\e[201~");
}*/
sendText(text);
}
}
bool TermWidget::eventFilter(QObject * obj, QEvent * ev)
{
if (ev->type() == QEvent::MouseButtonPress)
{
QMouseEvent *mev = (QMouseEvent *)ev;
if ( mev->button() == Qt::MidButton )
{
impl()->pasteSelection();
return true;
}
}
return false;
}
TermWidget::TermWidget(TerminalConfig &cfg, QWidget * parent)
: QWidget(parent),
DBusAddressable("/terminals")
{ {
#ifdef HAVE_QDBUS
registerAdapter<TerminalAdaptor, TermWidget>(this);
#endif
m_border = palette().color(QPalette::Window); m_border = palette().color(QPalette::Window);
m_term = new TermWidgetImpl(wdir, shell, this); m_term = new TermWidgetImpl(cfg, this);
setFocusProxy(m_term); setFocusProxy(m_term);
m_layout = new QVBoxLayout; m_layout = new QVBoxLayout;
setLayout(m_layout); setLayout(m_layout);
m_layout->addWidget(m_term); m_layout->addWidget(m_term);
foreach (QObject *o, m_term->children())
{
// Find TerminalDisplay
if (!o->isWidgetType() || qobject_cast<QWidget*>(o)->isHidden())
continue;
o->installEventFilter(this);
}
propertiesChanged(); propertiesChanged();
@ -216,10 +328,52 @@ void TermWidget::term_termLostFocus()
void TermWidget::paintEvent (QPaintEvent *) void TermWidget::paintEvent (QPaintEvent *)
{ {
QPainter p(this); if (Properties::Instance()->highlightCurrentTerminal)
QPen pen(m_border); {
pen.setWidth(30); QPainter p(this);
pen.setBrush(m_border); QPen pen(m_border);
p.setPen(pen); pen.setWidth(3);
p.drawRect(0, 0, width()-1, height()-1); pen.setBrush(m_border);
p.setPen(pen);
p.drawRect(0, 0, width()-1, height()-1);
}
}
#if HAVE_QDBUS
QDBusObjectPath TermWidget::splitHorizontal(const QHash<QString,QVariant> &termArgs)
{
TermWidgetHolder *holder = findParent<TermWidgetHolder>(this);
assert(holder != NULL);
TerminalConfig cfg = TerminalConfig::fromDbus(termArgs, this);
return holder->split(this, Qt::Horizontal, cfg)->getDbusPath();
}
QDBusObjectPath TermWidget::splitVertical(const QHash<QString,QVariant> &termArgs)
{
TermWidgetHolder *holder = findParent<TermWidgetHolder>(this);
assert(holder != NULL);
TerminalConfig cfg = TerminalConfig::fromDbus(termArgs, this);
return holder->split(this, Qt::Vertical, cfg)->getDbusPath();
} }
QDBusObjectPath TermWidget::getTab()
{
return findParent<TermWidgetHolder>(this)->getDbusPath();
}
void TermWidget::closeTerminal()
{
TermWidgetHolder *holder = findParent<TermWidgetHolder>(this);
holder->splitCollapse(this);
}
void TermWidget::sendText(const QString text)
{
if (impl())
{
impl()->sendText(text);
}
}
#endif

@ -20,9 +20,11 @@
#define TERMWIDGET_H #define TERMWIDGET_H
#include <qtermwidget.h> #include <qtermwidget.h>
#include "terminalconfig.h"
#include <QClipboard>
#include <QAction> #include <QAction>
#include "dbusaddressable.h"
class TermWidgetImpl : public QTermWidget class TermWidgetImpl : public QTermWidget
{ {
@ -32,8 +34,9 @@ class TermWidgetImpl : public QTermWidget
public: public:
TermWidgetImpl(const QString & wdir, const QString & shell=QString(), QWidget * parent=0); TermWidgetImpl(TerminalConfig &cfg, QWidget * parent=0);
void propertiesChanged(); void propertiesChanged();
void paste(QClipboard::Mode mode);
signals: signals:
void renameSession(); void renameSession();
@ -43,6 +46,8 @@ class TermWidgetImpl : public QTermWidget
void zoomIn(); void zoomIn();
void zoomOut(); void zoomOut();
void zoomReset(); void zoomReset();
void pasteSelection();
void pasteClipboard();
private slots: private slots:
void customContextMenuCall(const QPoint & pos); void customContextMenuCall(const QPoint & pos);
@ -50,7 +55,7 @@ class TermWidgetImpl : public QTermWidget
}; };
class TermWidget : public QWidget class TermWidget : public QWidget, public DBusAddressable
{ {
Q_OBJECT Q_OBJECT
@ -59,13 +64,21 @@ class TermWidget : public QWidget
QColor m_border; QColor m_border;
public: public:
TermWidget(const QString & wdir, const QString & shell=QString(), QWidget * parent=0); TermWidget(TerminalConfig &cfg, QWidget * parent=0);
void propertiesChanged(); void propertiesChanged();
QStringList availableKeyBindings() { return m_term->availableKeyBindings(); } QStringList availableKeyBindings() { return m_term->availableKeyBindings(); }
TermWidgetImpl * impl() { return m_term; } TermWidgetImpl * impl() { return m_term; }
#ifdef HAVE_QDBUS
QDBusObjectPath splitHorizontal(const QHash<QString,QVariant> &termArgs);
QDBusObjectPath splitVertical(const QHash<QString,QVariant> &termArgs);
QDBusObjectPath getTab();
void sendText(const QString text);
void closeTerminal();
#endif
signals: signals:
void finished(); void finished();
void renameSession(); void renameSession();
@ -80,6 +93,7 @@ class TermWidget : public QWidget
protected: protected:
void paintEvent (QPaintEvent * event); void paintEvent (QPaintEvent * event);
bool eventFilter(QObject * obj, QEvent * evt) override;
private slots: private slots:
void term_termGetFocus(); void term_termGetFocus();

@ -20,18 +20,31 @@
#include <QSplitter> #include <QSplitter>
#include <QInputDialog> #include <QInputDialog>
#ifdef HAVE_QDBUS
#include <QtDBus/QtDBus>
#include "tabadaptor.h"
#endif
#include "qterminalapp.h"
#include "mainwindow.h"
#include "termwidgetholder.h" #include "termwidgetholder.h"
#include "termwidget.h" #include "termwidget.h"
#include "properties.h" #include "properties.h"
#include <assert.h> #include <assert.h>
#include <climits>
#include <algorithm>
TermWidgetHolder::TermWidgetHolder(const QString & wdir, const QString & shell, QWidget * parent) TermWidgetHolder::TermWidgetHolder(TerminalConfig &config, QWidget * parent)
: QWidget(parent), : QWidget(parent)
m_wdir(wdir), #ifdef HAVE_QDBUS
m_shell(shell), , DBusAddressable("/tabs")
m_currentTerm(0) #endif
{ {
#ifdef HAVE_QDBUS
new TabAdaptor(this);
QDBusConnection::sessionBus().registerObject(getDbusPathString(), this);
#endif
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
QGridLayout * lay = new QGridLayout(this); QGridLayout * lay = new QGridLayout(this);
lay->setSpacing(0); lay->setSpacing(0);
@ -39,9 +52,10 @@ TermWidgetHolder::TermWidgetHolder(const QString & wdir, const QString & shell,
QSplitter *s = new QSplitter(this); QSplitter *s = new QSplitter(this);
s->setFocusPolicy(Qt::NoFocus); s->setFocusPolicy(Qt::NoFocus);
TermWidget *w = newTerm(); TermWidget *w = newTerm(config);
s->addWidget(w); s->addWidget(w);
lay->addWidget(s); lay->addWidget(s);
m_currentTerm = w;
setLayout(lay); setLayout(lay);
} }
@ -124,33 +138,64 @@ void TermWidgetHolder::setWDir(const QString & wdir)
m_wdir = wdir; m_wdir = wdir;
} }
void TermWidgetHolder::switchNextSubterminal() typedef struct {
{ QPoint topLeft;
// TODO/FIXME: merge switchPrevSubterminal with switchNextSubterminal QPoint middle;
QList<TermWidget*> l = findChildren<TermWidget*>(); QPoint bottomRight;
int ix = -1; } NavigationData;
foreach (TermWidget * w, l)
{ static void transpose(QPoint *point) {
++ix; int x = point->x();
if (w->impl()->hasFocus()) point->setX(point->y());
{ point->setY(x);
}
static void transposeTransform(NavigationData *point) {
transpose(&point->topLeft);
transpose(&point->middle);
transpose(&point->bottomRight);
}
static void flipTransform(NavigationData *point) {
QPoint oldTopLeft = point->topLeft;
point->topLeft = -(point->bottomRight);
point->bottomRight = -(oldTopLeft);
point->middle = -(point->middle);
}
static void normalizeToRight(NavigationData *point, NavigationDirection dir) {
switch (dir) {
case Left:
flipTransform(point);
break; break;
} case Right:
// No-op
break;
case Top:
flipTransform(point);
transposeTransform(point);
break;
case Bottom:
transposeTransform(point);
break;
default:
assert("Invalid navigation");
return;
} }
}
if (ix < l.count()-1) static NavigationData getNormalizedDimensions(QWidget *w, NavigationDirection dir) {
{ NavigationData nd;
l.at(ix+1)->impl()->setFocus(Qt::OtherFocusReason); nd.topLeft = w->mapTo(w->window(), QPoint(0, 0));
} nd.middle = w->mapTo(w->window(), QPoint(w->width() / 2, w->height() / 2));
else if (ix == l.count()-1) nd.bottomRight = w->mapTo(w->window(), QPoint(w->width(), w->height()));
{ normalizeToRight(&nd, dir);
l.at(0)->impl()->setFocus(Qt::OtherFocusReason); return nd;
}
} }
void TermWidgetHolder::switchPrevSubterminal()
{ void TermWidgetHolder::directionalNavigation(NavigationDirection dir) {
// TODO/FIXME: merge switchPrevSubterminal with switchNextSubterminal // Find an active widget
QList<TermWidget*> l = findChildren<TermWidget*>(); QList<TermWidget*> l = findChildren<TermWidget*>();
int ix = -1; int ix = -1;
foreach (TermWidget * w, l) foreach (TermWidget * w, l)
@ -161,14 +206,50 @@ void TermWidgetHolder::switchPrevSubterminal()
break; break;
} }
} }
if (ix > l.count())
if (ix > 0)
{ {
l.at(ix-1)->impl()->setFocus(Qt::OtherFocusReason); l.at(0)->impl()->setFocus(Qt::OtherFocusReason);
return;
} }
else if (ix == 0)
// Found an active widget
TermWidget *w = l.at(ix);
NavigationData from = getNormalizedDimensions(w, dir);
// Search parent that contains point of interest (right edge middlepoint)
QPoint poi = QPoint(from.bottomRight.x(), from.middle.y());
// Perform a search for a TermWidget, where x() is strictly higher than
// poi.x(), y() is strictly less than poi.y(), and prioritizing, in order,
// lower x(), and lower distance between poi.y() and corners.
// Only "Right navigation" implementation is necessary -- other cases
// are normalized to this one.
l = findChildren<TermWidget*>();
int lowestX = INT_MAX;
int lowestMidpointDistance = INT_MAX;
TermWidget *fittest = NULL;
foreach (TermWidget * w, l)
{ {
l.at(l.count()-1)->impl()->setFocus(Qt::OtherFocusReason); NavigationData contenderDims = getNormalizedDimensions(w, dir);
int midpointDistance = std::min(
abs(poi.y() - contenderDims.topLeft.y()),
abs(poi.y() - contenderDims.bottomRight.y())
);
if (contenderDims.topLeft.x() > poi.x())
{
if (contenderDims.topLeft.x() > lowestX)
continue;
if (midpointDistance > lowestMidpointDistance)
continue;
lowestX = contenderDims.topLeft.x();
lowestMidpointDistance = midpointDistance;
fittest = w;
}
}
if (fittest != NULL) {
fittest->impl()->setFocus(Qt::OtherFocusReason);
} }
} }
@ -185,12 +266,14 @@ void TermWidgetHolder::propertiesChanged()
void TermWidgetHolder::splitHorizontal(TermWidget * term) void TermWidgetHolder::splitHorizontal(TermWidget * term)
{ {
split(term, Qt::Vertical); TerminalConfig defaultConfig;
split(term, Qt::Vertical, defaultConfig);
} }
void TermWidgetHolder::splitVertical(TermWidget * term) void TermWidgetHolder::splitVertical(TermWidget * term)
{ {
split(term, Qt::Horizontal); TerminalConfig defaultConfig;
split(term, Qt::Horizontal, defaultConfig);
} }
void TermWidgetHolder::splitCollapse(TermWidget * term) void TermWidgetHolder::splitCollapse(TermWidget * term)
@ -242,7 +325,7 @@ void TermWidgetHolder::splitCollapse(TermWidget * term)
emit finished(); emit finished();
} }
void TermWidgetHolder::split(TermWidget *term, Qt::Orientation orientation) TermWidget * TermWidgetHolder::split(TermWidget *term, Qt::Orientation orientation, TerminalConfig cfg)
{ {
QSplitter *parent = qobject_cast<QSplitter *>(term->parent()); QSplitter *parent = qobject_cast<QSplitter *>(term->parent());
assert(parent); assert(parent);
@ -257,16 +340,9 @@ void TermWidgetHolder::split(TermWidget *term, Qt::Orientation orientation)
s->setFocusPolicy(Qt::NoFocus); s->setFocusPolicy(Qt::NoFocus);
s->insertWidget(0, term); s->insertWidget(0, term);
// wdir settings cfg.provideCurrentDirectory(term->impl()->workingDirectory());
QString wd(m_wdir);
if (Properties::Instance()->useCWD) TermWidget * w = newTerm(cfg);
{
wd = term->impl()->workingDirectory();
if (wd.isEmpty())
wd = m_wdir;
}
TermWidget * w = newTerm(wd);
s->insertWidget(1, w); s->insertWidget(1, w);
s->setSizes(sizes); s->setSizes(sizes);
@ -274,19 +350,12 @@ void TermWidgetHolder::split(TermWidget *term, Qt::Orientation orientation)
parent->setSizes(parentSizes); parent->setSizes(parentSizes);
w->setFocus(Qt::OtherFocusReason); w->setFocus(Qt::OtherFocusReason);
return w;
} }
TermWidget *TermWidgetHolder::newTerm(const QString & wdir, const QString & shell) TermWidget *TermWidgetHolder::newTerm(TerminalConfig &cfg)
{ {
QString wd(wdir); TermWidget *w = new TermWidget(cfg, this);
if (wd.isEmpty())
wd = m_wdir;
QString sh(shell);
if (shell.isEmpty())
sh = m_shell;
TermWidget *w = new TermWidget(wd, sh, this);
// proxy signals // proxy signals
connect(w, SIGNAL(renameSession()), this, SIGNAL(renameSession())); connect(w, SIGNAL(renameSession()), this, SIGNAL(renameSession()));
connect(w, SIGNAL(removeCurrentSession()), this, SIGNAL(lastTerminalClosed())); connect(w, SIGNAL(removeCurrentSession()), this, SIGNAL(lastTerminalClosed()));
@ -339,3 +408,40 @@ void TermWidgetHolder::onTermTitleChanged(QString title, QString icon) const
if (m_currentTerm == term) if (m_currentTerm == term)
emit termTitleChanged(title, icon); emit termTitleChanged(title, icon);
} }
#ifdef HAVE_QDBUS
QDBusObjectPath TermWidgetHolder::getActiveTerminal()
{
if (m_currentTerm != NULL)
{
return m_currentTerm->getDbusPath();
}
return QDBusObjectPath();
}
QList<QDBusObjectPath> TermWidgetHolder::getTerminals()
{
QList<QDBusObjectPath> terminals;
foreach (TermWidget* w, findChildren<TermWidget*>())
{
terminals.push_back(w->getDbusPath());
}
return terminals;
}
QDBusObjectPath TermWidgetHolder::getWindow()
{
return findParent<MainWindow>(this)->getDbusPath();
}
void TermWidgetHolder::closeTab()
{
QTabWidget *parent = findParent<QTabWidget>(this);
int idx = parent->indexOf(this);
assert(idx != -1);
parent->tabCloseRequested(idx);
}
#endif

@ -21,10 +21,20 @@
#include <QWidget> #include <QWidget>
#include "termwidget.h" #include "termwidget.h"
#include "terminalconfig.h"
#include "dbusaddressable.h"
class QSplitter; class QSplitter;
typedef enum NavigationDirection {
Left,
Right,
Top,
Bottom
} NavigationDirection;
/*! \brief TermWidget group/session manager. /*! \brief TermWidget group/session manager.
This widget (one per TabWidget tab) is a "proxy" widget beetween TabWidget and This widget (one per TabWidget tab) is a "proxy" widget beetween TabWidget and
@ -34,11 +44,14 @@ for TabWidget - with its signals and slots.
Splitting and collapsing of TermWidgets is done here. Splitting and collapsing of TermWidgets is done here.
*/ */
class TermWidgetHolder : public QWidget class TermWidgetHolder : public QWidget
#ifdef HAVE_QDBUS
, public DBusAddressable
#endif
{ {
Q_OBJECT Q_OBJECT
public: public:
TermWidgetHolder(const QString & wdir, const QString & shell=QString(), QWidget * parent=0); TermWidgetHolder(TerminalConfig &cfg, QWidget * parent=0);
~TermWidgetHolder(); ~TermWidgetHolder();
void propertiesChanged(); void propertiesChanged();
@ -50,14 +63,22 @@ class TermWidgetHolder : public QWidget
void zoomOut(uint step); void zoomOut(uint step);
TermWidget* currentTerminal(); TermWidget* currentTerminal();
TermWidget* split(TermWidget * term, Qt::Orientation orientation, TerminalConfig cfg);
#ifdef HAVE_QDBUS
QDBusObjectPath getActiveTerminal();
QList<QDBusObjectPath> getTerminals();
QDBusObjectPath getWindow();
void closeTab();
#endif
public slots: public slots:
void splitHorizontal(TermWidget * term); void splitHorizontal(TermWidget * term);
void splitVertical(TermWidget * term); void splitVertical(TermWidget * term);
void splitCollapse(TermWidget * term); void splitCollapse(TermWidget * term);
void setWDir(const QString & wdir); void setWDir(const QString & wdir);
void switchNextSubterminal(); void directionalNavigation(NavigationDirection dir);
void switchPrevSubterminal();
void clearActiveTerminal(); void clearActiveTerminal();
void onTermTitleChanged(QString title, QString icon) const; void onTermTitleChanged(QString title, QString icon) const;
@ -73,7 +94,7 @@ class TermWidgetHolder : public QWidget
TermWidget * m_currentTerm; TermWidget * m_currentTerm;
void split(TermWidget * term, Qt::Orientation orientation); void split(TermWidget * term, Qt::Orientation orientation);
TermWidget * newTerm(const QString & wdir=QString(), const QString & shell=QString()); TermWidget * newTerm(TerminalConfig &cfg);
private slots: private slots:
void setCurrentTerminal(TermWidget* term); void setCurrentTerminal(TermWidget* term);

Loading…
Cancel
Save