diff --git a/.travis.yml b/.travis.yml index a87cc5bc6..e5bb3089b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,11 @@ dist: trusty language: cpp cache: ccache -# regex is for release tags +# regex is for master, release branches, and release tags branches: only: - master + - /^v\d+\.\d+-dev$/ - /^v(\d+\.){2}\d+$/ stages: diff --git a/src/chatlog/chatlog.cpp b/src/chatlog/chatlog.cpp index face3aa8d..a1e615461 100644 --- a/src/chatlog/chatlog.cpp +++ b/src/chatlog/chatlog.cpp @@ -34,6 +34,9 @@ #include #include +#include +#include + /** * @var ChatLog::repNameAfter * @brief repetition interval sender name (sec) @@ -454,6 +457,8 @@ void ChatLog::insertChatlinesOnTop(const QList& newLines) lines = combLines; + moveSelectionRectDownIfMulti(newLines.size()); + scene->setItemIndexMethod(oldIndexMeth); // redo layout @@ -722,6 +727,51 @@ void ChatLog::reloadTheme() } } +/** + * @brief Adjusts the multi line selection rectangle based on chatlog changing lines + * @param offset Amount to shift selection rect up by. Must be non-negative. + */ +void ChatLog::moveSelectionRectUpIfMulti(int offset) +{ + assert(offset >= 0); + if (selectionMode != Multi) { + return; + } + if (selLastRow < offset) { // entire selection now out of bounds + clearSelection(); + return; + } else { + selLastRow -= offset; + } + selClickedRow = std::max(0, selClickedRow - offset); + selFirstRow = std::max(0, selFirstRow - offset); + updateMultiSelectionRect(); + emit selectionChanged(); +} + +/** + * @brief Adjusts the multi line selection rectangle based on chatlog changing lines + * @param offset Amount to shift selection rect down by. Must be non-negative. + */ +void ChatLog::moveSelectionRectDownIfMulti(int offset) +{ + assert(offset >= 0); + if (selectionMode != Multi) { + return; + } + const int lastLine = lines.size() - 1; + if (selFirstRow + offset > lastLine) { // entire selection now out of bounds + clearSelection(); + return; + } else { + selFirstRow += offset; + } + selClickedRow = std::min(lastLine, selClickedRow + offset); + selLastRow = std::min(lastLine, selLastRow + offset); + updateMultiSelectionRect(); + emit selectionChanged(); +} + void ChatLog::removeFirsts(const int num) { if (lines.size() > num) { @@ -734,6 +784,8 @@ void ChatLog::removeFirsts(const int num) for (int i = 0; i < lines.size(); ++i) { lines[i]->setRow(i); } + + moveSelectionRectUpIfMulti(num); } void ChatLog::removeLasts(const int num) @@ -950,7 +1002,7 @@ void ChatLog::onWorkerTimeout() verticalScrollBar()->show(); isScroll = true; - emit workerTimeoutFinished(); + emit workerTimeoutFinished(); } } diff --git a/src/chatlog/chatlog.h b/src/chatlog/chatlog.h index 81e8c1d43..c582dc621 100644 --- a/src/chatlog/chatlog.h +++ b/src/chatlog/chatlog.h @@ -58,6 +58,8 @@ public: void selectAll(); void fontChanged(const QFont& font); void reloadTheme(); + void moveSelectionRectUpIfMulti(int offset); + void moveSelectionRectDownIfMulti(int offset); void removeFirsts(const int num); void removeLasts(const int num); void setScroll(const bool scroll); diff --git a/src/main.cpp b/src/main.cpp index bc38d2712..41234a594 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -237,13 +237,12 @@ int main(int argc, char* argv[]) uint32_t profileId = settings.getCurrentProfileId(); IPC ipc(profileId); - if (!ipc.isAttached()) { - qCritical() << "Can't init IPC"; - return EXIT_FAILURE; + if (ipc.isAttached()) { + QObject::connect(&settings, &Settings::currentProfileIdChanged, &ipc, &IPC::setProfileId); + } else { + qWarning() << "Can't init IPC, maybe we're in a jail? Continuing with reduced multi-client functionality."; } - QObject::connect(&settings, &Settings::currentProfileIdChanged, &ipc, &IPC::setProfileId); - // For the auto-updater if (sodium_init() < 0) { qCritical() << "Can't init libsodium"; @@ -296,7 +295,7 @@ int main(int argc, char* argv[]) bool autoLogin = settings.getAutoLogin(); uint32_t ipcDest = 0; - bool doIpc = true; + bool doIpc = ipc.isAttached(); QString eventType, firstParam; if (parser.isSet("p")) { profileName = parser.value("p"); @@ -381,10 +380,12 @@ int main(int argc, char* argv[]) } } - // Start to accept Inter-process communication - ipc.registerEventHandler("uri", &toxURIEventHandler); - ipc.registerEventHandler("save", &toxSaveEventHandler); - ipc.registerEventHandler("activate", &toxActivateEventHandler); + if (ipc.isAttached()) { + // Start to accept Inter-process communication + ipc.registerEventHandler("uri", &toxURIEventHandler); + ipc.registerEventHandler("save", &toxSaveEventHandler); + ipc.registerEventHandler("activate", &toxActivateEventHandler); + } // Event was not handled by already running instance therefore we handle it ourselves if (eventType == "uri") diff --git a/src/persistence/history.cpp b/src/persistence/history.cpp index 41c9323d3..96c493f94 100644 --- a/src/persistence/history.cpp +++ b/src/persistence/history.cpp @@ -612,9 +612,10 @@ QList History::getUnsentMessagesForFriend(const ToxPk& fri "aliases.display_name, sender.public_key, message " "FROM history " "JOIN faux_offline_pending ON history.id = faux_offline_pending.id " - "JOIN peers chat on chat.public_key = '%1' " + "JOIN peers chat on history.chat_id = chat.id " "JOIN aliases on sender_alias = aliases.id " - "JOIN peers sender on aliases.owner = sender.id;") + "JOIN peers sender on aliases.owner = sender.id " + "WHERE chat.public_key='%1';") .arg(friendPk.toString()); QList ret; diff --git a/src/widget/form/genericchatform.cpp b/src/widget/form/genericchatform.cpp index 7cfbc5a20..02e572e3f 100644 --- a/src/widget/form/genericchatform.cpp +++ b/src/widget/form/genericchatform.cpp @@ -654,6 +654,11 @@ QDateTime GenericChatForm::getTime(const ChatLine::Ptr &chatLine) const return QDateTime(); } +/** + * @brief GenericChatForm::loadHistory load history + * @param time start date + * @param type indicates the direction of loading history + */ void GenericChatForm::loadHistory(const QDateTime &time, const LoadHistoryDialog::LoadType type) { chatWidget->clear(); @@ -669,6 +674,10 @@ void GenericChatForm::loadHistory(const QDateTime &time, const LoadHistoryDialog } } +/** + * @brief GenericChatForm::loadHistoryTo load history before to date "time" or before the first "messages" item + * @param time start date + */ void GenericChatForm::loadHistoryTo(const QDateTime &time) { chatWidget->setScroll(false); @@ -695,7 +704,12 @@ void GenericChatForm::loadHistoryTo(const QDateTime &time) } } -void GenericChatForm::loadHistoryFrom(const QDateTime &time) +/** + * @brief GenericChatForm::loadHistoryFrom load history starting from date "time" or from the last "messages" item + * @param time start date + * @return true if function loaded history else false + */ +bool GenericChatForm::loadHistoryFrom(const QDateTime &time) { chatWidget->setScroll(false); auto begin = ChatLogIdx(0); @@ -709,8 +723,19 @@ void GenericChatForm::loadHistoryFrom(const QDateTime &time) if (begin.get() + DEF_NUM_MSG_TO_LOAD > chatLog.getNextIdx().get()) { add = chatLog.getNextIdx().get() - begin.get(); } + + // The chatLog.getNextIdx() is usually 1 more than the idx on last "messages" item + // so if we have nothing to load, "add" is equal 1 + if (add <= 1) { + chatWidget->setScroll(true); + return false; + } + auto end = ChatLogIdx(begin.get() + add); + renderMessages(begin, end); + + return true; } void GenericChatForm::removeFirstsMessages(const int num) @@ -1147,11 +1172,17 @@ void GenericChatForm::goToCurrentDate() renderMessages(begin, end); } +/** + * @brief GenericChatForm::loadHistoryLower load history after scrolling chatlog before first "messages" item + */ void GenericChatForm::loadHistoryLower() { loadHistoryTo(QDateTime()); } +/** + * @brief GenericChatForm::loadHistoryUpper load history after scrolling chatlog after last "messages" item + */ void GenericChatForm::loadHistoryUpper() { if (messages.empty()) { @@ -1159,8 +1190,9 @@ void GenericChatForm::loadHistoryUpper() } auto msg = messages.crbegin()->second; - loadHistoryFrom(QDateTime()); - chatWidget->scrollToLine(msg); + if (loadHistoryFrom(QDateTime())) { + chatWidget->scrollToLine(msg); + } } void GenericChatForm::updateShowDateInfo(const ChatLine::Ptr& line) diff --git a/src/widget/form/genericchatform.h b/src/widget/form/genericchatform.h index 3358de41b..2e1b2df0f 100644 --- a/src/widget/form/genericchatform.h +++ b/src/widget/form/genericchatform.h @@ -137,7 +137,7 @@ private: QDateTime getTime(const ChatLine::Ptr& chatLine) const; void loadHistory(const QDateTime& time, const LoadHistoryDialog::LoadType type); void loadHistoryTo(const QDateTime& time); - void loadHistoryFrom(const QDateTime& time); + bool loadHistoryFrom(const QDateTime& time); void removeFirstsMessages(const int num); void removeLastsMessages(const int num); diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index eaf9a0590..5049da7c9 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -1008,6 +1008,11 @@ void Widget::setStatusMessage(const QString& statusMessage) */ void Widget::playNotificationSound(IAudioSink::Sound sound, bool loop) { + if (!settings.getAudioOutDevEnabled()) { + // don't try to play sounds if audio is disabled + return; + } + if (audioNotification == nullptr) { audioNotification = std::unique_ptr(audio.makeSink()); if (audioNotification == nullptr) {