diff --git a/README.md b/README.md index 8147def8d..9252e7c42 100644 --- a/README.md +++ b/README.md @@ -20,15 +20,15 @@ However, it is not a fork. This client runs on Windows, Linux and Mac natively.
-You can find the latest versions of qTox here, or from the Tox Project's servers : +You can find the latest versions of qTox here (Windows and Linux), or from the Tox Project's servers : -Windows download
-Mac download
-Linux download (click "Last successful artifacts")
+Mac download
+Linux download (click "Last successful artifacts")

Screenshots

Note: The screenshots may not always be up to date, but they should give a good idea of the general look and features
- + + ##Documentation: diff --git a/debian/control b/debian/control index 1147f4397..6f7c59daa 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,7 @@ Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev (>= 1:1.14), lib Package: qtox Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libgcc1 (>= 1:4.1.1), libgl1-mesa-glx | libgl1, libopenal1 (>= 1.14), libopus0 (>= 0.9), libqt5core5a (>= 5.2), libqt5gui5 (>= 5.2), libqt5network5 (>= 5.0), libqt5widgets5 (>= 5.2), libqt5xml5 (>= 5.0), libstdc++6 (>= 4.9), libvpx1 (>= 1.0.0) +Depends: ${shlibs:Depends}, ${misc:Depends}, libgcc1 (>= 1:4.1.1), libgl1-mesa-glx | libgl1, libopenal1 (>= 1.14), libopus0 (>= 0.9), libqt5core5a (>= 5.2), libqt5gui5 (>= 5.2), libqt5network5 (>= 5.0), libqt5widgets5 (>= 5.2), libqt5xml5 (>= 5.0), libstdc++6 (>= 4.8.2), libvpx1 (>= 1.0.0) Description: Tox client qTox is a powerful Tox client that follows the Tox design guidelines. Tox is a decentralized and encrypted replacement for Skype, supporting diff --git a/img/icons/qtox.icns b/img/icons/qtox.icns new file mode 100644 index 000000000..bb96d3ae3 Binary files /dev/null and b/img/icons/qtox.icns differ diff --git a/qtox.pro b/qtox.pro index 10a17f2fc..0d0019c91 100644 --- a/qtox.pro +++ b/qtox.pro @@ -60,6 +60,7 @@ win32 { LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32 } else { macx { + ICON = img/icons/qtox.icns LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui } else { # If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package @@ -68,7 +69,7 @@ win32 { INSTALLS += target LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig - LIBS += -Wl,-Bdynamic -ltbb -lv4l1 -lv4l2 -lgnutls -lrtmp -lgnutls -lavformat -lavcodec -lavutil -lavfilter -lswscale -lusb-1.0 + LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0 } else { LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lvpx -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc @@ -134,10 +135,12 @@ HEADERS += src/widget/form/addfriendform.h \ src/widget/tool/chatactions/filetransferaction.h \ src/widget/tool/chatactions/systemmessageaction.h \ src/widget/tool/chatactions/actionaction.h \ + src/widget/tool/chatactions/alertaction.h \ src/widget/maskablepixmapwidget.h \ src/videosource.h \ src/cameraworker.h \ - src/widget/videosurface.h + src/widget/videosurface.h \ + src/widget/form/tabcompleter.h SOURCES += \ src/widget/form/addfriendform.cpp \ @@ -182,7 +185,9 @@ SOURCES += \ src/widget/tool/chatactions/filetransferaction.cpp \ src/widget/tool/chatactions/systemmessageaction.cpp \ src/widget/tool/chatactions/actionaction.cpp \ + src/widget/tool/chatactions/alertaction.cpp \ src/widget/maskablepixmapwidget.cpp \ src/cameraworker.cpp \ src/widget/videosurface.cpp \ - src/netvideosource.cpp + src/netvideosource.cpp \ + src/widget/form/tabcompleter.cpp diff --git a/src/cameraworker.cpp b/src/cameraworker.cpp index 3a6ef4f2a..b2829c579 100644 --- a/src/cameraworker.cpp +++ b/src/cameraworker.cpp @@ -18,6 +18,7 @@ #include #include +#include CameraWorker::CameraWorker(int index) : clock(nullptr) @@ -178,6 +179,7 @@ void CameraWorker::setProp(int prop, double val) double CameraWorker::getProp(int prop) { double ret = 0.0; + qApp->processEvents(); QMetaObject::invokeMethod(this, "_getProp", Qt::BlockingQueuedConnection, Q_RETURN_ARG(double, ret), Q_ARG(int, prop)); return ret; diff --git a/src/core.cpp b/src/core.cpp index 58fd47aff..559139dbf 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -226,6 +226,12 @@ void Core::start() } loadPath = ""; } + else // new ID + { + setStatusMessage(tr("Toxing on qTox")); // this also solves the not updating issue + setUsername(tr("qTox User")); + Widget::getInstance()->onSettingsClicked(); // update ui with new profile (im worried about threading, but it seems to work) + } tox_callback_friend_request(tox, onFriendRequest, this); tox_callback_friend_message(tox, onFriendMessage, this); @@ -1187,10 +1193,7 @@ void Core::saveConfiguration(const QString& path) void Core::switchConfiguration(const QString& profile) { if (profile.isEmpty()) - { - qWarning() << "Core: got null profile to switch to, not switching"; - return; - } + qDebug() << "Core: creating new Id"; else qDebug() << "Core: switching from" << Settings::getInstance().getCurrentProfile() << "to" << profile; saveConfiguration(); @@ -1205,8 +1208,11 @@ void Core::switchConfiguration(const QString& profile) } emit selfAvatarChanged(QPixmap(":/img/contact_dark.png")); emit blockingClearContacts(); // we need this to block, but signals are required for thread safety - - loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT); + + if (profile.isEmpty()) + loadPath = ""; + else + loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT); Settings::getInstance().setCurrentProfile(profile); start(); diff --git a/src/filetransferinstance.cpp b/src/filetransferinstance.cpp index b6534e2ab..16717eb1f 100644 --- a/src/filetransferinstance.cpp +++ b/src/filetransferinstance.cpp @@ -46,7 +46,7 @@ FileTransferInstance::FileTransferInstance(ToxFile File) filenameElided = fm.elidedText(filename, Qt::ElideRight, MAX_CONTENT_WIDTH); size = getHumanReadableSize(File.filesize); - contentPrefWidth = std::max(fm.width(filenameElided), fm.width(size)); + contentPrefWidth = std::max(fm.boundingRect(filenameElided).width(), fm.width(size)); speed = "0B/s"; eta = "00:00"; @@ -209,6 +209,7 @@ bool isFileWritable(QString& path) void FileTransferInstance::acceptRecvRequest() { QString path = Settings::getInstance().getAutoAcceptDir(Core::getInstance()->getFriendAddress(friendId)); + if (path.isEmpty()) path = Settings::getInstance().getGlobalAutoAcceptDir(); if (!path.isEmpty()) { QDir dir(path); diff --git a/src/main.cpp b/src/main.cpp index c683f462c..0dcc9726c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,6 @@ #include "misc/settings.h" #include #include -#include #include int main(int argc, char *argv[]) @@ -38,24 +37,6 @@ int main(int argc, char *argv[]) QFontDatabase::addApplicationFont("://DejaVuSans.ttf"); Widget* w = Widget::getInstance(); - if (QSystemTrayIcon::isSystemTrayAvailable() == false) - { - qWarning() << "No system tray detected!"; - w->show(); - } - else - { - QSystemTrayIcon *icon = new QSystemTrayIcon(w); - QObject::connect(icon, - SIGNAL(activated(QSystemTrayIcon::ActivationReason)), - w, - SLOT(onIconClick())); - icon->setIcon(w->windowIcon()); - icon->show(); - if(Settings::getInstance().getAutostartInTray() == false) - w->show(); - } - int errorcode = a.exec(); diff --git a/src/misc/settings.cpp b/src/misc/settings.cpp index de84e7a3c..98109a964 100644 --- a/src/misc/settings.cpp +++ b/src/misc/settings.cpp @@ -112,6 +112,7 @@ void Settings::load() translation = s.value("translation", "").toString(); makeToxPortable = s.value("makeToxPortable", false).toBool(); autostartInTray = s.value("autostartInTray", false).toBool(); + closeToTray = s.value("closeToTray", false).toBool(); forceTCP = s.value("forceTCP", false).toBool(); useProxy = s.value("useProxy", false).toBool(); proxyAddr = s.value("proxyAddr", "").toString(); @@ -137,6 +138,7 @@ void Settings::load() secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt(); timestampFormat = s.value("timestampFormat", "hh:mm").toString(); minimizeOnClose = s.value("minimizeOnClose", false).toBool(); + minimizeToTray = s.value("minimizeToTray", false).toBool(); useNativeStyle = s.value("nativeStyle", false).toBool(); style = s.value("style", "None").toString(); statusChangeNotificationEnabled = s.value("statusChangeNotificationEnabled", false).toBool(); @@ -153,6 +155,7 @@ void Settings::load() s.endGroup(); s.beginGroup("AutoAccept"); + globalAutoAcceptDir = s.value("globalAutoAcceptDir", "").toString(); for (auto& key : s.childKeys()) autoAccept[key] = s.value(key).toString(); s.endGroup(); @@ -225,6 +228,7 @@ void Settings::save(QString path) s.setValue("translation",translation); s.setValue("makeToxPortable",makeToxPortable); s.setValue("autostartInTray",autostartInTray); + s.setValue("closeToTray", closeToTray); s.setValue("useProxy", useProxy); s.setValue("forceTCP", forceTCP); s.setValue("proxyAddr", proxyAddr); @@ -250,6 +254,7 @@ void Settings::save(QString path) s.setValue("secondColumnHandlePosFromRight", secondColumnHandlePosFromRight); s.setValue("timestampFormat", timestampFormat); s.setValue("minimizeOnClose", minimizeOnClose); + s.setValue("minimizeToTray", minimizeToTray); s.setValue("nativeStyle", useNativeStyle); s.setValue("style",style); s.setValue("statusChangeNotificationEnabled", statusChangeNotificationEnabled); @@ -266,6 +271,7 @@ void Settings::save(QString path) s.endGroup(); s.beginGroup("AutoAccept"); + s.setValue("globalAutoAcceptDir", globalAutoAcceptDir); for (auto& id : autoAccept.keys()) s.setValue(id, autoAccept.value(id)); s.endGroup(); @@ -390,6 +396,27 @@ void Settings::setAutostartInTray(bool newValue) autostartInTray = newValue; } +bool Settings::getCloseToTray() const +{ + return closeToTray; +} + +void Settings::setCloseToTray(bool newValue) +{ + closeToTray = newValue; +} + +bool Settings::getMinimizeToTray() const +{ + return minimizeToTray; +} + + +void Settings::setMinimizeToTray(bool newValue) +{ + minimizeToTray = newValue; +} + bool Settings::getStatusChangeNotificationEnabled() const { return statusChangeNotificationEnabled; @@ -504,6 +531,16 @@ void Settings::setAutoAcceptDir(const QString& id, const QString& dir) autoAccept[id.left(TOX_ID_PUBLIC_KEY_LENGTH)] = dir; } +QString Settings::getGlobalAutoAcceptDir() const +{ + return globalAutoAcceptDir; +} + +void Settings::setGlobalAutoAcceptDir(const QString& newValue) +{ + globalAutoAcceptDir = newValue; +} + void Settings::setWidgetData(const QString& uniqueName, const QByteArray& data) { widgetSettings[uniqueName] = data; diff --git a/src/misc/settings.h b/src/misc/settings.h index 5d4363f31..5c3e6bc17 100644 --- a/src/misc/settings.h +++ b/src/misc/settings.h @@ -52,6 +52,12 @@ public: bool getAutostartInTray() const; void setAutostartInTray(bool newValue); + bool getCloseToTray() const; + void setCloseToTray(bool newValue); + + bool getMinimizeToTray() const; + void setMinimizeToTray(bool newValue); + QString getStyle() const; void setStyle(const QString& newValue); @@ -128,6 +134,9 @@ public: QString getAutoAcceptDir(const QString& id) const; void setAutoAcceptDir(const QString&id, const QString& dir); + QString getGlobalAutoAcceptDir() const; + void setGlobalAutoAcceptDir(const QString& dir); + // ChatView int getFirstColumnHandlePos() const; void setFirstColumnHandlePos(const int pos); @@ -185,6 +194,8 @@ private: QString translation; static bool makeToxPortable; bool autostartInTray; + bool closeToTray; + bool minimizeToTray; bool forceTCP; @@ -201,6 +212,7 @@ private: QHash widgetSettings; QHash autoAccept; + QString globalAutoAcceptDir; // GUI bool enableSmoothAnimation; diff --git a/src/misc/style.cpp b/src/misc/style.cpp index 70100270f..e9dec32e3 100644 --- a/src/misc/style.cpp +++ b/src/misc/style.cpp @@ -70,6 +70,7 @@ QColor Style::getColor(Style::ColorPalette entry) QColor("#414141").lighter(120), QColor("#d1d1d1"), QColor("#ffffff"), + QColor("#ff7700"), }; return palette[entry]; @@ -108,6 +109,7 @@ QString Style::resolve(QString qss) {"@mediumGreyLight", getColor(MediumGreyLight).name()}, {"@lightGrey", getColor(LightGrey).name()}, {"@white", getColor(White).name()}, + {"@orange", getColor(Orange).name()}, // fonts {"@extraBig", qssifyFont(getFont(ExtraBig))}, diff --git a/src/misc/style.h b/src/misc/style.h index a07064e04..e818b2ddb 100644 --- a/src/misc/style.h +++ b/src/misc/style.h @@ -37,6 +37,7 @@ public: MediumGreyLight, LightGrey, White, + Orange, }; enum Font diff --git a/src/widget/form/addfriendform.cpp b/src/widget/form/addfriendform.cpp index b31a7818e..9e1243eff 100644 --- a/src/widget/form/addfriendform.cpp +++ b/src/widget/form/addfriendform.cpp @@ -154,4 +154,6 @@ void AddFriendForm::handleDnsLookup() // finally we got it emit friendRequested(friendAdress, getMessage()); + this->toxId.setText(""); + this->message.setText(""); } diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 0d317332f..40bf599cb 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -87,7 +87,7 @@ void ChatForm::onSendTriggered() if (msg.isEmpty()) return; QString name = Widget::getInstance()->getUsername(); - if (msg.startsWith("/me ")) + if (msg.startsWith("/me")) { msg = msg.right(msg.length() - 4); addMessage(name, msg, true); @@ -180,7 +180,8 @@ void ChatForm::onFileRecvRequest(ToxFile file) chatWidget->insertMessage(new FileTransferAction(fileTrans, getElidedName(name), QTime::currentTime().toString("hh:mm"), false)); - if (!Settings::getInstance().getAutoAcceptDir(Core::getInstance()->getFriendAddress(f->friendId)).isEmpty()) + if (!Settings::getInstance().getAutoAcceptDir(Core::getInstance()->getFriendAddress(f->friendId)).isEmpty() + || !Settings::getInstance().getGlobalAutoAcceptDir().isEmpty()) fileTrans->pressFromHtml("btnB"); } @@ -408,7 +409,8 @@ void ChatForm::onAvPeerTimeout(int FriendId, int) void ChatForm::onAvMediaChange(int FriendId, int CallId, bool video) { - Q_UNUSED(FriendId) + if (FriendId != f->friendId || CallId != callId) + return; if (video) { diff --git a/src/widget/form/genericchatform.cpp b/src/widget/form/genericchatform.cpp index bdb764777..d25484543 100644 --- a/src/widget/form/genericchatform.cpp +++ b/src/widget/form/genericchatform.cpp @@ -25,6 +25,7 @@ #include "src/widget/tool/chatactions/messageaction.h" #include "src/widget/tool/chatactions/systemmessageaction.h" #include "src/widget/tool/chatactions/actionaction.h" +#include "src/widget/tool/chatactions/alertaction.h" #include "src/widget/chatareawidget.h" #include "src/widget/tool/chattextedit.h" #include "src/widget/maskablepixmapwidget.h" @@ -173,7 +174,7 @@ void GenericChatForm::addMessage(QString author, QString message, bool isAction, QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); bool isMe = (author == Widget::getInstance()->getUsername()); - if (!isAction && message.startsWith("/me ")) + if (!isAction && message.startsWith("/me")) { // always render actions regardless of what core thinks isAction = true; message = message.right(message.length()-4); @@ -193,6 +194,13 @@ void GenericChatForm::addMessage(QString author, QString message, bool isAction, previousName = author; } +void GenericChatForm::addAlertMessage(QString author, QString message, QDateTime datetime) +{ + QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); + chatWidget->insertMessage(new AlertAction(author, message, date)); + previousName = author; +} + void GenericChatForm::onEmoteButtonClicked() { // don't show the smiley selection widget if there are no smileys available diff --git a/src/widget/form/genericchatform.h b/src/widget/form/genericchatform.h index 0baa4f315..5782823a6 100644 --- a/src/widget/form/genericchatform.h +++ b/src/widget/form/genericchatform.h @@ -22,7 +22,7 @@ #include // Spacing in px inserted when the author of the last message changes -#define AUTHOR_CHANGE_SPACING 5 +#define AUTHOR_CHANGE_SPACING 5 // why the hell is this a thing? surely the different font is enough? class QLabel; class QVBoxLayout; @@ -45,6 +45,7 @@ public: virtual void setName(const QString &newName); virtual void show(Ui::MainWindow &ui); void addMessage(QString author, QString message, bool isAction = false, QDateTime datetime=QDateTime::currentDateTime()); + void addAlertMessage(QString author, QString message, QDateTime datetime=QDateTime::currentDateTime()); void addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime=QDateTime::currentDateTime()); int getNumberOfMessages(); diff --git a/src/widget/form/groupchatform.cpp b/src/widget/form/groupchatform.cpp index 0c5b4c9e1..11a32a71a 100644 --- a/src/widget/form/groupchatform.cpp +++ b/src/widget/form/groupchatform.cpp @@ -15,6 +15,7 @@ */ #include "groupchatform.h" +#include "tabcompleter.h" #include "src/group.h" #include "src/widget/groupwidget.h" #include "src/widget/tool/chattextedit.h" @@ -33,6 +34,8 @@ GroupChatForm::GroupChatForm(Group* chatGroup) namesList = new QLabel(); namesList->setObjectName("peersLabel"); + tabber = new TabCompleter(msgEdit, group); + fileButton->setEnabled(false); callButton->setVisible(false); videoButton->setVisible(false); @@ -59,6 +62,8 @@ GroupChatForm::GroupChatForm(Group* chatGroup) connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered())); connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered())); + connect(msgEdit, &ChatTextEdit::tabPressed, tabber, &TabCompleter::complete); + connect(msgEdit, &ChatTextEdit::keyPressed, tabber, &TabCompleter::reset); setAcceptDrops(true); } diff --git a/src/widget/form/groupchatform.h b/src/widget/form/groupchatform.h index 6b3984b06..f715768e8 100644 --- a/src/widget/form/groupchatform.h +++ b/src/widget/form/groupchatform.h @@ -21,6 +21,7 @@ namespace Ui {class MainWindow;} class Group; +class TabCompleter; class GroupChatForm : public GenericChatForm { @@ -41,6 +42,7 @@ protected: private: Group* group; QLabel *nusersLabel, *namesList; + TabCompleter* tabber; }; #endif // GROUPCHATFORM_H diff --git a/src/widget/form/settings/avsettings.ui b/src/widget/form/settings/avsettings.ui index 74de38e38..daba3b9d3 100644 --- a/src/widget/form/settings/avsettings.ui +++ b/src/widget/form/settings/avsettings.ui @@ -34,7 +34,44 @@ 489 - + + + + + Volume Settings (Stubs) + + + + + + Microphone + + + + + + + Playback + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + @@ -47,7 +84,7 @@ QFormLayout::ExpandingFieldsGrow - + Resolution @@ -64,7 +101,7 @@ - + Hue @@ -78,7 +115,7 @@ - + Brightness @@ -92,7 +129,7 @@ - + Saturation @@ -106,7 +143,7 @@ - + Contrast @@ -119,64 +156,27 @@ - - - - - 1 - 99 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - - - - - - - - - Volume Settings (Stubs) - - - - - - Playback + + + + + 1 + 99 + - - - - - - Qt::Horizontal + + QFrame::NoFrame - - - - - - Microphone - - - - - - - Qt::Horizontal + + QFrame::Raised + + + + + diff --git a/src/widget/form/settings/generalform.cpp b/src/widget/form/settings/generalform.cpp index 78867b60e..e6b21b109 100644 --- a/src/widget/form/settings/generalform.cpp +++ b/src/widget/form/settings/generalform.cpp @@ -40,7 +40,9 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : bodyUI->transComboBox->setCurrentIndex(locales.indexOf(Settings::getInstance().getTranslation())); bodyUI->cbMakeToxPortable->setChecked(Settings::getInstance().getMakeToxPortable()); bodyUI->startInTray->setChecked(Settings::getInstance().getAutostartInTray()); - bodyUI->statusChangesCheckbox->setChecked(Settings::getInstance().getStatusChangeNotificationEnabled()); + bodyUI->closeToTray->setChecked(Settings::getInstance().getCloseToTray()); + bodyUI->minimizeToTray->setChecked(Settings::getInstance().getMinimizeToTray()); + bodyUI->statusChanges->setChecked(Settings::getInstance().getStatusChangeNotificationEnabled()); for (auto entry : SmileyPack::listSmileyPacks()) { @@ -72,7 +74,9 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) : connect(bodyUI->transComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onTranslationUpdated())); connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated); connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray); - connect(bodyUI->statusChangesCheckbox, &QCheckBox::stateChanged, this, &GeneralForm::onSetStatusChange); + connect(bodyUI->closeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetCloseToTray); + connect(bodyUI->minimizeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetMinimizeToTray); + connect(bodyUI->statusChanges, &QCheckBox::stateChanged, this, &GeneralForm::onSetStatusChange); connect(bodyUI->smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int))); // new syntax can't handle overloaded signals... (at least not in a pretty way) connect(bodyUI->cbUDPDisabled, &QCheckBox::stateChanged, this, &GeneralForm::onUDPUpdated); @@ -109,6 +113,16 @@ void GeneralForm::onSetAutostartInTray() Settings::getInstance().setAutostartInTray(bodyUI->startInTray->isChecked()); } +void GeneralForm::onSetCloseToTray() +{ + Settings::getInstance().setCloseToTray(bodyUI->closeToTray->isChecked()); +} + +void GeneralForm::onSetMinimizeToTray() +{ + Settings::getInstance().setMinimizeToTray(bodyUI->minimizeToTray->isChecked()); +} + void GeneralForm::onStyleSelected(QString style) { Settings::getInstance().setStyle(style); @@ -125,7 +139,7 @@ void GeneralForm::onAutoAwayChanged() void GeneralForm::onSetStatusChange() { - Settings::getInstance().setStatusChangeNotificationEnabled(bodyUI->statusChangesCheckbox->isChecked()); + Settings::getInstance().setStatusChangeNotificationEnabled(bodyUI->statusChanges->isChecked()); } void GeneralForm::onSmileyBrowserIndexChanged(int index) diff --git a/src/widget/form/settings/generalform.h b/src/widget/form/settings/generalform.h index bae1eb8d0..6397ccdfd 100644 --- a/src/widget/form/settings/generalform.h +++ b/src/widget/form/settings/generalform.h @@ -35,6 +35,7 @@ private slots: void onTranslationUpdated(); void onMakeToxPortableUpdated(); void onSetAutostartInTray(); + void onSetCloseToTray(); void onSmileyBrowserIndexChanged(int index); void onUDPUpdated(); void onProxyAddrEdited(); @@ -43,6 +44,7 @@ private slots: void onStyleSelected(QString style); void onSetStatusChange(); void onAutoAwayChanged(); + void onSetMinimizeToTray(); private: diff --git a/src/widget/form/settings/generalsettings.ui b/src/widget/form/settings/generalsettings.ui index 924bc057b..f2976eea5 100644 --- a/src/widget/form/settings/generalsettings.ui +++ b/src/widget/form/settings/generalsettings.ui @@ -7,7 +7,7 @@ 0 0 527 - 500 + 525 @@ -74,7 +74,21 @@ - + + + Close to tray + + + + + + + Minimize to tray + + + + + Show contacts' status changes diff --git a/src/widget/form/settings/identityform.cpp b/src/widget/form/settings/identityform.cpp index 691aa4d86..3347ea30c 100644 --- a/src/widget/form/settings/identityform.cpp +++ b/src/widget/form/settings/identityform.cpp @@ -54,6 +54,7 @@ IdentityForm::IdentityForm() : connect(bodyUI->exportButton, &QPushButton::clicked, this, &IdentityForm::onExportClicked); connect(bodyUI->deleteButton, &QPushButton::clicked, this, &IdentityForm::onDeleteClicked); connect(bodyUI->importButton, &QPushButton::clicked, this, &IdentityForm::onImportClicked); + connect(bodyUI->newButton, &QPushButton::clicked, this, &IdentityForm::onNewClicked); connect(Core::getInstance(), &Core::usernameSet, this, [=](const QString& val) { bodyUI->userName->setText(val); }); connect(Core::getInstance(), &Core::statusMessageSet, this, [=](const QString& val) { bodyUI->statusMessage->setText(val); }); @@ -120,15 +121,22 @@ void IdentityForm::onRenameClicked() { QString cur = bodyUI->profiles->currentText(); QString title = tr("Rename \"%1\"", "renaming a profile").arg(cur); - QString name = QInputDialog::getText(this, title, title+":"); - if (name != "") + do { + QString name = QInputDialog::getText(this, title, title+":"); + if (name.isEmpty()) break; name = Core::sanitize(name); QDir dir(Settings::getSettingsDirPath()); - QFile::rename(dir.filePath(cur+Core::TOX_EXT), dir.filePath(name+Core::TOX_EXT)); - bodyUI->profiles->setItemText(bodyUI->profiles->currentIndex(), name); - Settings::getInstance().setCurrentProfile(name); - } + QString file = dir.filePath(name+Core::TOX_EXT); + if (!QFile::exists(file) || checkContinue(tr("Profile already exists", "rename confirm title"), + tr("A profile named \"%1\" already exists. Do you want to erase it?", "rename confirm text").arg(cur))) + { + QFile::rename(dir.filePath(cur+Core::TOX_EXT), file); + bodyUI->profiles->setItemText(bodyUI->profiles->currentIndex(), name); + Settings::getInstance().setCurrentProfile(name); + break; + } + } while (true); } void IdentityForm::onExportClicked() @@ -149,9 +157,8 @@ void IdentityForm::onDeleteClicked() } else { - QMessageBox::StandardButton resp = QMessageBox::question(this, - tr("Deletion imminent!","deletion confirmation title"), tr("Are you sure you want to delete this profile?","deletion confirmation text"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - if (resp == QMessageBox::Yes) + if (checkContinue(tr("Deletion imminent!","deletion confirmation title"), + tr("Are you sure you want to delete this profile?","deletion confirmation text"))) { QFile::remove(QDir(Settings::getSettingsDirPath()).filePath(bodyUI->profiles->currentText()+Core::TOX_EXT)); bodyUI->profiles->removeItem(bodyUI->profiles->currentIndex()); @@ -167,6 +174,7 @@ void IdentityForm::onImportClicked() return; QFileInfo info(path); + QString profile = info.completeBaseName(); if (info.suffix() != "tox") { @@ -174,8 +182,22 @@ void IdentityForm::onImportClicked() return; } - QString profile = info.completeBaseName(); + if (info.exists() && !checkContinue(tr("Profile already exists", "import confirm title"), + tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile))) + return; + QString profilePath = QDir(Settings::getSettingsDirPath()).filePath(profile + Core::TOX_EXT); QFile::copy(path, profilePath); bodyUI->profiles->addItem(profile); } + +void IdentityForm::onNewClicked() +{ + emit Widget::getInstance()->changeProfile(QString()); +} + +bool IdentityForm::checkContinue(const QString& title, const QString& msg) +{ + QMessageBox::StandardButton resp = QMessageBox::question(this, title, msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + return resp == QMessageBox::Yes; +} diff --git a/src/widget/form/settings/identityform.h b/src/widget/form/settings/identityform.h index f21f653f1..93fc38947 100644 --- a/src/widget/form/settings/identityform.h +++ b/src/widget/form/settings/identityform.h @@ -63,6 +63,8 @@ private slots: void onExportClicked(); void onDeleteClicked(); void onImportClicked(); + void onNewClicked(); + bool checkContinue(const QString& title, const QString& msg); private: Ui::IdentitySettings* bodyUI; diff --git a/src/widget/form/settings/identitysettings.ui b/src/widget/form/settings/identitysettings.ui index 49314395b..ba54f46c8 100644 --- a/src/widget/form/settings/identitysettings.ui +++ b/src/widget/form/settings/identitysettings.ui @@ -122,11 +122,22 @@ - - - Import a profile - - + + + + + Import a profile + + + + + + + New Tox ID + + + + diff --git a/src/widget/form/tabcompleter.cpp b/src/widget/form/tabcompleter.cpp new file mode 100644 index 000000000..fa4691e13 --- /dev/null +++ b/src/widget/form/tabcompleter.cpp @@ -0,0 +1,122 @@ +/* + Copyright (C) 2005-2014 by the Quassel Project and Project Tox + devel@quassel-irc.org and https://tox.im + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +/* This file was taken from the Quassel IRC client source (src/uisupport), and + was greatly simplified for use in qTox. */ + +#include "tabcompleter.h" +#include "src/core.h" +#include "src/group.h" +#include "src/widget/tool/chattextedit.h" +#include +#include + +const QString TabCompleter::nickSuffix = QString(": "); + +TabCompleter::TabCompleter(ChatTextEdit* msgEdit, Group* group) + : QObject(msgEdit), msgEdit(msgEdit), group(group), enabled(false) +{ +} + +/* from quassel/src/uisupport/multilineedit.h + // Compatibility methods with the rest of the classes which still expect this to be a QLineEdit + inline QString text() const { return toPlainText(); } + inline QString html() const { return toHtml(); } + inline int cursorPosition() const { return textCursor().position(); } + inline void insert(const QString &newText) { insertPlainText(newText); } + inline void backspace() { keyPressEvent(new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier)); } +*/ + +void TabCompleter::buildCompletionList() +{ + // ensure a safe state in case we return early. + completionMap.clear(); + nextCompletion = completionMap.begin(); + + // split the string on the given RE (not chars, nums or braces/brackets) and take the last section + QString tabAbbrev = msgEdit->toPlainText().left(msgEdit->textCursor().position()).section(QRegExp("[^\\w\\d-_\\[\\]{}|`^.\\\\]"), -1, -1); + // that section is then used as the completion regex + QRegExp regex(QString("^[-_\\[\\]{}|`^.\\\\]*").append(QRegExp::escape(tabAbbrev)), Qt::CaseInsensitive); + + for(auto name : group->peers.values()) + if (regex.indexIn(name) > -1) + completionMap[name.toLower()] = name; + + nextCompletion = completionMap.begin(); + lastCompletionLength = tabAbbrev.length(); +} + + +void TabCompleter::complete() +{ + if (!enabled) { + buildCompletionList(); + enabled = true; + } + + if (nextCompletion != completionMap.end()) { + // clear previous completion + for (int i = 0; i < lastCompletionLength; i++) { + msgEdit->keyPressEvent(new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier)); + } + + // insert completion + msgEdit->insertPlainText(*nextCompletion); + + // remember charcount to delete next time and advance to next completion + lastCompletionLength = nextCompletion->length(); + nextCompletion++; + + // we're completing the first word of the line + if (msgEdit->textCursor().position() == lastCompletionLength) { + msgEdit->insertPlainText(nickSuffix); + lastCompletionLength += nickSuffix.length(); + } + } + else { // we're at the end of the list -> start over again + if (!completionMap.isEmpty()) { + nextCompletion = completionMap.begin(); + complete(); + } + } +} + + +void TabCompleter::reset() +{ + enabled = false; +} + +// this determines the sort order +bool TabCompleter::SortableString::operator<(const SortableString &other) const +{ + QString name = Core::getInstance()->getUsername(); + if (this->contents == name) + return false; + else if (other.contents == name) + return true; + +/* QDateTime thisTime = thisUser->lastChannelActivity(_currentBufferId); + QDateTime thatTime = thatUser->lastChannelActivity(_currentBufferId); + + + if (thisTime.isValid() || thatTime.isValid()) + return thisTime > thatTime; +*/ // this could be a useful feature at some point + + return QString::localeAwareCompare(this->contents, other.contents) < 0; +} diff --git a/src/widget/form/tabcompleter.h b/src/widget/form/tabcompleter.h new file mode 100644 index 000000000..f48b1a797 --- /dev/null +++ b/src/widget/form/tabcompleter.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2005-2014 by the Quassel Project and Project Tox + devel@quassel-irc.org and https://tox.im + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +/* This file was taken from the Quassel IRC client source (src/uisupport), and + was greatly simplified for use in qTox. */ + +#ifndef TABCOMPLETER_H +#define TABCOMPLETER_H + +#include +#include +#include // I'm really confused why I need this + +class ChatTextEdit; +class Group; + +class TabCompleter : public QObject +{ + Q_OBJECT +public: + explicit TabCompleter(ChatTextEdit* msgEdit, Group* group); + +public slots: + void complete(); + void reset(); + +private: + struct SortableString { + inline SortableString(const QString &n) { contents = n; } + bool operator<(const SortableString &other) const; + QString contents; + }; + + ChatTextEdit* msgEdit; + Group* group; + bool enabled; + const static QString nickSuffix; + + QMap completionMap; + QMap::Iterator nextCompletion; + int lastCompletionLength; + + void buildCompletionList(); +}; + + +#endif diff --git a/src/widget/friendwidget.cpp b/src/widget/friendwidget.cpp index 3a584c6f3..7d790a221 100644 --- a/src/widget/friendwidget.cpp +++ b/src/widget/friendwidget.cpp @@ -49,9 +49,10 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) QPoint pos = event->globalPos(); QString id = Core::getInstance()->getFriendAddress(friendId); QString dir = Settings::getInstance().getAutoAcceptDir(id); + QString globalDir = Settings::getInstance().getGlobalAutoAcceptDir(); QMenu menu; + QMenu* inviteMenu = menu.addMenu(tr("Invite to group","Menu to invite a friend to a groupchat")); QAction* copyId = menu.addAction(tr("Copy friend ID","Menu to copy the Tox ID of that friend")); - QMenu* inviteMenu = menu.addMenu(tr("Invite in group","Menu to invite a friend in a groupchat")); QMap groupActions; for (Group* group : GroupList::groupList) { @@ -60,10 +61,15 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) } if (groupActions.isEmpty()) inviteMenu->setEnabled(false); + menu.addSeparator(); QAction* autoAccept = menu.addAction(tr("Auto accept files from this friend", "context menu entry")); - QAction* disableAutoAccept = menu.addAction(tr("Diasble auto accepting files", "context menu entry")); + QAction* disableAutoAccept = menu.addAction(tr("Manually accept files from this friend", "context menu entry")); + QAction* globalAA = menu.addAction(tr("Auto accept files from all friends", "context menu entry")); + QAction* disableGlobalAA = menu.addAction(tr("Disable global auto accept", "context menu entry")); if (dir.isEmpty()) disableAutoAccept->setEnabled(false); + if (globalDir.isEmpty()) + disableGlobalAA->setEnabled(false); menu.addSeparator(); QAction* removeFriendAction = menu.addAction(tr("Remove friend", "Menu to remove the friend from our friendlist")); @@ -98,6 +104,21 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) { Settings::getInstance().setAutoAcceptDir(id, ""); } + else if (selectedItem == globalAA) + { + if (globalDir.isEmpty()) + globalDir = QDir::homePath(); + globalDir = QFileDialog::getExistingDirectory(0, tr("Choose an auto accept directory","popup title"), dir); + if (!globalDir.isEmpty()) + { + qDebug() << "FriendWidget: setting global auto accept dir to" << globalDir; + Settings::getInstance().setGlobalAutoAcceptDir(globalDir); + } + } + else if (selectedItem == disableGlobalAA) + { + Settings::getInstance().setGlobalAutoAcceptDir(""); + } else if (groupActions.contains(selectedItem)) { Group* group = groupActions[selectedItem]; diff --git a/src/widget/tool/chatactions/actionaction.cpp b/src/widget/tool/chatactions/actionaction.cpp index 3facb978c..c68f4449f 100644 --- a/src/widget/tool/chatactions/actionaction.cpp +++ b/src/widget/tool/chatactions/actionaction.cpp @@ -15,11 +15,10 @@ */ #include "actionaction.h" -#include "src/misc/smileypack.h" +#include -ActionAction::ActionAction(const QString &author, const QString &message, const QString &date, const bool& me) : - ChatAction(me, author, date), - message(message) +ActionAction::ActionAction(const QString &author, QString message, const QString &date, const bool& me) : + MessageAction(author, author+" "+message, date, me) { } @@ -45,24 +44,5 @@ QString ActionAction::getName() QString ActionAction::getMessage() { - QString message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); - - // detect urls - QRegExp exp("(www\\.|http[s]?:\\/\\/|ftp:\\/\\/)\\S+"); - int offset = 0; - while ((offset = exp.indexIn(message_, offset)) != -1) - { - QString url = exp.cap(); - - // add scheme if not specified - if (exp.cap(1) == "www.") - url.prepend("http://"); - - QString htmledUrl = QString("%1").arg(url); - message_.replace(offset, exp.cap().length(), htmledUrl); - - offset += htmledUrl.length(); - } - - return QString("
%1 %2
").arg(name).arg(message_); + return MessageAction::getMessage("action"); } diff --git a/src/widget/tool/chatactions/actionaction.h b/src/widget/tool/chatactions/actionaction.h index 08553a96e..d438f0ecd 100644 --- a/src/widget/tool/chatactions/actionaction.h +++ b/src/widget/tool/chatactions/actionaction.h @@ -17,12 +17,12 @@ #ifndef ACTIONACTION_H #define ACTIONACTION_H -#include "chataction.h" +#include "messageaction.h" -class ActionAction : public ChatAction +class ActionAction : public MessageAction { public: - ActionAction(const QString &author, const QString &message, const QString& date, const bool&); + ActionAction(const QString &author, QString message, const QString& date, const bool&); virtual ~ActionAction(){;} virtual QString getMessage(); virtual QString getName(); diff --git a/src/widget/tool/chatactions/alertaction.cpp b/src/widget/tool/chatactions/alertaction.cpp new file mode 100644 index 000000000..b62c1896e --- /dev/null +++ b/src/widget/tool/chatactions/alertaction.cpp @@ -0,0 +1,47 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +#include "alertaction.h" + +AlertAction::AlertAction(const QString &author, const QString &message, const QString &date) : + MessageAction(author, message, date, false) +{ +} + +void AlertAction::setup(QTextCursor cursor, QTextEdit *) +{ + // When this function is called, we're supposed to only update ourselve when needed + // Nobody should ask us to do anything with our content, we're on our own + // Except we never udpate on our own, so we can safely free our resources + + (void) cursor; + message.clear(); + message.squeeze(); + name.clear(); + name.squeeze(); + date.clear(); + date.squeeze(); +} +/* +QString AlertAction::getName() +{ + return QString("
%2
").arg("alert_name").arg(toHtmlChars(name)); +} +*/ +QString AlertAction::getMessage() +{ + return MessageAction::getMessage("alert"); +} diff --git a/src/widget/tool/chatactions/alertaction.h b/src/widget/tool/chatactions/alertaction.h new file mode 100644 index 000000000..64e00e6bf --- /dev/null +++ b/src/widget/tool/chatactions/alertaction.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program is libre software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the COPYING file for more details. +*/ + +#ifndef ALERTACTION_H +#define ALERTACTION_H + +#include "messageaction.h" + +class AlertAction : public MessageAction +{ +public: + AlertAction(const QString &author, const QString &message, const QString& date); + virtual ~AlertAction(){;} + virtual QString getMessage(); + //virtual QString getName(); only do the message for now; preferably would do the whole row + virtual void setup(QTextCursor cursor, QTextEdit*) override; + +private: + QString message; +}; + +#endif // MESSAGEACTION_H diff --git a/src/widget/tool/chatactions/messageaction.cpp b/src/widget/tool/chatactions/messageaction.cpp index 4a8b6962b..8058aa56e 100644 --- a/src/widget/tool/chatactions/messageaction.cpp +++ b/src/widget/tool/chatactions/messageaction.cpp @@ -38,7 +38,7 @@ void MessageAction::setup(QTextCursor cursor, QTextEdit *) date.squeeze(); } -QString MessageAction::getMessage() +QString MessageAction::getMessage(QString div) { QString message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); @@ -65,14 +65,19 @@ QString MessageAction::getMessage() for (QString& s : messageLines) { if (QRegExp("^[ ]*>.*").exactMatch(s)) - message_ += ">" + s.right(s.length()-4) + "
"; + message_ += "" + s.right(s.length()-4) + "
"; else message_ += s + "
"; } message_ = message_.left(message_.length()-4); - if (isMe) - return QString("
" + message_ + "
"); - else - return QString("
" + message_ + "
"); + return QString(QString("
").arg(div) + message_ + "
"); +} + +QString MessageAction::getMessage() +{ + if (isMe) + return getMessage("message_me"); + else + return getMessage("message"); } diff --git a/src/widget/tool/chatactions/messageaction.h b/src/widget/tool/chatactions/messageaction.h index aa32801eb..c5ba63de3 100644 --- a/src/widget/tool/chatactions/messageaction.h +++ b/src/widget/tool/chatactions/messageaction.h @@ -25,9 +25,10 @@ public: MessageAction(const QString &author, const QString &message, const QString &date, const bool &me); virtual ~MessageAction(){;} virtual QString getMessage(); + virtual QString getMessage(QString div); virtual void setup(QTextCursor cursor, QTextEdit*) override; -private: +protected: QString message; }; diff --git a/src/widget/tool/chattextedit.cpp b/src/widget/tool/chattextedit.cpp index 9b51b8fba..d9ba2ee46 100644 --- a/src/widget/tool/chattextedit.cpp +++ b/src/widget/tool/chattextedit.cpp @@ -27,11 +27,15 @@ ChatTextEdit::ChatTextEdit(QWidget *parent) : void ChatTextEdit::keyPressEvent(QKeyEvent * event) { int key = event->key(); - if ((key == Qt::Key_Enter || key == Qt::Key_Return) - && !(event->modifiers() && Qt::ShiftModifier)) - { + if ((key == Qt::Key_Enter || key == Qt::Key_Return) && !(event->modifiers() && Qt::ShiftModifier)) emit enterPressed(); - return; + else if (key == Qt::Key_Tab) + emit tabPressed(); + else if (key == Qt::Key_Backspace) // because of the backspace() hack in tabber, we can't emit on these + QTextEdit::keyPressEvent(event); + else + { + emit keyPressed(); + QTextEdit::keyPressEvent(event); } - QTextEdit::keyPressEvent(event); } diff --git a/src/widget/tool/chattextedit.h b/src/widget/tool/chattextedit.h index f8a1cb73a..6bab07cda 100644 --- a/src/widget/tool/chattextedit.h +++ b/src/widget/tool/chattextedit.h @@ -28,6 +28,8 @@ public: signals: void enterPressed(); + void tabPressed(); + void keyPressed(); public slots: diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index fdc3465d8..51285fc99 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -61,7 +61,52 @@ Widget::Widget(QWidget *parent) void Widget::init() { + ui->setupUi(this); + + if (QSystemTrayIcon::isSystemTrayAvailable() == true) + { + icon = new QSystemTrayIcon(this); + icon->setIcon(this->windowIcon()); + trayMenu = new QMenu; + trayMenu->setStyleSheet("QMenu {background: white; color: black; border: 1px solid black;}" + "QMenu::item:selected { background: #414141}"); + + statusOnline = new QAction(tr("online"), this); + statusOnline->setIcon(QIcon(":ui/statusButton/dot_online.png")); + connect(statusOnline, SIGNAL(triggered()), this, SLOT(setStatusOnline())); + statusAway = new QAction(tr("away"), this); + statusAway->setIcon(QIcon(":ui/statusButton/dot_idle.png")); + connect(statusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); + statusBusy = new QAction(tr("busy"), this); + connect(statusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); + statusBusy->setIcon(QIcon(":ui/statusButton/dot_busy.png")); + actionQuit = new QAction(tr("&Quit"), this); + connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); + + trayMenu->addAction(new QAction(tr("Change status to:"), this)); + trayMenu->addAction(statusOnline); + trayMenu->addAction(statusAway); + trayMenu->addAction(statusBusy); + trayMenu->addSeparator(); + trayMenu->addAction(actionQuit); + icon->setContextMenu(trayMenu); + + connect(icon, + SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, + SLOT(onIconClick(QSystemTrayIcon::ActivationReason))); + + icon->show(); + + if(Settings::getInstance().getAutostartInTray() == false) + this->show(); + } + else + { + qWarning() << "No system tray detected!"; + this->show(); + } ui->statusbar->hide(); ui->menubar->hide(); @@ -148,7 +193,6 @@ void Widget::init() filesForm = new FilesForm(); addFriendForm = new AddFriendForm; settingsWidget = new SettingsWidget(); - connect(core, &Core::connected, this, &Widget::onConnected); connect(core, &Core::disconnected, this, &Widget::onDisconnected); @@ -233,12 +277,19 @@ Widget::~Widget() for (Group* g : GroupList::groupList) delete g; GroupList::groupList.clear(); + delete statusAway; + delete statusBusy; + delete statusOnline; + delete actionQuit; + delete trayMenu; + delete icon; delete ui; instance = nullptr; } Widget* Widget::getInstance() { + if (!instance) { instance = new Widget(); @@ -254,10 +305,30 @@ QThread* Widget::getCoreThread() void Widget::closeEvent(QCloseEvent *event) { - Settings::getInstance().setWindowGeometry(saveGeometry()); - Settings::getInstance().setWindowState(saveState()); - Settings::getInstance().setSplitterState(ui->mainSplitter->saveState()); - QWidget::closeEvent(event); + if(Settings::getInstance().getCloseToTray() == true) + { + event->ignore(); + this->hide(); + } + else + { + Settings::getInstance().setWindowGeometry(saveGeometry()); + Settings::getInstance().setWindowState(saveState()); + Settings::getInstance().setSplitterState(ui->mainSplitter->saveState()); + QWidget::closeEvent(event); + } +} + +void Widget::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::WindowStateChange) + { + if(isMinimized() == true + && Settings::getInstance().getMinimizeToTray() == true) + { + this->hide(); + } + } } QString Widget::detectProfile() @@ -454,12 +525,21 @@ void Widget::onTransferClicked() activeChatroomWidget = nullptr; } -void Widget::onIconClick() +void Widget::onIconClick(QSystemTrayIcon::ActivationReason reason) { - if(this->isHidden() == true) - this->show(); - else - this->hide(); + switch (reason) { + case QSystemTrayIcon::Trigger: + if(this->isHidden() == true) + this->show(); + else + this->hide(); + case QSystemTrayIcon::DoubleClick: + break; + case QSystemTrayIcon::MiddleClick: + break; + default: + ; + } } void Widget::onSettingsClicked() @@ -750,14 +830,19 @@ void Widget::onGroupMessageReceived(int groupnumber, const QString& message, con if (!g) return; - g->chatForm->addMessage(author, message); + QString name = core->getUsername(); + bool targeted = (author != name) && message.contains(name, Qt::CaseInsensitive); + if (targeted) + g->chatForm->addAlertMessage(author, message); + else + g->chatForm->addMessage(author, message); if ((static_cast(g->widget) != activeChatroomWidget) || isMinimized() || !isActiveWindow()) { g->hasNewMessages = 1; - newMessageAlert(); // sound alert on any message, not just naming user - if (message.contains(core->getUsername(), Qt::CaseInsensitive)) + if (targeted) { + newMessageAlert(); g->userWasMentioned = 1; // useful for highlighting line or desktop notifications } g->widget->updateStatusLight(); @@ -773,17 +858,23 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha g = createGroup(groupnumber); } + QString name = core->getGroupPeerName(groupnumber, peernumber); TOX_CHAT_CHANGE change = static_cast(Change); if (change == TOX_CHAT_CHANGE_PEER_ADD) { - QString name = core->getGroupPeerName(groupnumber, peernumber); if (name.isEmpty()) name = tr("", "Placeholder when we don't know someone's name in a group chat"); g->addPeer(peernumber,name); + //g->chatForm->addSystemInfoMessage(tr("%1 has joined the chat").arg(name), "green"); + // we can't display these messages until irungentoo fixes peernumbers + // https://github.com/irungentoo/toxcore/issues/1128 } else if (change == TOX_CHAT_CHANGE_PEER_DEL) + { g->removePeer(peernumber); - else if (change == TOX_CHAT_CHANGE_PEER_NAME) + //g->chatForm->addSystemInfoMessage(tr("%1 has left the chat").arg(name), "silver"); + } + else if (change == TOX_CHAT_CHANGE_PEER_NAME) // core overwrites old name before telling us it changed... g->updatePeer(peernumber,core->getGroupPeerName(groupnumber, peernumber)); } diff --git a/src/widget/widget.h b/src/widget/widget.h index 37af9b499..c75851a1b 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -18,6 +18,7 @@ #define WIDGET_H #include +#include #include "form/addfriendform.h" #include "form/settingswidget.h" #include "form/settings/identityform.h" @@ -65,6 +66,11 @@ public: ~Widget(); virtual void closeEvent(QCloseEvent *event); + virtual void changeEvent(QEvent *event); + + +public slots: + void onSettingsClicked(); signals: void friendRequestAccepted(const QString& userId); @@ -82,7 +88,6 @@ private slots: void onAddClicked(); void onGroupClicked(); void onTransferClicked(); - void onSettingsClicked(); void onFailedToStartCore(); void onBadProxyCore(); void onAvatarClicked(); @@ -112,7 +117,7 @@ private slots: void onMessageSendResult(int friendId, const QString& message, int messageId); void onGroupSendResult(int groupId, const QString& message, int result); void playRingtone(); - void onIconClick(); + void onIconClick(QSystemTrayIcon::ActivationReason); void onUserAway(); private: @@ -124,6 +129,12 @@ private: void removeGroup(Group* g); QString askProfiles(); QString detectProfile(); + QSystemTrayIcon *icon; + QMenu *trayMenu; + QAction *statusOnline, + *statusAway, + *statusBusy, + *actionQuit; Ui::MainWindow *ui; QSplitter *centralLayout; diff --git a/translations/fr.qm b/translations/fr.qm index ff6462596..cba6869e9 100644 Binary files a/translations/fr.qm and b/translations/fr.qm differ diff --git a/translations/fr.ts b/translations/fr.ts index a9837cde0..d18f9b982 100644 --- a/translations/fr.ts +++ b/translations/fr.ts @@ -3,11 +3,6 @@ AVForm - - - Audio/Video settings - - Hide video preview On a button @@ -18,6 +13,11 @@ On a button Montrer l'aperçu vidéo + + + Audio/Video + Audio/Vidéo + AVPage @@ -41,57 +41,52 @@ Form - + qTox - + + Video Settings + Options vidéo + + + + Resolution + Résolution + + + Volume Settings (Stubs) - + Options du volume (Fictif) - + Playback - + Haut-parleurs - + Microphone - - - - - Video settings - + Microphone - Modes - - - - Hue - + Teinte - + Brightness - + Luminosité - + Saturation - + Saturation - + Contrast - - - - - Preview - + Contraste Show video preview @@ -192,7 +187,7 @@ ChatForm - + Send a file Envoyer un fichier @@ -211,33 +206,44 @@ Core - - Encrypted profile - + + Toxing on qTox + Toxer avec qTox - + + qTox User + Utilisateur de qTox + + + + Encrypted profile + Profil chiffré + + + Your tox profile seems to be encrypted, qTox can't open it Do you want to erase this profile ? - + Votre profil tox semble être chiffré, qTox ne peut pas l'ouvrir +Voulez-vous effacer ce profil ? FileTransferInstance - + Save a file Title of the file saving dialog Sauvegarder un fichier - + Location not writable Title of permissions popup Impossible d'écrire ici - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Vous n'avez pas la permission d'écrire ici. Choisissez un audre endroit, ou annulez. @@ -309,19 +315,55 @@ Do you want to erase this profile ? FriendWidget - + + Invite to group + Menu to invite a friend to a groupchat + Inviter au groupe + + + Copy friend ID Menu to copy the Tox ID of that friend Copier l'ID ami - - Invite in group - Menu to invite a friend in a groupchat - Inviter dans un groupe + + Auto accept files from this friend + context menu entry + Automatiquement accepter les fichiers de ce contact - + + Manually accept files from this friend + context menu entry + Accepter les fichiers de ce contact manuellement + + + + Auto accept files from all friends + context menu entry + Accepter les fichiers de tous les contacts automatiquement + + + + Disable global auto accept + context menu entry + Désactiver l'acceptation automatique de fichier + + + + + Choose an auto accept directory + popup title + Choisir un dossier de téléchargement + + + Invite in group + Menu to invite a friend in a groupchat + Inviter dans un groupe + + + Remove friend Menu to remove the friend from our friendlist Supprimer ami @@ -330,9 +372,13 @@ Do you want to erase this profile ? GeneralForm - General Settings - Options Générales + Options Générales + + + + General + Général @@ -375,95 +421,110 @@ Do you want to erase this profile ? Form - + qTox General Settings - Options Générales + Options Générales - Use translations Text on a checkbox to enable translations - Utiliser les traductions + Utiliser les traductions - + + + The translation may not load until qTox restarts. + La translation peut ne pas se charger jusqu'à ce que qTox redémarre. + + + + Translation: + Traduction: + + + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - Sauvegarde les options dans le dossier courant au lieu du dossier de configuration habituel + Sauvegarde les options dans le dossier courant au lieu du dossier de configuration habituel - + Make Tox portable - Rendre Tox portable + Rendre Tox portable - + Start in tray - + Démarrer dans la barre d'état - + Show contacts' status changes - + Montrer les changements de status des contacts - + Provided in minutes - + En minutes - + Auto away after (0 to disable): - + Auto-absent après (0 pour désactiver): - - minutes - - - - - Theme - Thème + + Set to 0 to disable + Mettre à 0 pour désactiver + minutes + minutes + + + + Theme + Thème + + + Smiley Pack: Text on smiley pack label - + Pack de smileys: - + :) - + :) - + ;) - + :) - + :p - + :p - + :O - + :O - + :'( - + :'( - + Style: - + Style: Smiley Pack @@ -471,51 +532,51 @@ Do you want to erase this profile ? Pack de smileys - + Connection Settings - - - - - Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 - Activer IPv6 (recommandé) - - - - This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. - force tcp checkbox tooltip - - - - - Disable UDP (not recommended) - Text on checkbox to disable UDP - - - - - Use proxy (SOCKS5) - + Options de réseau - Address - Text on proxy addr label - + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Activer IPv6 (recommandé) + + + + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + force tcp checkbox tooltip + Permet par exemple d'utiliser Tox à travers Tor, mais ce n'est à utiliser que si nécessaire, car cela ralenti le réseau Tox. + Disable UDP (not recommended) + Text on checkbox to disable UDP + Désactiver UDP (non recommandé) + + + + Use proxy (SOCKS5) + Utiliser un proxy (SOCKS5) + + + + Address + Text on proxy addr label + Addresse + + + Port Text on proxy port label - + Port GenericChatForm - - + + Save chat log Sauvegarder l'historique de conversation @@ -523,7 +584,7 @@ Do you want to erase this profile ? GroupChatForm - + %1 users in chat Number of users in chat %1 personnes @@ -533,7 +594,7 @@ Do you want to erase this profile ? <Inconnu> - + %1 users in chat %1 personnes @@ -545,19 +606,19 @@ Do you want to erase this profile ? GroupWidget - - + + %1 users in chat %1 personnes - - + + 0 users in chat 0 personnes - + Quit group Menu to quit a groupchat Quitter le groupe @@ -566,87 +627,111 @@ Do you want to erase this profile ? IdentityForm - - Your identity - + + Identity + Identité - + Call active popup title - + Appel en cours - + You can't switch profiles while a call is active! popup text - + Vous ne pouvez pas changer de profil quand un appel est en cours! - + Rename "%1" renaming a profile - + Renommer "%1" - + + Profile already exists + rename confirm title + Ce profil existe déjà + + + + A profile named "%1" already exists. Do you want to erase it? + rename confirm text + Un profil appelé "%1" existe déjà. Voulez-vous le supprimer ? + + + Export profile save dialog title - + Exporter le profil - + Tox save file (*.tox) save dialog filter - + Fichier sauvegarde Tox (*.tox) - + Profile currently loaded current profile deletion warning title - + Profil en cours d'utilisation - + This profile is currently in use. Please load a different profile before deleting this one. current profile deletion warning text - + Ce profil est en cours d'utilisation. Merci de choisir un autre profil avant de supprimer celui-ci. - + Deletion imminent! deletion confirmation title - + Suppression imminente! - + Are you sure you want to delete this profile? deletion confirmation text - + Êtes-vous sur de vouloir supprimer ce profil ? - + Import profile import dialog title - + Importer un profil - + Tox save file (*.tox) import dialog filter - + Fichier sauvegarde Tox (*.tox) - + Ignoring non-Tox file popup title - + Fichier non-Tox ignoré - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text - + Attention: Vous avez sélectionné un fichier qui n'est pas une sauvegarde Tox: il sera ignoré. + + + + Profile already exists + import confirm title + Ce profil existe déjà + + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + Un profil appelé "%1" existe déjà. Voulez-vous le supprimer ? @@ -679,78 +764,84 @@ Do you want to erase this profile ? Form - + qTox Public Information - Informations Publiques + Informations Publiques Name - Nom + Nom Status - Status + Status Tox ID - ID Tox + ID Tox Your Tox ID (click to copy) - + Votre ID Tox (cliquez pour copier) Profiles - + Profils Available profiles: - + Profils disponibles: Load load profile button - + Charger Rename rename profile button - + Renommer Export export profile button - + Exporter Delete delete profile button - + Supprimer This is useful to remain safe on public computers delete profile button tooltip - + Util pour sécuriser sur un ordinateur public - + Import a profile import profile button - + Importer un profil + + + + New Tox ID + new profile button + Nouvel ID Tox @@ -805,8 +896,8 @@ Do you want to erase this profile ? PrivacyForm - Privacy settings - + Privacy + Vie privée @@ -903,103 +994,103 @@ Do you want to erase this profile ? Ctrl+Q - + Online Button to set your status to 'Online' Connecté - + Away Button to set your status to 'Away' - Indisponnible + Indisponible - + Busy Button to set your status to 'Busy' Occupé - + Choose a profile - + Choisir un profil - + Please choose which identity to use - + Merci de choisir l'identité à utiliser - + Choose a profile picture - + Choisissez une image de profil - - + + Error - - - - - Unable to open this file - - - - - Unable to read this image - + Erreur + Unable to open this file + Impossible d'ouvrir ce fichier + + + + Unable to read this image + Impossible de lire cette image + + + This image is too big - + Cette image est trop volumineuse - + Toxcore failed to start, the application will terminate after you close this message. - + Toxcore n'as pas pu démarrer correctement, l'application va quitter quand vous fermerez ce message. - + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text - + Toxcore n'as pas pu démarrer avec ces paramètres de proxy, qTox ne peut pas continuer; merci de modifier vos paramètres et redémarrer. - + away contact status - + indisponnible - + busy contact status - + occupé - + offline contact status - + déconnecté - + online contact status - + connecté - + %1 is now %2 e.g. "Dubslow is now online" - + %1 est maintenant %2 - + <Unknown> Placeholder when we don't know someone's name in a group chat <Inconnu> diff --git a/translations/it.qm b/translations/it.qm index 8aef73313..f4945ef5b 100644 Binary files a/translations/it.qm and b/translations/it.qm differ diff --git a/translations/it.ts b/translations/it.ts index 00ff091fe..80933d3e8 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -17,47 +17,47 @@ Form - + Video Settings Impostazioni Video - + Resolution Risoluzione - + Volume Settings (Stubs) - Impostazioni Volume (Stub) + Impostazioni Audio (Stub) - + Playback Altoparlanti - + Microphone Microfono - + Hue Colore - + Brightness Luminoistà - + Saturation Saturazione - + Contrast Contrasto @@ -153,12 +153,22 @@ Core - + + Toxing on qTox + Toxing on qTox + + + + qTox User + qTox User + + + Encrypted profile Profilo criptato - + Your tox profile seems to be encrypted, qTox can't open it Do you want to erase this profile ? Il tuo profilo Tox sembra essere criptato, qTox non può aprirlo\nVuoi eliminare questo profilo? @@ -167,19 +177,19 @@ Do you want to erase this profile ? FileTransferInstance - + Save a file Title of the file saving dialog Salva file - + Location not writable Title of permissions popup Errore - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Non hai sufficienti permessi per scrivere in questa locazione. Scegli un'altra posizione, o annulla il salvataggio. @@ -243,37 +253,50 @@ Do you want to erase this profile ? FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Copia Tox ID del contatto - - Invite in group - Menu to invite a friend in a groupchat - Invita nel gruppo - - - + Auto accept files from this friend context menu entry Accetta automaticamente i files inviati da questo contatto - - Diasble auto accepting files + + Invite to group + Menu to invite a friend to a groupchat + Invita nel gruppo + + + + Manually accept files from this friend context menu entry - Non accettare automaticamente i files inviati da questo contatto + Accetta manualmente i files inviati da questo contatto + + + + Auto accept files from all friends + context menu entry + Accetta automaticamente i files inviati da tutti i contatti + Disable global auto accept + context menu entry + Accetta manualmente i files inviati da tutti i contatti + + + Remove friend Menu to remove the friend from our friendlist Rimuovi contatto - + + Choose an auto accept directory popup title Scegli dove salvare i files accettati automaticamente @@ -311,33 +334,33 @@ Do you want to erase this profile ? Lingua: - + Auto away after (0 to disable): Imposta assenza dopo: - + Set to 0 to disable Imposta 0 per disabilitare - + Smiley Pack: Text on smiley pack label Emoticons: - + Style: Stile: - + Connection Settings Impostazioni Connessione - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Abilita IPv6 (consigliato) @@ -356,78 +379,88 @@ Do you want to erase this profile ? Start in tray - Avvia minimizzato + Avvia minimizzato nella traybar + Close to tray + Chiudi nella traybar + + + + Minimize to tray + Minimizza nella traybar + + + Show contacts' status changes Mostra quando i contatti cambiano stato - + Provided in minutes Espresso in minuti - + minutes minuti - + Theme Impostazioni Tema - + :) :) - + ;) ;) - + :p :p - + :O :O - + :'( :'( - + Use proxy (SOCKS5) Usa proxy (SOCKS5) - + Address Text on proxy addr label IP - + Port Text on proxy port label Porta - + Disable UDP (not recommended) Text on checkbox to disable UDP Disabilita connessioni UDP (non raccomandato) - + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. force tcp checkbox tooltip Questo permette di usare qTox con Tor; tuttavia aggiunge carico alla rete Tox, quindi usalo solo se necessario. @@ -436,8 +469,8 @@ Do you want to erase this profile ? GenericChatForm - - + + Save chat log Salva il log della chat @@ -445,13 +478,13 @@ Do you want to erase this profile ? GroupChatForm - + %1 users in chat Number of users in chat %1 utenti in chat - + %1 users in chat %1 utenti in chat @@ -485,83 +518,107 @@ Do you want to erase this profile ? Identità - + Call active popup title Chiamata in corso - + You can't switch profiles while a call is active! popup text Non puoi cambiare profilo durante una chiamata! - + Rename "%1" renaming a profile Rinomina "%1" - + + Profile already exists + rename confirm title + Profilo già esistente + + + + A profile named "%1" already exists. Do you want to erase it? + rename confirm text + Un profilo chiamato "%1" esiste già. Vuoi sovrascriverlo? + + + Export profile save dialog title Esporta profilo - + Tox save file (*.tox) save dialog filter Tox save file (*.tox) - + Profile currently loaded current profile deletion warning title Profilo attualmente in uso - + This profile is currently in use. Please load a different profile before deleting this one. current profile deletion warning text Questo profilo è attualmente in uso. Per favore carica un profilo differente prima di eliminare questo. - + Deletion imminent! deletion confirmation title Eliminazione imminente! - + Are you sure you want to delete this profile? deletion confirmation text Sei sicuro di voler eliminare questo profilo? - + Import profile import dialog title Importa profilo - + Tox save file (*.tox) import dialog filter Tox save file (*.tox) - + Ignoring non-Tox file popup title File ignorato - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text Attenzione: hai scelto un file che non contiente un profilo Tox.\nQuesto file verrà ignorato. + + + Profile already exists + import confirm title + Profilo già esistente + + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + Un profilo chiamato "%1" esiste già. Vuoi sovrascriverlo? + IdentitySettings @@ -636,10 +693,16 @@ Do you want to erase this profile ? Utile per preservare la tua sicurezza su computer pubblici - + Import a profile import profile button - Importa un profilo + Importa profilo + + + + New Tox ID + new profile button + Nuovo profilo @@ -701,103 +764,128 @@ Do you want to erase this profile ? Widget - + + online + online + + + + away + assente + + + + busy + occupato + + + + &Quit + &Esci + + + + Change status to: + Cambia stato in: + + + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Assente - + Busy Button to set your status to 'Busy' Occupato - + Choose a profile Scegli un profilo - + Please choose which identity to use Per favore scegli quale identità usare - + Choose a profile picture Scegli un'immagine per il profilo - - - + + + Error Errore - + Unable to open this file Impossibile aprire il file - + Unable to read this image Impossibile leggere l'immagine - + This image is too big L'immagine è troppo grande - + Toxcore failed to start, the application will terminate after you close this message. Impossibile avviare Toxcore.\nqTox terminerà dopo che avrai chiuso questo messaggio. - + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text Impossibile avviare Toxcore con le tue impostazione proxy.\nqTox non può funzionare correttamente, per favore modifica le impostazioni e riavvia il programma. - + away contact status assente - + busy contact status occupato - + offline contact status offline - + online contact status online - + %1 is now %2 e.g. "Dubslow is now online" %1 è ora %2 - + <Unknown> Placeholder when we don't know someone's name in a group chat <Sconosciuto> diff --git a/translations/pl.qm b/translations/pl.qm index 8f6d42d71..84f49ab21 100644 Binary files a/translations/pl.qm and b/translations/pl.qm differ diff --git a/translations/pl.ts b/translations/pl.ts index 8ca565afa..3a0b4a6de 100644 --- a/translations/pl.ts +++ b/translations/pl.ts @@ -48,27 +48,27 @@ Ustawienia - + Video Settings Ustawienia wideo - + Resolution Rozdzielczość - + Volume Settings (Stubs) Ustawienia dźwięku - + Playback Odtwarzanie - + Microphone Mikrofon @@ -81,22 +81,22 @@ Tryby - + Hue Odcień - + Brightness Jasność - + Saturation Nasycenie - + Contrast Kontrast @@ -200,12 +200,23 @@ Core - + + Toxing on qTox + better translation? + Toxuję na qTox + + + + qTox User + Użytkownik qToxa + + + Encrypted profile Zaszyfrowany profil - + Your tox profile seems to be encrypted, qTox can't open it Do you want to erase this profile ? Twój profil zdaje się być zaszyfrowany, qTox nie jest w stanie go otworzyć @@ -215,19 +226,19 @@ Czy chcesz usunąć ten profil ? FileTransferInstance - + Save a file Title of the file saving dialog Zapisz plik - + Location not writable Title of permissions popup Nie można zapisać w lokacji - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Nie masz uprawnienia by zapisać w tej lokacji. Wybierz inną lub anuluj zapis. @@ -291,37 +302,61 @@ Czy chcesz usunąć ten profil ? FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Kopiuj ID kontaktu - Invite in group Menu to invite a friend in a groupchat - Zaproś do grupy + Zaproś do grupy - + Auto accept files from this friend context menu entry Odbieraj pliki automatycznie - Diasble auto accepting files context menu entry - Nie odbieraj plików automatycznie + Nie odbieraj plików automatycznie + + + + Invite to group + Menu to invite a friend to a groupchat + Zaproś do grupy + + + + Manually accept files from this friend + context menu entry + Ręcznie akceptuj pliki od tego znajomego + + + + Auto accept files from all friends + context menu entry + Automatycznie akceptuj pliki od wszystkich znajomych + Disable global auto accept + context menu entry + better translation? + Wyłącz globalnie automatyczną akceptację + + + Remove friend Menu to remove the friend from our friendlist Usuń kontakt - + + Choose an auto accept directory popup title Wybierz domyślną ścieżkę dla plików @@ -390,7 +425,7 @@ Czy chcesz usunąć ten profil ? Use translations Text on a checkbox to enable translations - Użyj tłumaczenia + Użyj tłumaczenia @@ -422,33 +457,43 @@ Czy chcesz usunąć ten profil ? + Close to tray + Zamknij do traya + + + + Minimize to tray + Minimalizuj do traya + + + Show contacts' status changes Pokazuj zmiany statusów - + Provided in minutes Podane w minutach - + Auto away after (0 to disable): Zmiana statusu na "Nieobecny" (0 by wyłączyć): - + Set to 0 to disable Ustaw na 0 by wyłączyć - + Smiley Pack: Text on smiley pack label better translation? anyone? Paczka uśmiechów: - + Style: Styl: @@ -457,12 +502,12 @@ Czy chcesz usunąć ten profil ? Automatyczna zmiana statusu na "Nieobecny" po: - + minutes min - + Theme Motyw @@ -473,27 +518,27 @@ Czy chcesz usunąć ten profil ? Paczka uśmiechów - + :) :) - + ;) ;) - + :p :p - + :O :O - + :'( :'( @@ -502,41 +547,41 @@ Czy chcesz usunąć ten profil ? Styl - + Connection Settings Ustawienia połączenia - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Użyj IPv6 (zalecane) - + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. force tcp checkbox tooltip To pozwala np. na toxowanie przez Tora. Niestety obciąża to sieć Tox, więc używaj tylko w razie potrzeby. - + Disable UDP (not recommended) Text on checkbox to disable UDP Wyłącz UDP (nie zalecane) - + Use proxy (SOCKS5) Użyj proxy (SOCKS5) - + Address Text on proxy addr label Adres - + Port Text on proxy port label Port @@ -545,8 +590,8 @@ Czy chcesz usunąć ten profil ? GenericChatForm - - + + Save chat log Zapisz historię rozmowy @@ -554,7 +599,7 @@ Czy chcesz usunąć ten profil ? GroupChatForm - + %1 users in chat Number of users in chat %1 użytkowników w czacie @@ -564,7 +609,7 @@ Czy chcesz usunąć ten profil ? <Nieznany/a> - + %1 users in chat %1 użytkowników w czacie @@ -602,83 +647,107 @@ Czy chcesz usunąć ten profil ? Tożsamość - + Call active popup title Rozmowa w trakcie - + You can't switch profiles while a call is active! popup text Nie można zmienić profilu podczas aktywnego połączenia! - + Rename "%1" renaming a profile Zmień nazwę "%1" - + + Profile already exists + rename confirm title + Profil już istnieje + + + + A profile named "%1" already exists. Do you want to erase it? + rename confirm text + Profil pod nazwą "%1" już istnieje. Czy chcesz go usunąć? + + + Export profile save dialog title Eksportuj profil - + Tox save file (*.tox) save dialog filter Plik zapisu Tox (*.tox) - + Profile currently loaded current profile deletion warning title Profil obecnie załadowany - + This profile is currently in use. Please load a different profile before deleting this one. current profile deletion warning text Ten profil jest obecnie w użyciu. Proszę załaduj inny profil przed usunięciem tego. - + Deletion imminent! deletion confirmation title Usuwanie profilu! - + Are you sure you want to delete this profile? deletion confirmation text Czy na pewno chcesz usunąć ten profil? - + Import profile import dialog title Importuj profil - + Tox save file (*.tox) import dialog filter Plik zapisu Tox (*.tox) - + Ignoring non-Tox file popup title Zignorowano niepoprawny plik profilu - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text Ostrzeżenie: Wybrano plik który nie jest plikiem zapisu Tox; zignorowano. + + + Profile already exists + import confirm title + Profil już istnieje + + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + Profil pod nazwą "%1" już istnieje. Czy chcesz go usunąć? + IdentityPage @@ -778,11 +847,17 @@ Czy chcesz usunąć ten profil ? Użyteczne by pozostać bezpiecznym na publicznych komputerach - + Import a profile import profile button Importuj profil + + + New Tox ID + new profile button + Nowy Tox ID + MainWindow @@ -891,103 +966,128 @@ Czy chcesz usunąć ten profil ? Widget - + + online + online + + + + away + nieobecna/y + + + + busy + zajęta/y + + + + &Quit + &Wyjdź + + + + Change status to: + Zmień status na: + + + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Nieobecny/a - + Busy Button to set your status to 'Busy' Zajęty/a - + Choose a profile Wybierz profil - + Please choose which identity to use Proszę wybierz która tożsamość ma być użyta - + Choose a profile picture Wybierz obrazek profilu - - - + + + Error Błąd - + Unable to open this file Nie można otworzyć tego pliku - + Unable to read this image Nie można odczytać tego obrazka - + This image is too big Ten obrazek jest zbyt wielki - + Toxcore failed to start, the application will terminate after you close this message. Nie udało się uruchomić Toxcore, aplikacja zamknie się po zamknięciu tej wiadomości. - + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text Nie udało się uruchomić toxcore z twoimi ustawieniami proxy. qTox nie może działać, proszę zmodyfikuj ustawienia i zrestartuj. - + away contact status nieobecna/y - + busy contact status zajęta/y - + offline contact status offline - + online contact status online - + %1 is now %2 e.g. "Dubslow is now online" %1 jest teraz %2 - + <Unknown> Placeholder when we don't know someone's name in a group chat <Nieznany/a> diff --git a/translations/ru.qm b/translations/ru.qm index f3d7a3e2a..e228ad220 100644 Binary files a/translations/ru.qm and b/translations/ru.qm differ diff --git a/translations/ru.ts b/translations/ru.ts index 7860d8430..5290150e2 100644 --- a/translations/ru.ts +++ b/translations/ru.ts @@ -5,18 +5,8 @@ AVForm - Audio/Video settings - Настройки аудио/видео - - - Hide video preview - On a button - Спрятать видео-превью - - - Show video preview - On a button - Посмотреть видео-превью + Audio/Video + Аудио/Видео @@ -27,58 +17,49 @@ - - Volume Settings (Stubs) - - - - - Playback - - - - - Microphone - - - - - Video settings + + Video Settings Настройки видео - - Modes - + + Resolution + Разрешение - + + Volume Settings (Stubs) + Настройки звука (заглушка) + + + + Playback + Воспроизведение + + + + Microphone + Микрофон + + + Hue - + Тон - + Brightness - + Яркость - + Saturation - + Насыщенность - + Contrast - - - - - Preview - - - - Show video preview - Посмотреть видео-превью + Контраст @@ -166,7 +147,7 @@ ChatForm - + Send a file Отправить файл @@ -174,12 +155,23 @@ Core - + + Toxing on qTox + Как-то так. Может, можно ещё что-нибудь придумать? + Всем привет из qTox'а + + + + qTox User + Пользователь qTox + + + Encrypted profile Зашифрованный профиль - + Your tox profile seems to be encrypted, qTox can't open it Do you want to erase this profile ? Похоже, ваш tox-профиль зашифрован, qTox не может открыть его @@ -189,19 +181,19 @@ Do you want to erase this profile ? FileTransferInstance - + Save a file Title of the file saving dialog Сохранить файл - + Location not writable Title of permissions popup Непригодная для записи локация - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup У вас нет прав записи в эту локацию. Выберете другую или закройте диалог сохранения. @@ -267,40 +259,71 @@ Do you want to erase this profile ? FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Копировать ID друга - Invite in group Menu to invite a friend in a groupchat + Пригласить в группу + + + + Auto accept files from this friend + context menu entry + Автоматически принимать файлы от этого друга + + + Diasble auto accepting files + context menu entry + Запретить принимать файлы автоматически + + + + Invite to group + Menu to invite a friend to a groupchat Пригласить в группу - + + Manually accept files from this friend + context menu entry + Вручную принимать файлы от этого друга + + + + Auto accept files from all friends + context menu entry + Автоматически принимать файлы от всех друзей + + + + Disable global auto accept + context menu entry + Выключить глобальное автопринятие + + + Remove friend Menu to remove the friend from our friendlist Удалить друга + + + + Choose an auto accept directory + popup title + Выбрать папку для автоматического приёма + GeneralForm - - General Settings - Общие настройки - - - Bad port - title of bad port popup - Неправильный порт - - - The port you entered is invalid; please enter another. - text of bad port popup - Введёный порт неверен; введите другой. + + General + Общие @@ -316,153 +339,154 @@ Do you want to erase this profile ? Общие настройки - + + + The translation may not load until qTox restarts. + Перевод не изменится до перезапуска qTox. + + + + Translation: + Перевод: + + + + Close to tray + Сворачивать в трей при закрытии + + + + Minimize to tray + Сворачивать в трей + + + + Set to 0 to disable + Укажите 0, чтобы отключить + + + Smiley Pack: Text on smiley pack label - - - - - :) - - - - - ;) - - - - - :p - - - - - :O - + Набор смайликов: + :) + :) + + + + ;) + ;) + + + + :p + :p + + + + :O + :O + + + :'( - + :'( - + Style: - + Стиль: - + Connection Settings - + Настройки соединения - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Включить IPv6 (рекомендуется) - + Use proxy (SOCKS5) - + Использовать прокси (SOCKS5) - + Address Text on proxy addr label - + Адрес - + Port Text on proxy port label - + Порт - - Use translations - Text on a checkbox to enable translations - Использовать перевод - - - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox Сохранять настройки в рабочую директорию вместо страндартной папки настроек - + Make Tox portable Портативный режим - + Start in tray - + Запускать в системном лотке - + Show contacts' status changes - + Показывать изменения статусов контактов - + Provided in minutes - + Выставлено в минутах - + Auto away after (0 to disable): - + Автоматически отсутствовать после (0 для отключения): - + minutes - + минут - + Theme Тема - Smiley Pack - Text on smiley pack label - Набор смайликов - - - Proxy settings - Настройки прокси - - - + Disable UDP (not recommended) Text on checkbox to disable UDP Выключить UDP (не рекомендуется) - + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. force tcp checkbox tooltip Это позволяет, например, использовать tox поверх Tor. Однако это добавляет нагрузку на сеть Tox, так что используйте только в случае необходимости. - - Proxy address - Text on proxy addr label - Адрес прокси - - - Proxy port - Text on proxy port label - Порт прокси - GenericChatForm - - + + Save chat log Сохранить лог чата @@ -470,13 +494,13 @@ Do you want to erase this profile ? GroupChatForm - + %1 users in chat Number of users in chat %1 пользователей в чате - + %1 users in chat %1 пользователей в чате @@ -484,20 +508,20 @@ Do you want to erase this profile ? GroupWidget - + Quit group Menu to quit a groupchat Покинуть группу - - + + %1 users in chat %1 пользователей в чате - - + + 0 users in chat Ни одного пользователя в чате @@ -505,87 +529,111 @@ Do you want to erase this profile ? IdentityForm - - Your identity - Ваша идентификация + + Identity + Личность - + Call active popup title - + Идёт звонок - + You can't switch profiles while a call is active! popup text - + Вы не можете переключить профиль, пока идёт звонок! - + Rename "%1" renaming a profile - + Переименовать «%1» - + + Profile already exists + rename confirm title + Профиль уже существует + + + + A profile named "%1" already exists. Do you want to erase it? + rename confirm text + Профиль с именем «%1» уже существует. Желаете его стереть? + + + Export profile save dialog title - + Экспортировать профиль - + Tox save file (*.tox) save dialog filter - + Файл сохранения Tox (*.tox) - + Profile currently loaded current profile deletion warning title - + Профиль в настоящее время загружен - + This profile is currently in use. Please load a different profile before deleting this one. current profile deletion warning text - + Этот профиль используется. Загрузите другой профиль, прежде чем удалять этот. - + Deletion imminent! deletion confirmation title - + Необратимое удаление! - + Are you sure you want to delete this profile? deletion confirmation text - + Вы действительно хотите удалить этот профиль? - + Import profile import dialog title - + Импортировать профиль - + Tox save file (*.tox) import dialog filter - + Файл сохранения Tox (*.tox) - + Ignoring non-Tox file popup title - + Игнорирование не-Tox файла - + Warning: you've chosen a file that is not a Tox save file; ignoring. popup text - + Внимание: вы выбрали не файл сохранения Tox; игнорирование. + + + + Profile already exists + import confirm title + Профиль уже существует + + + + A profile named "%1" already exists. Do you want to erase it? + import confirm text + Профиль с именем «%1» уже существует. Желаете его стереть? @@ -623,48 +671,54 @@ Do you want to erase this profile ? Profiles - + Профили Available profiles: - + Доступные профили: Load load profile button - + Загрузить Rename rename profile button - + Переименовать Export export profile button - + Экспортировать Delete delete profile button - + Удалить This is useful to remain safe on public computers delete profile button tooltip - + Это полезно, чтобы оставаться в безопасности за общими компьютерами - + Import a profile import profile button - + Импортировать профиль + + + + New Tox ID + new profile button + Новый Tox ID @@ -719,122 +773,139 @@ Do you want to erase this profile ? PrivacyForm - Privacy settings - Настройки приватности - - - - SelfCamView - - Tox video test - Title of the window to test the video/webcam - Проверка видео + Privacy + Защищённость Widget - + + online + в сети + + + + away + отошёл + + + + busy + занят + + + + &Quit + В&ыход + + + + Change status to: + Сменить статус на: + + + Online Button to set your status to 'Online' В сети - + Away Button to set your status to 'Away' Вероятно, это не столь долгое путешествие Отошёл - + Busy Button to set your status to 'Busy' Занят - + Choose a profile - + Выберите профиль - + Please choose which identity to use - + Выберите личность, которую хотите использовать - + Choose a profile picture Выбрать картинку для профиля - - - + + + Error Ошибка - + Unable to open this file Невозможно открыть файл - + Unable to read this image Невозможно прочесть это изображение - + This image is too big Это изображение слишком большое - + Toxcore failed to start, the application will terminate after you close this message. Не удалось запустить toxcore, приложение будет завершено после того как вы закроете это сообщение. - + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. popup text Не удалось запустить toxcore с вашими настройками прокси, qTox не может работать; измените ваши настройки и перезапустите его. - + away contact status - + отсутствует - + busy contact status - + занят - + offline contact status - + офлайн - + online contact status - + в сети - + %1 is now %2 e.g. "Dubslow is now online" - + %1 сейчас %2 - + <Unknown> Placeholder when we don't know someone's name in a group chat - <Неизвестно> + <Неизвестный> diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index b5c537362..dc1f46d73 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -38,8 +38,8 @@ span.quote { } div.green { - margin-top: 12px; - margin-bottom: 12px; + margin-top: 6px; + margin-bottom: 6px; margin-left: 0px; margin-right: 0px; color: @white; @@ -48,8 +48,8 @@ div.green { } div.silver { - margin-top: 12px; - margin-bottom: 12px; + margin-top: 6px; + margin-bottom: 6px; margin-left: 0px; margin-right: 0px; color: @black; @@ -58,8 +58,8 @@ div.silver { } div.red { - margin-top: 12px; - margin-bottom: 12px; + margin-top: 6px; + margin-bottom: 6px; margin-left: 0px; margin-right: 0px; color: @white; @@ -67,6 +67,20 @@ div.red { font: @small; } +div.alert { + margin-left: 0px; + margin-right: 0px; + color: @black; + background-color: @orange; + font: @big; +} + +div.alert_name { + color: @black; + background-color: @orange; + font: @bigBold; +} + div.button { margin-top: 0px; margin-bottom: 0px;