Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d67a977c5 |
73
.gitignore
vendored
73
.gitignore
vendored
@ -1,73 +0,0 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
@ -5,29 +5,28 @@
|
||||
#include "task.h"
|
||||
enum
|
||||
{
|
||||
ClientInitId = 62000,
|
||||
ClientCloseId = 62001,
|
||||
AttachDatabaseId = 62002,
|
||||
SelectTaskId = 62003,
|
||||
UiInitId = 62004
|
||||
ClientInitId = 62000,
|
||||
ClientCloseId = 62001,
|
||||
AttachDatabaseId,
|
||||
SelectTaskId,
|
||||
UiInitId
|
||||
};
|
||||
|
||||
template <int N>
|
||||
class ClientEvent: public QEvent
|
||||
{
|
||||
private:
|
||||
int mType;
|
||||
int mType = N;
|
||||
public:
|
||||
ClientEvent(int numtype)
|
||||
:QEvent(static_cast<QEvent::Type>(numtype)), mType(numtype)
|
||||
ClientEvent<N>()
|
||||
:QEvent(static_cast<QEvent::Type>(N))
|
||||
{}
|
||||
};
|
||||
|
||||
class SelectTaskEvent: public ClientEvent
|
||||
class SelectTaskEvent: public ClientEvent<SelectTaskId>
|
||||
{
|
||||
public:
|
||||
SelectTaskEvent(PTask task)
|
||||
:ClientEvent(SelectTaskId)
|
||||
{
|
||||
SelectTaskEvent(PTask task) {
|
||||
mTask = task;
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
URL for used image:
|
||||
https://thenounproject.com/icon/coffee-break-537907/
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
#define APP_VERSION_MAJOR 0
|
||||
#define APP_VERSION_MINOR 9
|
||||
#define APP_VERSION_SUFFIX 7
|
||||
#define APP_VERSION_SUFFIX 8
|
||||
|
||||
//#ifdef TARGET_OSX
|
||||
#define ICONS ":/assets/images"
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QTextStream>
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QFile>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@ -138,15 +138,6 @@ bool date::operator >= (const date& rhs)
|
||||
return std::tie(mYear, mMonth, mDay) >= std::tie(rhs.mYear, rhs.mMonth, rhs.mDay);
|
||||
}
|
||||
|
||||
std::string date::toString() const
|
||||
{
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%02d:%02d:%02d", mDay, mMonth, mYear);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
time::time(int h, int m, int s)
|
||||
:mHour(h), mMinute(m), mSecond(s)
|
||||
{}
|
||||
@ -219,22 +210,14 @@ time_t chrono::strToTime(const std::string& s)
|
||||
|
||||
QString path::pathToSettings()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
QString folder = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
#else
|
||||
QString folder = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
||||
#endif
|
||||
QString folder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
QString path = folder + "/" + SETTINGS_FILENAME;
|
||||
return path;
|
||||
}
|
||||
|
||||
QString path::pathToDatabase()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
QString folder = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
#else
|
||||
QString folder = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
||||
#endif
|
||||
QString folder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
QString path = folder + "/" + DATABASENAME;
|
||||
return path;
|
||||
}
|
||||
@ -266,11 +249,7 @@ QString path::pathToDatabaseTemplate()
|
||||
|
||||
QString path::pathToLog()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
QString folder = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
#else
|
||||
QString folder = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
||||
#endif
|
||||
QString folder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
return folder + "/" + LOGNAME;
|
||||
}
|
||||
|
||||
|
||||
@ -39,8 +39,6 @@ namespace helper
|
||||
bool operator > (const date& rhs);
|
||||
bool operator == (const date& rhs);
|
||||
bool operator >= (const date& rhs);
|
||||
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
struct time
|
||||
|
||||
@ -6,14 +6,9 @@
|
||||
#include <QDir>
|
||||
#include "settings.h"
|
||||
#include "helper.h"
|
||||
#include "runguard.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
RunGuard guard("Noo app - runguard");
|
||||
if ( !guard.tryToRun() )
|
||||
return 0;
|
||||
|
||||
QApplication app(argc, argv);
|
||||
app.setApplicationName(APPNAME);
|
||||
helper::theme::applyCurrent(Settings::instance());
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
# include "platforms/linux/autostart.h"
|
||||
#endif
|
||||
|
||||
// #include <QDesktopWidget>
|
||||
#include <QDebug>
|
||||
#include <iostream>
|
||||
|
||||
@ -57,7 +58,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
setUpdatesEnabled(true);
|
||||
|
||||
// Other initialization will run in next event loop iteration
|
||||
QApplication::postEvent(this, new ClientEvent(UiInitId));
|
||||
QApplication::postEvent(this, new ClientEvent<UiInitId>());
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
@ -778,7 +779,7 @@ void MainWindow::setupMainUi()
|
||||
FvUpdater::sharedUpdater()->SetFeedURL("http://satorilight.com/LittAppCast.xml");
|
||||
#endif
|
||||
initClient();
|
||||
QApplication::postEvent(this, new ClientEvent(AttachDatabaseId));
|
||||
QApplication::postEvent(this, new ClientEvent<AttachDatabaseId>());
|
||||
}
|
||||
|
||||
void MainWindow::buildPasswordView()
|
||||
@ -1190,9 +1191,9 @@ int MainWindow::showTrayWindow(QDialog* dlg)
|
||||
|
||||
int w = dlg->geometry().width();
|
||||
int h = dlg->geometry().height();
|
||||
QRect rec = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
int desktopHeight = rec.height();
|
||||
int desktopWidth = rec.width();
|
||||
auto screen_size = QGuiApplication::primaryScreen()->size();
|
||||
int desktopHeight = screen_size.height();
|
||||
int desktopWidth = screen_size.width();
|
||||
|
||||
QRect iconRect;
|
||||
if (mTrayIcon)
|
||||
@ -1370,7 +1371,7 @@ void MainWindow::showTimeReport()
|
||||
|
||||
void MainWindow::criticalAlertFinished(int /*status*/)
|
||||
{
|
||||
QApplication::postEvent(this, new ClientEvent(ClientCloseId));
|
||||
QApplication::postEvent(this, new ClientEvent<ClientCloseId>());
|
||||
}
|
||||
|
||||
void MainWindow::warningAlertFinished(int /*status*/)
|
||||
|
||||
@ -174,11 +174,11 @@ macx {
|
||||
platforms/osx/sleeptracker_osx.mm
|
||||
}
|
||||
|
||||
#!include("fervor/Fervor.pri") {
|
||||
# error("Unable to include Fervor autoupdater.")
|
||||
#}
|
||||
!include("fervor/Fervor.pri") {
|
||||
error("Unable to include Fervor autoupdater.")
|
||||
}
|
||||
|
||||
!include("qtkeychain/qtkeychain.pri") {
|
||||
!include("qtkeychain/qt5keychain.pri") {
|
||||
error("Unable to include QTKeyChain library.")
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@ -1,75 +1,83 @@
|
||||
# [QMarkdownTextEdit](https://github.com/pbek/qmarkdowntextedit)
|
||||
[](https://github.com/pbek/qmarkdowntextedit/actions)
|
||||
[](https://travis-ci.org/pbek/qmarkdowntextedit)
|
||||
|
||||
[](https://github.com/pbek/qmarkdowntextedit/actions)
|
||||
[](https://travis-ci.org/pbek/qmarkdowntextedit)
|
||||
[](https://ci.appveyor.com/project/pbek/qmarkdowntextedit)
|
||||
|
||||
QMarkdownTextEdit is a C++ Qt [QPlainTextEdit](http://doc.qt.io/qt-5/qplaintextedit.html) widget with [markdown](https://en.wikipedia.org/wiki/Markdown) highlighting and some other goodies.
|
||||
|
||||
## Widget Features
|
||||
|
||||
- Markdown highlighting
|
||||
- Code syntax highlighting
|
||||
- Clickable links with `Ctrl + Click`
|
||||
- Block indent with `Tab` and `Shift + Tab`
|
||||
- Duplicate text with `Ctrl + Alt + Down`
|
||||
- Searching of text with `Ctrl + F`
|
||||
- Jump between search results with `Up` and `Down`
|
||||
- Close search field with `Escape`
|
||||
- Jump between search results with `Up` and `Down`
|
||||
- Close search field with `Escape`
|
||||
- Replacing of text with `Ctrl + R`
|
||||
- You can also replace text with regular expressions or whole words
|
||||
- You can also replace text with regular expressions or whole words
|
||||
- Line numbers (Qt >= 5.5)
|
||||
- Very fast
|
||||
- And much more...
|
||||
|
||||
## Supported Markdown Features
|
||||
|
||||
Commonmark compliance is enforced where possible however we are not fully Commonmark compliant yet. Following is a list of features/extensions supported by the highlighter. Please note that this is just a plaintext editor and as such, it only does the highlighting and not rendering of the markdown to HTML.
|
||||
|
||||
| Feature | Availablity |
|
||||
| --------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
||||
| Bolds and Italics | Yes |
|
||||
| Lists (Unordered/Orderered) | Yes |
|
||||
| Feature | Availablity |
|
||||
| --------------------------------------------------------------------------------------- | ----------------------------------------------------- |
|
||||
| Bolds and Italics | Yes |
|
||||
| Lists (Unordered/Orderered) | Yes |
|
||||
| Links and Images<br/>(Inline/Reference/Autolinks/E-mail) | Yes (Cannot handle nested links or complex cases yet) |
|
||||
| Heading (ATX and Setext) | Yes |
|
||||
| Codeblocks (indented and fenced)<br/> Both backtick and tilde code fences are supported | Yes (Only fenced code block has syntax highlighting) |
|
||||
| Inline code | Yes |
|
||||
| Strikethrough | Yes |
|
||||
| Underline | Yes (Optional) |
|
||||
| Blockquotes | Yes |
|
||||
| Table | Yes |
|
||||
|
||||
| Heading (ATX and Setext) | Yes |
|
||||
| Codeblocks (indented and fenced)<br/> Both backtick and tilde code fences are supported | Yes (Only fenced code block has syntax highlighting) |
|
||||
| Inline code | Yes |
|
||||
| Strikethrough | Yes |
|
||||
| Underline | Yes (Optional) |
|
||||
| Blockquotes | Yes |
|
||||
| Table | Yes |
|
||||
|
||||
## Screenshot
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
There are multiple ways to use this. You can use the editor directly, or you can subclass it or you can just use the highlighter.
|
||||
|
||||
### Using the editor
|
||||
|
||||
#### QMake
|
||||
- Include [qmarkdowntextedit.pri](https://github.com/pbek/qmarkdowntextedit/blob/develop/qmarkdowntextedit.pri)
|
||||
|
||||
- Include [qmarkdowntextedit.pri](https://github.com/pbek/qmarkdowntextedit/blob/main/qmarkdowntextedit.pri)
|
||||
to your project like this `include (qmarkdowntextedit/qmarkdowntextedit.pri)`
|
||||
- add a normal `QPlainTextEdit` to your UI and promote it to `QMarkdownTextEdit` (base class `QPlainTextEdit`)
|
||||
|
||||
#### CMake
|
||||
- Include [CMakeLists.txt](https://github.com/pbek/qmarkdowntextedit/blob/develop/CMakeLists.txt)
|
||||
|
||||
- Include [CMakeLists.txt](https://github.com/pbek/qmarkdowntextedit/blob/main/CMakeLists.txt)
|
||||
to your project like this `add_subdirectory(qmarkdowntextedit)`
|
||||
- add a normal `QPlainTextEdit` to your UI and promote it to `QMarkdownTextEdit` (base class `QPlainTextEdit`)
|
||||
|
||||
|
||||
### Using the highlighter only
|
||||
|
||||
Highlighter can work with both `QPlainTextEdit` and `QTextEdit`. Example:
|
||||
|
||||
```cpp
|
||||
auto doc = ui->plainTextEdit->document();
|
||||
auto *highlighter = new MarkdownHighlighter(doc);
|
||||
```
|
||||
|
||||
## Projects using QMarkdownTextEdit
|
||||
|
||||
- [QOwnNotes](https://github.com/pbek/QOwnNotes)
|
||||
- [Notes](https://github.com/nuttyartist/notes)
|
||||
- [CuteMarkEd-NG](https://github.com/Waqar144/CuteMarkEd-NG)
|
||||
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This SOFTWARE PRODUCT is provided by THE PROVIDER "as is" and "with all faults." THE PROVIDER makes no representations or warranties of any kind concerning the safety, suitability, lack of viruses, inaccuracies, typographical errors, or other harmful components of this SOFTWARE PRODUCT.
|
||||
|
||||
There are inherent dangers in the use of any software, and you are solely responsible for determining whether this SOFTWARE PRODUCT is compatible with your equipment and other software installed on your equipment. You are also solely responsible for the protection of your equipment and backup of your data, and THE PROVIDER will not be liable for any damages you may suffer in connection with using, modifying, or distributing this SOFTWARE PRODUCT.
|
||||
|
||||
22
client/qmarkdowntextedit/justfile
Normal file
22
client/qmarkdowntextedit/justfile
Normal file
@ -0,0 +1,22 @@
|
||||
# Use `just <recipe>` to run a recipe
|
||||
# https://just.systems/man/en/
|
||||
|
||||
# By default, run the `--list` command
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Aliases
|
||||
|
||||
alias fmt := format
|
||||
|
||||
# Format all files
|
||||
[group('linter')]
|
||||
format:
|
||||
nix-shell -p treefmt libclang nodePackages.prettier shfmt nixfmt-rfc-style taplo --run treefmt
|
||||
|
||||
# Add git commit hashes to the .git-blame-ignore-revs file
|
||||
[group('linter')]
|
||||
add-git-blame-ignore-revs:
|
||||
git log --pretty=format:"%H" --grep="^lint" >> .git-blame-ignore-revs
|
||||
sort .git-blame-ignore-revs | uniq > .git-blame-ignore-revs.tmp
|
||||
mv .git-blame-ignore-revs.tmp .git-blame-ignore-revs
|
||||
@ -11,11 +11,9 @@
|
||||
class LineNumArea final : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit LineNumArea(QMarkdownTextEdit *parent)
|
||||
: QWidget(parent),
|
||||
textEdit(parent)
|
||||
{
|
||||
: QWidget(parent), textEdit(parent) {
|
||||
Q_ASSERT(parent);
|
||||
|
||||
_currentLineColor = QColor(QStringLiteral("#eef067"));
|
||||
@ -26,16 +24,13 @@ public:
|
||||
setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||
}
|
||||
|
||||
void setCurrentLineColor(QColor color) {
|
||||
_currentLineColor = color;
|
||||
}
|
||||
void setCurrentLineColor(QColor color) { _currentLineColor = color; }
|
||||
|
||||
void setOtherLineColor(QColor color) {
|
||||
_otherLinesColor = std::move(color);
|
||||
}
|
||||
|
||||
int lineNumAreaWidth() const
|
||||
{
|
||||
int lineNumAreaWidth() const {
|
||||
if (!enabled) {
|
||||
return 0;
|
||||
}
|
||||
@ -48,40 +43,37 @@ public:
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x050B00
|
||||
int space = 13 + textEdit->fontMetrics().horizontalAdvance(u'9') * digits;
|
||||
int space =
|
||||
13 + textEdit->fontMetrics().horizontalAdvance(u'9') * digits;
|
||||
#else
|
||||
int space = 13 + textEdit->fontMetrics().width(QLatin1Char('9')) * digits;
|
||||
int space =
|
||||
13 + textEdit->fontMetrics().width(QLatin1Char('9')) * digits;
|
||||
#endif
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
bool isLineNumAreaEnabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
bool isLineNumAreaEnabled() const { return enabled; }
|
||||
|
||||
void setLineNumAreaEnabled(bool e)
|
||||
{
|
||||
void setLineNumAreaEnabled(bool e) {
|
||||
enabled = e;
|
||||
setHidden(!e);
|
||||
}
|
||||
|
||||
QSize sizeHint() const override
|
||||
{
|
||||
return {lineNumAreaWidth(), 0};
|
||||
}
|
||||
QSize sizeHint() const override { return {lineNumAreaWidth(), 0}; }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override
|
||||
{
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override {
|
||||
QPainter painter(this);
|
||||
|
||||
painter.fillRect(event->rect(), palette().color(QPalette::Active, QPalette::Window));
|
||||
painter.fillRect(event->rect(),
|
||||
palette().color(QPalette::Active, QPalette::Window));
|
||||
|
||||
auto block = textEdit->firstVisibleBlock();
|
||||
int blockNumber = block.blockNumber();
|
||||
qreal top = textEdit->blockBoundingGeometry(block).translated(textEdit->contentOffset()).top();
|
||||
qreal top = textEdit->blockBoundingGeometry(block)
|
||||
.translated(textEdit->contentOffset())
|
||||
.top();
|
||||
// Maybe the top is not 0?
|
||||
top += textEdit->viewportMargins().top();
|
||||
qreal bottom = top;
|
||||
@ -96,17 +88,13 @@ protected:
|
||||
if (block.isVisible() && bottom >= event->rect().top()) {
|
||||
QString number = QString::number(blockNumber + 1);
|
||||
|
||||
auto isCurrentLine = textEdit->textCursor().blockNumber() == blockNumber;
|
||||
auto isCurrentLine =
|
||||
textEdit->textCursor().blockNumber() == blockNumber;
|
||||
painter.setPen(isCurrentLine ? currentLine : otherLines);
|
||||
|
||||
painter.drawText(
|
||||
-5,
|
||||
top,
|
||||
sizeHint().width(),
|
||||
textEdit->fontMetrics().height(),
|
||||
Qt::AlignRight,
|
||||
number
|
||||
);
|
||||
painter.drawText(-5, top, sizeHint().width(),
|
||||
textEdit->fontMetrics().height(),
|
||||
Qt::AlignRight, number);
|
||||
}
|
||||
|
||||
block = block.next();
|
||||
@ -114,11 +102,11 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
bool enabled = false;
|
||||
QMarkdownTextEdit *textEdit;
|
||||
QColor _currentLineColor;
|
||||
QColor _otherLinesColor;
|
||||
};
|
||||
|
||||
#endif // LINENUMBERAREA_H
|
||||
#endif // LINENUMBERAREA_H
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2019-2021 Waqar Ahmed -- <waqar.17a@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -12,8 +12,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@ -27,7 +27,6 @@
|
||||
*/
|
||||
|
||||
#include "markdownhighlighter.h"
|
||||
#include "qownlanguagedata.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QRegularExpression>
|
||||
@ -37,18 +36,23 @@
|
||||
#include <QTimer>
|
||||
#include <utility>
|
||||
|
||||
// We enable QStringView with Qt 5.15.1
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 1)
|
||||
#define MH_SUBSTR(pos, len) text.midRef(pos, len)
|
||||
#include "qownlanguagedata.h"
|
||||
|
||||
// We enable QStringView with Qt 5.15.14
|
||||
// Note: QStringView::mid wasn't working correctly at least with 5.15.2
|
||||
// and 5.15.3, but 5.15.14 was fine
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 14)
|
||||
#define MH_SUBSTR(pos, len) text.midRef(pos, len)
|
||||
#else
|
||||
#define MH_SUBSTR(pos, len) QStringView(text).mid(pos, len)
|
||||
#define MH_SUBSTR(pos, len) QStringView(text).mid(pos, len)
|
||||
#endif
|
||||
|
||||
QHash<QString, MarkdownHighlighter::HighlighterState>
|
||||
MarkdownHighlighter::_langStringToEnum;
|
||||
QHash<MarkdownHighlighter::HighlighterState, QTextCharFormat>
|
||||
MarkdownHighlighter::_formats;
|
||||
QVector<MarkdownHighlighter::HighlightingRule> MarkdownHighlighter::_highlightingRules;
|
||||
QVector<MarkdownHighlighter::HighlightingRule>
|
||||
MarkdownHighlighter::_highlightingRules;
|
||||
|
||||
/**
|
||||
* Markdown syntax highlighting
|
||||
@ -169,7 +173,11 @@ void MarkdownHighlighter::initHighlightingRules() {
|
||||
{
|
||||
HighlightingRule rule(HighlighterState::Table);
|
||||
rule.shouldContain = QStringLiteral("|");
|
||||
rule.pattern = QRegularExpression(QStringLiteral("^\\|.+?\\|$"));
|
||||
// Support up to 3 leading spaces, because md4c seems to support it
|
||||
// See https://github.com/pbek/QOwnNotes/issues/3137
|
||||
rule.pattern =
|
||||
QRegularExpression(QStringLiteral("^\\s{0,3}(\\|.+?\\|)$"));
|
||||
rule.capturingGroup = 1;
|
||||
_highlightingRules.append(rule);
|
||||
}
|
||||
}
|
||||
@ -364,7 +372,12 @@ void MarkdownHighlighter::initCodeLangs() {
|
||||
{QLatin1String("xml"), MarkdownHighlighter::CodeXML},
|
||||
{QLatin1String("yml"), MarkdownHighlighter::CodeYAML},
|
||||
{QLatin1String("yaml"), MarkdownHighlighter::CodeYAML},
|
||||
{QLatin1String("forth"), MarkdownHighlighter::CodeForth}};
|
||||
{QLatin1String("forth"), MarkdownHighlighter::CodeForth},
|
||||
{QLatin1String("systemverilog"),
|
||||
MarkdownHighlighter::CodeSystemVerilog},
|
||||
{QLatin1String("gdscript"), MarkdownHighlighter::CodeGDScript},
|
||||
{QLatin1String("toml"), MarkdownHighlighter::CodeTOML},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -434,7 +447,7 @@ void MarkdownHighlighter::highlightMarkdown(const QString &text) {
|
||||
* @param text
|
||||
* @return 1, if 1 space, 2 if 2 spaces, 3 if 3 spaces. Otherwise 0
|
||||
*/
|
||||
int getIndentation(const QString &text) {
|
||||
static int getIndentation(const QString &text) {
|
||||
int spaces = 0;
|
||||
// no more than 3 spaces
|
||||
while (spaces < 4 && spaces < text.length() &&
|
||||
@ -443,6 +456,73 @@ int getIndentation(const QString &text) {
|
||||
return spaces;
|
||||
}
|
||||
|
||||
static bool isParagraph(const QString &text) {
|
||||
// blank line
|
||||
if (text.isEmpty()) return false;
|
||||
int indent = getIndentation(text);
|
||||
// code block
|
||||
if (indent >= 4) return false;
|
||||
|
||||
const auto textView = MH_SUBSTR(indent, -1);
|
||||
if (textView.isEmpty()) return false;
|
||||
|
||||
// unordered listtextView
|
||||
if (textView.startsWith(QStringLiteral("- ")) ||
|
||||
textView.startsWith(QStringLiteral("+ ")) ||
|
||||
textView.startsWith(QStringLiteral("* "))) {
|
||||
return false;
|
||||
}
|
||||
// block quote
|
||||
if (textView.startsWith(QStringLiteral("> "))) return false;
|
||||
// atx heading
|
||||
if (textView.startsWith(QStringLiteral("#"))) {
|
||||
int firstSpace = textView.indexOf(' ');
|
||||
if (firstSpace > 0 && firstSpace <= 7) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// hr
|
||||
auto isThematicBreak = [textView]() {
|
||||
return std::all_of(textView.begin(), textView.end(),
|
||||
[](QChar c) {
|
||||
auto ch = c.unicode();
|
||||
return ch == '-' || ch == ' ' || ch == '\t';
|
||||
}) ||
|
||||
std::all_of(textView.begin(), textView.end(),
|
||||
[](QChar c) {
|
||||
auto ch = c.unicode();
|
||||
return ch == '+' || ch == ' ' || ch == '\t';
|
||||
}) ||
|
||||
std::all_of(textView.begin(), textView.end(), [](QChar c) {
|
||||
auto ch = c.unicode();
|
||||
return ch == '*' || ch == ' ' || ch == '\t';
|
||||
});
|
||||
};
|
||||
if (isThematicBreak()) return false;
|
||||
// ordered list
|
||||
if (textView.at(0).isDigit()) {
|
||||
int i = 1;
|
||||
int count = 1;
|
||||
for (; i < textView.size(); ++i) {
|
||||
if (textView[i].isDigit()) {
|
||||
count++;
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// ordered list marker can't be more than 9 numbers
|
||||
if (count <= 9 && i + 1 < textView.size() &&
|
||||
(textView[i] == QLatin1Char('.') ||
|
||||
textView[i] == QLatin1Char(')')) &&
|
||||
textView[i + 1] == QLatin1Char(' ')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight headlines
|
||||
*
|
||||
@ -471,13 +551,15 @@ void MarkdownHighlighter::highlightHeadline(const QString &text) {
|
||||
const auto state =
|
||||
HighlighterState(HighlighterState::H1 + headingLevel - 1);
|
||||
|
||||
// Set styling of the "#"s to "masked syntax", but with the size of the heading
|
||||
// Set styling of the "#"s to "masked syntax", but with the size of
|
||||
// the heading
|
||||
auto maskedFormat = _formats[MaskedSyntax];
|
||||
maskedFormat.setFontPointSize(_formats[state].fontPointSize());
|
||||
setFormat(0, headingLevel, maskedFormat);
|
||||
|
||||
// Set the styling of the rest of the heading
|
||||
setFormat(headingLevel + 1, text.length() - 1 - headingLevel, _formats[state]);
|
||||
setFormat(headingLevel + 1, text.length() - 1 - headingLevel,
|
||||
_formats[state]);
|
||||
|
||||
setCurrentBlockState(state);
|
||||
return;
|
||||
@ -496,17 +578,22 @@ void MarkdownHighlighter::highlightHeadline(const QString &text) {
|
||||
// take care of ==== and ---- headlines
|
||||
const QString prev = currentBlock().previous().text();
|
||||
auto prevSpaces = getIndentation(prev);
|
||||
const bool isPrevParagraph = isParagraph(prev);
|
||||
|
||||
if (text.at(spacesOffset) == QLatin1Char('=') && prevSpaces < 4) {
|
||||
if (text.at(spacesOffset) == QLatin1Char('=') && prevSpaces < 4 &&
|
||||
isPrevParagraph) {
|
||||
const bool pattern1 =
|
||||
!prev.isEmpty() && hasOnlyHeadChars(text, QLatin1Char('='), spacesOffset);
|
||||
!prev.isEmpty() &&
|
||||
hasOnlyHeadChars(text, QLatin1Char('='), spacesOffset);
|
||||
if (pattern1) {
|
||||
highlightSubHeadline(text, H1);
|
||||
return;
|
||||
}
|
||||
} else if (text.at(spacesOffset) == QLatin1Char('-') && prevSpaces < 4) {
|
||||
} else if (text.at(spacesOffset) == QLatin1Char('-') && prevSpaces < 4 &&
|
||||
isPrevParagraph) {
|
||||
const bool pattern2 =
|
||||
!prev.isEmpty() && hasOnlyHeadChars(text, QLatin1Char('-'), spacesOffset);
|
||||
!prev.isEmpty() &&
|
||||
hasOnlyHeadChars(text, QLatin1Char('-'), spacesOffset);
|
||||
if (pattern2) {
|
||||
highlightSubHeadline(text, H2);
|
||||
return;
|
||||
@ -516,10 +603,12 @@ void MarkdownHighlighter::highlightHeadline(const QString &text) {
|
||||
const QString nextBlockText = currentBlock().next().text();
|
||||
if (nextBlockText.isEmpty()) return;
|
||||
const int nextSpaces = getIndentation(nextBlockText);
|
||||
const bool isCurrentParagraph = isParagraph(text);
|
||||
|
||||
if (nextSpaces >= nextBlockText.length()) return;
|
||||
|
||||
if (nextBlockText.at(nextSpaces) == QLatin1Char('=') && nextSpaces < 4) {
|
||||
if (nextBlockText.at(nextSpaces) == QLatin1Char('=') && nextSpaces < 4 &&
|
||||
isCurrentParagraph) {
|
||||
const bool nextHasEqualChars =
|
||||
hasOnlyHeadChars(nextBlockText, QLatin1Char('='), nextSpaces);
|
||||
if (nextHasEqualChars) {
|
||||
@ -527,7 +616,7 @@ void MarkdownHighlighter::highlightHeadline(const QString &text) {
|
||||
setCurrentBlockState(HighlighterState::H1);
|
||||
}
|
||||
} else if (nextBlockText.at(nextSpaces) == QLatin1Char('-') &&
|
||||
nextSpaces < 4) {
|
||||
nextSpaces < 4 && isCurrentParagraph) {
|
||||
const bool nextHasMinusChars =
|
||||
hasOnlyHeadChars(nextBlockText, QLatin1Char('-'), nextSpaces);
|
||||
if (nextHasMinusChars) {
|
||||
@ -577,7 +666,7 @@ void MarkdownHighlighter::highlightIndentedCodeBlock(const QString &text) {
|
||||
!text.startsWith(QLatin1Char('\t'))))
|
||||
return;
|
||||
|
||||
const QString prevTrimmed = currentBlock().previous().text().trimmed();
|
||||
const QString prevTrimmed = currentBlock().previous().text().trimmed();
|
||||
// previous line must be empty according to CommonMark except if it is a
|
||||
// heading https://spec.commonmark.org/0.29/#indented-code-block
|
||||
if (!prevTrimmed.isEmpty() && previousBlockState() != CodeBlockIndented &&
|
||||
@ -682,6 +771,9 @@ void MarkdownHighlighter::highlightSyntax(const QString &text) {
|
||||
bool isYAML = false;
|
||||
bool isMake = false;
|
||||
bool isForth = false;
|
||||
bool isGDScript = false;
|
||||
bool isSQL = false;
|
||||
bool isTOML = false;
|
||||
|
||||
QMultiHash<char, QLatin1String> keywords{};
|
||||
QMultiHash<char, QLatin1String> others{};
|
||||
@ -765,7 +857,12 @@ void MarkdownHighlighter::highlightSyntax(const QString &text) {
|
||||
break;
|
||||
case HighlighterState::CodeSQL:
|
||||
case HighlighterState::CodeSQL + tildeOffset:
|
||||
case HighlighterState::CodeSQLComment:
|
||||
case HighlighterState::CodeSQLComment + tildeOffset:
|
||||
loadSQLData(types, keywords, builtin, literals, others);
|
||||
isSQL = true;
|
||||
comment =
|
||||
QLatin1Char('-'); // prevent the default comment highlighting
|
||||
break;
|
||||
case HighlighterState::CodeJSON:
|
||||
case HighlighterState::CodeJSON + tildeOffset:
|
||||
@ -831,6 +928,24 @@ void MarkdownHighlighter::highlightSyntax(const QString &text) {
|
||||
isForth = true;
|
||||
loadForthData(types, keywords, builtin, literals, others);
|
||||
break;
|
||||
case HighlighterState::CodeSystemVerilog:
|
||||
case HighlighterState::CodeSystemVerilogComment:
|
||||
loadSystemVerilogData(types, keywords, builtin, literals, others);
|
||||
break;
|
||||
case HighlighterState::CodeGDScript:
|
||||
case HighlighterState::CodeGDScript + tildeOffset:
|
||||
isGDScript = true;
|
||||
loadGDScriptData(types, keywords, builtin, literals, others);
|
||||
comment = QLatin1Char('#');
|
||||
break;
|
||||
case HighlighterState::CodeTOML:
|
||||
case HighlighterState::CodeTOML + tildeOffset:
|
||||
case HighlighterState::CodeTOMLString:
|
||||
case HighlighterState::CodeTOMLString + tildeOffset:
|
||||
isTOML = true;
|
||||
loadTOMLData(types, keywords, builtin, literals, others);
|
||||
comment = QLatin1Char('#');
|
||||
break;
|
||||
default:
|
||||
setFormat(0, textLen, _formats[CodeBlock]);
|
||||
return;
|
||||
@ -841,7 +956,7 @@ void MarkdownHighlighter::highlightSyntax(const QString &text) {
|
||||
const QString &text, const QTextCharFormat &fmt) -> int {
|
||||
// check if we are at the beginning OR if this is the start of a word
|
||||
if (i == 0 || (!text.at(i - 1).isLetterOrNumber() &&
|
||||
text.at(i-1) != QLatin1Char('_'))) {
|
||||
text.at(i - 1) != QLatin1Char('_'))) {
|
||||
const char c = text.at(i).toLatin1();
|
||||
auto it = data.find(c);
|
||||
for (; it != data.end() && it.key() == c; ++it) {
|
||||
@ -992,6 +1107,9 @@ void MarkdownHighlighter::highlightSyntax(const QString &text) {
|
||||
if (isYAML) ymlHighlighter(text);
|
||||
if (isMake) makeHighlighter(text);
|
||||
if (isForth) forthHighlighter(text);
|
||||
if (isGDScript) gdscriptHighlighter(text);
|
||||
if (isSQL) sqlHighlighter(text);
|
||||
if (isTOML) tomlHighlighter(text);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1003,7 +1121,7 @@ void MarkdownHighlighter::highlightSyntax(const QString &text) {
|
||||
*/
|
||||
int MarkdownHighlighter::highlightStringLiterals(QChar strType,
|
||||
const QString &text, int i) {
|
||||
const auto& strFormat = _formats[CodeString];
|
||||
const auto &strFormat = _formats[CodeString];
|
||||
setFormat(i, 1, strFormat);
|
||||
++i;
|
||||
|
||||
@ -1606,6 +1724,213 @@ void MarkdownHighlighter::forthHighlighter(const QString &text) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The GDScript highlighter
|
||||
* @param text
|
||||
* @details This function is responsible for GDScript highlighting.
|
||||
* 1. Hightlight '$' NodePath constructs.
|
||||
* 2. Highlight '%' UniqueNode constructs.
|
||||
* 3. Highlight '@' annotations as `CodeOther`
|
||||
*/
|
||||
void MarkdownHighlighter::gdscriptHighlighter(const QString &text) {
|
||||
if (text.isEmpty()) return;
|
||||
|
||||
// 1. Hightlight '$' NodePath constructs.
|
||||
// 2. Highlight '%' UniqueNode constructs.
|
||||
const QRegularExpression re = QRegularExpression(QStringLiteral(
|
||||
R"([$%][a-zA-Z_][a-zA-Z0-9_]*(/[a-zA-Z_][a-zA-Z0-9_]*)*|@)"));
|
||||
QRegularExpressionMatchIterator i = re.globalMatch(text);
|
||||
while (i.hasNext()) {
|
||||
QRegularExpressionMatch match = i.next();
|
||||
// 3. Hightlight '@' annotation symbol
|
||||
if (match.captured().startsWith(QLatin1Char('@'))) {
|
||||
setFormat(match.capturedStart(), match.capturedLength(),
|
||||
_formats[CodeOther]);
|
||||
} else {
|
||||
setFormat(match.capturedStart(), match.capturedLength(),
|
||||
_formats[CodeNumLiteral]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The SQL highlighter
|
||||
* @param text
|
||||
* @details This function is responsible for SQL comment highlighting.
|
||||
* 1. Highlight "--" comments
|
||||
* 2. Highlight "/ *"-style multi-line comments
|
||||
*/
|
||||
void MarkdownHighlighter::sqlHighlighter(const QString &text) {
|
||||
if (text.isEmpty()) return;
|
||||
const auto textLen = text.length();
|
||||
|
||||
for (int i = 0; i < textLen; ++i) {
|
||||
if (i + 1 > textLen) {
|
||||
break;
|
||||
}
|
||||
// Check for comments: single-line, or multi-line start or end
|
||||
if (text[i] == QLatin1Char('-') && text[i + 1] == QLatin1Char('-')) {
|
||||
setFormat(i, textLen, _formats[CodeComment]);
|
||||
} else if (text[i] == QLatin1Char('/') &&
|
||||
text[i + 1] == QLatin1Char('*')) {
|
||||
// we're in a multi-line comment now
|
||||
if (currentBlockState() % 2 == 0) {
|
||||
setCurrentBlockState(currentBlockState() + 1);
|
||||
// Did the multi-line comment end in the same line?
|
||||
int endingComment = text.indexOf(QLatin1String("*/"), i + 2);
|
||||
int highlightEnd = textLen;
|
||||
if (endingComment > -1) {
|
||||
highlightEnd = endingComment + 2;
|
||||
}
|
||||
|
||||
setFormat(i, highlightEnd - i, _formats[CodeComment]);
|
||||
}
|
||||
} else if (text[i] == QLatin1Char('*') &&
|
||||
text[i + 1] == QLatin1Char('/')) {
|
||||
// we're now no longer in a multi-line comment
|
||||
if (currentBlockState() % 2 != 0) {
|
||||
setCurrentBlockState(currentBlockState() - 1);
|
||||
// Did the multi-line comment start in the same line?
|
||||
int startingComment = text.indexOf(QLatin1String("/*"), 0);
|
||||
int highlightStart = 0;
|
||||
if (startingComment > -1) {
|
||||
highlightStart = startingComment;
|
||||
}
|
||||
|
||||
setFormat(highlightStart - i, i + 1, _formats[CodeComment]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The TOML highlighter
|
||||
* @param text
|
||||
* @details This function is responsible for TOML highlighting.
|
||||
*/
|
||||
void MarkdownHighlighter::tomlHighlighter(const QString &text) {
|
||||
if (text.isEmpty()) return;
|
||||
const auto textLen = text.length();
|
||||
|
||||
bool onlyWhitespaceBeforeHeader = true;
|
||||
int possibleAssignmentPos = text.indexOf(QLatin1Char('='), 0);
|
||||
int singleQStringStart = -1;
|
||||
int doubleQStringStart = -1;
|
||||
int multiSingleQStringStart = -1;
|
||||
int multiDoubleQStringStart = -1;
|
||||
QLatin1Char singleQ = QLatin1Char('\'');
|
||||
QLatin1Char doubleQ = QLatin1Char('"');
|
||||
|
||||
for (int i = 0; i < textLen; ++i) {
|
||||
if (i + 1 > textLen) {
|
||||
break;
|
||||
}
|
||||
|
||||
// track the state of strings
|
||||
// multiline highlighting doesn't quite behave due to clashing handling
|
||||
// of " and ' chars, but this accomodates normal " and ' strings, as
|
||||
// well as ones wrapped by either """ or '''
|
||||
if (text[i] == doubleQ) {
|
||||
if (i + 2 <= textLen && text[i + 1] == doubleQ &&
|
||||
text[i + 2] == doubleQ) {
|
||||
if (multiDoubleQStringStart > -1) {
|
||||
multiDoubleQStringStart = -1;
|
||||
} else {
|
||||
multiDoubleQStringStart = i;
|
||||
int multiDoubleQStringEnd =
|
||||
text.indexOf(QLatin1String("\"\"\""), i + 1);
|
||||
if (multiDoubleQStringEnd > -1) {
|
||||
setFormat(i, multiDoubleQStringEnd - i,
|
||||
_formats[CodeString]);
|
||||
i = multiDoubleQStringEnd + 2;
|
||||
multiDoubleQStringEnd = -1;
|
||||
multiDoubleQStringStart = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (doubleQStringStart > -1) {
|
||||
doubleQStringStart = -1;
|
||||
} else {
|
||||
doubleQStringStart = i;
|
||||
}
|
||||
}
|
||||
} else if (text[i] == singleQ) {
|
||||
if (i + 2 <= textLen && text[i + 1] == singleQ &&
|
||||
text[i + 2] == singleQ) {
|
||||
if (multiSingleQStringStart > -1) {
|
||||
multiSingleQStringStart = -1;
|
||||
} else {
|
||||
multiSingleQStringStart = i;
|
||||
int multiSingleQStringEnd =
|
||||
text.indexOf(QLatin1String("'''"), i + 1);
|
||||
if (multiSingleQStringEnd > -1) {
|
||||
setFormat(i, multiSingleQStringEnd - i,
|
||||
_formats[CodeString]);
|
||||
i = multiSingleQStringEnd + 2;
|
||||
multiSingleQStringEnd = -1;
|
||||
multiSingleQStringStart = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (singleQStringStart > -1) {
|
||||
singleQStringStart = -1;
|
||||
} else {
|
||||
singleQStringStart = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool inString = doubleQStringStart > -1 || singleQStringStart > -1 ||
|
||||
multiSingleQStringStart > -1 ||
|
||||
multiDoubleQStringStart > -1;
|
||||
|
||||
// do comment highlighting
|
||||
if (text[i] == QLatin1Char('#') && !inString) {
|
||||
setFormat(i, textLen - i, _formats[CodeComment]);
|
||||
return;
|
||||
}
|
||||
|
||||
// table header (all stuff preceeding must only be whitespace)
|
||||
if (text[i] == QLatin1Char('[') && onlyWhitespaceBeforeHeader) {
|
||||
int headerEnd = text.indexOf(QLatin1Char(']'), i);
|
||||
if (headerEnd > -1) {
|
||||
setFormat(i, headerEnd + 1 - i, _formats[CodeType]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// handle numbers, inf, nan and datetime the same way
|
||||
if (i > possibleAssignmentPos && !inString &&
|
||||
(text[i].isNumber() || text.indexOf(QLatin1String("inf"), i) > 0 ||
|
||||
text.indexOf(QLatin1String("nan"), i) > 0)) {
|
||||
int nextWhitespace = text.indexOf(QLatin1Char(' '), i);
|
||||
int endOfNumber = textLen;
|
||||
if (nextWhitespace > -1) {
|
||||
if (text[nextWhitespace - 1] == QLatin1Char(','))
|
||||
nextWhitespace--;
|
||||
endOfNumber = nextWhitespace;
|
||||
}
|
||||
|
||||
int highlightStart = i;
|
||||
if (i > 0) {
|
||||
if (text[i - 1] == QLatin1Char('-') ||
|
||||
text[i - 1] == QLatin1Char('+')) {
|
||||
highlightStart--;
|
||||
}
|
||||
}
|
||||
setFormat(highlightStart, endOfNumber - highlightStart,
|
||||
_formats[CodeNumLiteral]);
|
||||
i = endOfNumber;
|
||||
}
|
||||
|
||||
if (!text[i].isSpace()) {
|
||||
onlyWhitespaceBeforeHeader = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight multi-line frontmatter blocks
|
||||
*
|
||||
@ -1675,17 +2000,14 @@ void MarkdownHighlighter::highlightCommentBlock(const QString &text) {
|
||||
void MarkdownHighlighter::highlightThematicBreak(const QString &text) {
|
||||
int i = 0;
|
||||
for (; i < 4 && i < text.length(); ++i) {
|
||||
if (text.at(i) != QLatin1Char(' '))
|
||||
break;
|
||||
if (text.at(i) != QLatin1Char(' ')) break;
|
||||
}
|
||||
|
||||
const QString sText = text.mid(i);
|
||||
if (sText.isEmpty() || i == 4 || text.startsWith(QLatin1Char('\t')))
|
||||
return;
|
||||
if (sText.isEmpty() || i == 4 || text.startsWith(QLatin1Char('\t'))) return;
|
||||
|
||||
const char c = sText.at(0).toLatin1();
|
||||
if (c != '-' && c != '_' && c != '*')
|
||||
return;
|
||||
if (c != '-' && c != '_' && c != '*') return;
|
||||
|
||||
int len = 0;
|
||||
bool hasSameChars = true;
|
||||
@ -1698,35 +2020,34 @@ void MarkdownHighlighter::highlightThematicBreak(const QString &text) {
|
||||
}
|
||||
if (len < 3) return;
|
||||
|
||||
if (hasSameChars)
|
||||
setFormat(0, text.length(), _formats[HorizontalRuler]);
|
||||
if (hasSameChars) setFormat(0, text.length(), _formats[HorizontalRuler]);
|
||||
}
|
||||
|
||||
void MarkdownHighlighter::highlightCheckbox(const QString &text, int curPos)
|
||||
{
|
||||
if (curPos + 4 >= text.length())
|
||||
return;
|
||||
void MarkdownHighlighter::highlightCheckbox(const QString &text, int curPos) {
|
||||
if (curPos + 4 >= text.length()) return;
|
||||
|
||||
const bool hasOpeningBracket = text.at(curPos + 2) == QLatin1Char('[');
|
||||
const bool hasClosingBracket = text.at(curPos + 4) == QLatin1Char(']');
|
||||
const QChar midChar = text.at(curPos + 3);
|
||||
const bool hasXorSpace = midChar == QLatin1Char(' ') || midChar == QLatin1Char('x') || midChar == QLatin1Char('X');
|
||||
const bool hasXorSpace = midChar == QLatin1Char(' ') ||
|
||||
midChar == QLatin1Char('x') ||
|
||||
midChar == QLatin1Char('X');
|
||||
const bool hasDash = midChar == QLatin1Char('-');
|
||||
|
||||
if (hasOpeningBracket && hasClosingBracket && (hasXorSpace || hasDash)) {
|
||||
const int start = curPos + 2;
|
||||
constexpr int length = 3;
|
||||
|
||||
const auto fmt = hasXorSpace ?
|
||||
(midChar == QLatin1Char(' ') ? CheckBoxUnChecked : CheckBoxChecked) :
|
||||
MaskedSyntax;
|
||||
const auto fmt = hasXorSpace
|
||||
? (midChar == QLatin1Char(' ') ? CheckBoxUnChecked
|
||||
: CheckBoxChecked)
|
||||
: MaskedSyntax;
|
||||
|
||||
setFormat(start, length, _formats[fmt]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool isBeginningOfList(QChar front)
|
||||
{
|
||||
static bool isBeginningOfList(QChar front) {
|
||||
return front == QLatin1Char('-') || front == QLatin1Char('+') ||
|
||||
front == QLatin1Char('*') || front.isNumber();
|
||||
}
|
||||
@ -1741,8 +2062,7 @@ void MarkdownHighlighter::highlightLists(const QString &text) {
|
||||
while (spaces < text.length() && text.at(spaces).isSpace()) ++spaces;
|
||||
|
||||
// return if we reached the end
|
||||
if (spaces >= text.length())
|
||||
return;
|
||||
if (spaces >= text.length()) return;
|
||||
|
||||
const QChar front = text.at(spaces);
|
||||
// check for start of list
|
||||
@ -1757,16 +2077,17 @@ void MarkdownHighlighter::highlightLists(const QString &text) {
|
||||
int number = curPos;
|
||||
// move forward till first non-number char
|
||||
while (number < text.length() && text.at(number).isNumber()) ++number;
|
||||
int count = number - curPos;
|
||||
|
||||
// reached end?
|
||||
if (number + 1 >= text.length()) return;
|
||||
if (number + 1 >= text.length() || count > 9) return;
|
||||
|
||||
// there should be a '.' or ')' after a number
|
||||
if ((text.at(number) == QLatin1Char('.') ||
|
||||
text.at(number) == QLatin1Char(')')) &&
|
||||
(text.at(number + 1) == QLatin1Char(' '))) {
|
||||
setCurrentBlockState(List);
|
||||
setFormat(curPos, number - curPos + 1, _formats[List]);
|
||||
setFormat(curPos, number - curPos + 1, _formats[List]);
|
||||
|
||||
// highlight checkbox if any
|
||||
highlightCheckbox(text, number);
|
||||
@ -1779,8 +2100,7 @@ void MarkdownHighlighter::highlightLists(const QString &text) {
|
||||
if (curPos + 1 >= text.length()) return;
|
||||
|
||||
// check for a space after it
|
||||
if (text.at(curPos + 1) != QLatin1Char(' '))
|
||||
return;
|
||||
if (text.at(curPos + 1) != QLatin1Char(' ')) return;
|
||||
|
||||
// check if we are in checkbox list
|
||||
highlightCheckbox(text, curPos);
|
||||
@ -1896,7 +2216,11 @@ int isInLinkRange(int pos, QVector<QPair<int, int>> &range) {
|
||||
* underlines, strikethrough, links, and images.
|
||||
*/
|
||||
void MarkdownHighlighter::highlightInlineRules(const QString &text) {
|
||||
bool isEmStrongDone = false;
|
||||
// clear existing span ranges for this block
|
||||
auto it = _ranges.find(currentBlock().blockNumber());
|
||||
if (it != _ranges.end()) {
|
||||
it->clear();
|
||||
}
|
||||
|
||||
for (int i = 0; i < text.length(); ++i) {
|
||||
QChar currentChar = text.at(i);
|
||||
@ -1907,14 +2231,12 @@ void MarkdownHighlighter::highlightInlineRules(const QString &text) {
|
||||
} else if (currentChar == QLatin1Char('<') &&
|
||||
MH_SUBSTR(i, 4) == QLatin1String("<!--")) {
|
||||
i = highlightInlineComment(text, i);
|
||||
} else if (!isEmStrongDone && (currentChar == QLatin1Char('*') ||
|
||||
currentChar == QLatin1Char('_'))) {
|
||||
highlightEmAndStrong(text, i);
|
||||
isEmStrongDone = true;
|
||||
} else {
|
||||
i = highlightLinkOrImage(text, i);
|
||||
}
|
||||
}
|
||||
|
||||
highlightEmAndStrong(text, 0);
|
||||
}
|
||||
|
||||
// Helper function for MarkdownHighlighter::highlightLinkOrImage
|
||||
@ -1998,8 +2320,6 @@ void MarkdownHighlighter::formatAndMaskRemaining(
|
||||
*/
|
||||
int MarkdownHighlighter::highlightLinkOrImage(const QString &text,
|
||||
int startIndex) {
|
||||
clearRangesForBlock(currentBlock().blockNumber(), RangeType::Link);
|
||||
|
||||
// If the first 4 characters are spaces (for 4-spaces fence code),
|
||||
// but not list markers, return
|
||||
if (text.left(4).trimmed().isEmpty()) {
|
||||
@ -2034,7 +2354,8 @@ int MarkdownHighlighter::highlightLinkOrImage(const QString &text,
|
||||
const static QStringList patterns = {"\\d+\\. ", "\\d+\\) "};
|
||||
|
||||
// Construct the regular expression pattern
|
||||
const static QString patternString = "^(" + patterns.join("|") + ")";
|
||||
const static QString patternString =
|
||||
"^(" + patterns.join("|") + ")";
|
||||
const static QRegularExpression pattern(patternString);
|
||||
|
||||
// Check if the text starts with any of the specified patterns
|
||||
@ -2195,8 +2516,7 @@ int MarkdownHighlighter::highlightLinkOrImage(const QString &text,
|
||||
*/
|
||||
int MarkdownHighlighter::highlightInlineSpans(const QString &text,
|
||||
int currentPos, const QChar c) {
|
||||
//clear code span ranges for this block
|
||||
clearRangesForBlock(currentBlock().blockNumber(), RangeType::CodeSpan);
|
||||
// clear code span ranges for this block
|
||||
|
||||
int i = currentPos;
|
||||
// found a backtick
|
||||
@ -2218,26 +2538,24 @@ int MarkdownHighlighter::highlightInlineSpans(const QString &text,
|
||||
if (next == -1) {
|
||||
return currentPos;
|
||||
}
|
||||
if (next + len < text.length() && text.at(next + len) == c) return currentPos;
|
||||
if (next + len < text.length() && text.at(next + len) == c)
|
||||
return currentPos;
|
||||
|
||||
//get existing format if any
|
||||
//we want to append to the existing format, not overwrite it
|
||||
// get existing format if any
|
||||
// we want to append to the existing format, not overwrite it
|
||||
QTextCharFormat fmt = QSyntaxHighlighter::format(start + 1);
|
||||
QTextCharFormat inlineFmt;
|
||||
|
||||
//select appropriate format for current text
|
||||
if (c != QLatin1Char('~'))
|
||||
inlineFmt = _formats[InlineCodeBlock];
|
||||
// select appropriate format for current text
|
||||
if (c != QLatin1Char('~')) inlineFmt = _formats[InlineCodeBlock];
|
||||
|
||||
|
||||
//make sure we don't change font size / existing formatting
|
||||
// make sure we don't change font size / existing formatting
|
||||
if (fmt.fontPointSize() > 0)
|
||||
inlineFmt.setFontPointSize(fmt.fontPointSize());
|
||||
|
||||
if (c == QLatin1Char('~'))
|
||||
{
|
||||
if (c == QLatin1Char('~')) {
|
||||
inlineFmt.setFontStrikeOut(true);
|
||||
//we don't want these properties for "inline code span"
|
||||
// we don't want these properties for "inline code span"
|
||||
inlineFmt.setFontItalic(fmt.fontItalic());
|
||||
inlineFmt.setFontWeight(fmt.fontWeight());
|
||||
inlineFmt.setFontUnderline(fmt.fontUnderline());
|
||||
@ -2245,10 +2563,11 @@ int MarkdownHighlighter::highlightInlineSpans(const QString &text,
|
||||
}
|
||||
|
||||
if (c == QLatin1Char('`')) {
|
||||
_ranges[currentBlock().blockNumber()].append(InlineRange(start, next, RangeType::CodeSpan));
|
||||
_ranges[currentBlock().blockNumber()].append(
|
||||
InlineRange(start, next, RangeType::CodeSpan));
|
||||
}
|
||||
|
||||
//format the text
|
||||
// format the text
|
||||
setFormat(start + len, next - (start + len), inlineFmt);
|
||||
|
||||
// format backticks as masked
|
||||
@ -2399,41 +2718,31 @@ void balancePairs(QVector<Delimiter> &delims) {
|
||||
}
|
||||
}
|
||||
|
||||
void MarkdownHighlighter::clearRangesForBlock(int blockNumber, RangeType type)
|
||||
{
|
||||
if (!_ranges.value(blockNumber).isEmpty()) {
|
||||
auto& rangeList = _ranges[currentBlock().blockNumber()];
|
||||
rangeList.erase(std::remove_if(rangeList.begin(), rangeList.end(),
|
||||
[type](const InlineRange& range) {
|
||||
return range.type == type;
|
||||
}), rangeList.end());
|
||||
}
|
||||
}
|
||||
|
||||
QPair<int,int>
|
||||
MarkdownHighlighter::findPositionInRanges(MarkdownHighlighter::RangeType type,
|
||||
int blockNum, int pos) const {
|
||||
QPair<int, int> MarkdownHighlighter::findPositionInRanges(
|
||||
MarkdownHighlighter::RangeType type, int blockNum, int pos) const {
|
||||
const QVector<InlineRange> rangeList = _ranges.value(blockNum);
|
||||
auto it = std::find_if(rangeList.cbegin(), rangeList.cend(),
|
||||
[pos, type](const InlineRange& range){
|
||||
if ((pos == range.begin || pos == range.end) && range.type == type)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
if (it == rangeList.cend())
|
||||
return {-1, -1};
|
||||
return { it->begin, it->end };
|
||||
auto it = std::find_if(
|
||||
rangeList.cbegin(), rangeList.cend(),
|
||||
[pos, type](const InlineRange &range) {
|
||||
if ((pos == range.begin || pos == range.end) && range.type == type)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
if (it == rangeList.cend()) return {-1, -1};
|
||||
return {it->begin, it->end};
|
||||
}
|
||||
|
||||
bool MarkdownHighlighter::isPosInACodeSpan(int blockNumber, int position) const
|
||||
{
|
||||
bool MarkdownHighlighter::isPosInACodeSpan(int blockNumber,
|
||||
int position) const {
|
||||
const QVector<InlineRange> rangeList = _ranges.value(blockNumber);
|
||||
return std::find_if(rangeList.cbegin(), rangeList.cend(),
|
||||
[position](const InlineRange& range){
|
||||
if (position > range.begin && position < range.end && range.type == RangeType::CodeSpan)
|
||||
return true;
|
||||
return false;
|
||||
}) != rangeList.cend();
|
||||
[position](const InlineRange &range) {
|
||||
if (position > range.begin &&
|
||||
position < range.end &&
|
||||
range.type == RangeType::CodeSpan)
|
||||
return true;
|
||||
return false;
|
||||
}) != rangeList.cend();
|
||||
}
|
||||
|
||||
bool MarkdownHighlighter::isPosInALink(int blockNumber, int position) const {
|
||||
@ -2446,15 +2755,18 @@ bool MarkdownHighlighter::isPosInALink(int blockNumber, int position) const {
|
||||
}) != rangeList.cend();
|
||||
}
|
||||
|
||||
QPair<int, int> MarkdownHighlighter::getSpanRange(MarkdownHighlighter::RangeType rangeType, int blockNumber, int position) const
|
||||
{
|
||||
QPair<int, int> MarkdownHighlighter::getSpanRange(
|
||||
MarkdownHighlighter::RangeType rangeType, int blockNumber,
|
||||
int position) const {
|
||||
const QVector<InlineRange> rangeList = _ranges.value(blockNumber);
|
||||
const auto it = std::find_if(rangeList.cbegin(), rangeList.cend(),
|
||||
[position, rangeType](const InlineRange& range){
|
||||
if (position > range.begin && position < range.end && range.type == rangeType)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
const auto it =
|
||||
std::find_if(rangeList.cbegin(), rangeList.cend(),
|
||||
[position, rangeType](const InlineRange &range) {
|
||||
if (position > range.begin && position < range.end &&
|
||||
range.type == rangeType)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (it == rangeList.cend()) {
|
||||
return QPair<int, int>(-1, -1);
|
||||
@ -2468,8 +2780,6 @@ QPair<int, int> MarkdownHighlighter::getSpanRange(MarkdownHighlighter::RangeType
|
||||
*/
|
||||
void MarkdownHighlighter::highlightEmAndStrong(const QString &text,
|
||||
const int pos) {
|
||||
clearRangesForBlock(currentBlock().blockNumber(), RangeType::Emphasis);
|
||||
|
||||
// 1. collect all em/strong delimiters
|
||||
QVector<Delimiter> delims;
|
||||
for (int i = pos; i < text.length(); ++i) {
|
||||
@ -2477,8 +2787,7 @@ void MarkdownHighlighter::highlightEmAndStrong(const QString &text,
|
||||
continue;
|
||||
|
||||
bool isInCodeSpan = isPosInACodeSpan(currentBlock().blockNumber(), i);
|
||||
if (isInCodeSpan)
|
||||
continue;
|
||||
if (isInCodeSpan) continue;
|
||||
|
||||
i = collectEmDelims(text, i, delims);
|
||||
--i;
|
||||
@ -2523,9 +2832,9 @@ void MarkdownHighlighter::highlightEmAndStrong(const QString &text,
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
|
||||
fmt.setFontFamily(_formats[Bold].fontFamily());
|
||||
#else
|
||||
const QStringList fontFamilies = _formats[Bold].fontFamilies().toStringList();
|
||||
if (!fontFamilies.isEmpty())
|
||||
fmt.setFontFamilies(fontFamilies);
|
||||
const QStringList fontFamilies =
|
||||
_formats[Bold].fontFamilies().toStringList();
|
||||
if (!fontFamilies.isEmpty()) fmt.setFontFamilies(fontFamilies);
|
||||
#endif
|
||||
|
||||
if (_formats[state].fontPointSize() > 0)
|
||||
@ -2547,16 +2856,10 @@ void MarkdownHighlighter::highlightEmAndStrong(const QString &text,
|
||||
masked.append({endDelim.pos, 2});
|
||||
|
||||
int block = currentBlock().blockNumber();
|
||||
_ranges[block].append(InlineRange(
|
||||
startDelim.pos,
|
||||
endDelim.pos + 1,
|
||||
RangeType::Emphasis
|
||||
));
|
||||
_ranges[block].append(InlineRange(
|
||||
startDelim.pos - 1,
|
||||
endDelim.pos,
|
||||
RangeType::Emphasis
|
||||
));
|
||||
_ranges[block].append(InlineRange(startDelim.pos, endDelim.pos + 1,
|
||||
RangeType::Emphasis));
|
||||
_ranges[block].append(InlineRange(startDelim.pos - 1, endDelim.pos,
|
||||
RangeType::Emphasis));
|
||||
--i;
|
||||
} else {
|
||||
// qDebug () << "Em: " << startDelim.pos << endDelim.pos;
|
||||
@ -2573,9 +2876,9 @@ void MarkdownHighlighter::highlightEmAndStrong(const QString &text,
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
|
||||
fmt.setFontFamily(_formats[Italic].fontFamily());
|
||||
#else
|
||||
const QStringList fontFamilies = _formats[Italic].fontFamilies().toStringList();
|
||||
if (!fontFamilies.isEmpty())
|
||||
fmt.setFontFamilies(fontFamilies);
|
||||
const QStringList fontFamilies =
|
||||
_formats[Italic].fontFamilies().toStringList();
|
||||
if (!fontFamilies.isEmpty()) fmt.setFontFamilies(fontFamilies);
|
||||
#endif
|
||||
|
||||
if (_formats[state].fontPointSize() > 0)
|
||||
@ -2595,11 +2898,8 @@ void MarkdownHighlighter::highlightEmAndStrong(const QString &text,
|
||||
masked.append({endDelim.pos, 1});
|
||||
|
||||
int block = currentBlock().blockNumber();
|
||||
_ranges[block].append(InlineRange(
|
||||
startDelim.pos,
|
||||
endDelim.pos,
|
||||
RangeType::Emphasis
|
||||
));
|
||||
_ranges[block].append(
|
||||
InlineRange(startDelim.pos, endDelim.pos, RangeType::Emphasis));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@ -107,10 +107,12 @@ class MarkdownHighlighter : public QSyntaxHighlighter {
|
||||
|
||||
enum class RangeType { CodeSpan, Emphasis, Link };
|
||||
|
||||
QPair<int, int> findPositionInRanges(MarkdownHighlighter::RangeType type, int blockNum, int pos) const;
|
||||
QPair<int, int> findPositionInRanges(MarkdownHighlighter::RangeType type,
|
||||
int blockNum, int pos) const;
|
||||
bool isPosInACodeSpan(int blockNumber, int position) const;
|
||||
bool isPosInALink(int blockNumber, int position) const;
|
||||
QPair<int, int> getSpanRange(RangeType rangeType, int blockNumber, int position) const;
|
||||
QPair<int, int> getSpanRange(RangeType rangeType, int blockNumber,
|
||||
int position) const;
|
||||
|
||||
// we used some predefined numbers here to be compatible with
|
||||
// the peg-Markdown parser
|
||||
@ -193,6 +195,7 @@ class MarkdownHighlighter : public QSyntaxHighlighter {
|
||||
CodeV = 222,
|
||||
CodeVComment = 223,
|
||||
CodeSQL = 224,
|
||||
CodeSQLComment = 225,
|
||||
CodeJSON = 226,
|
||||
CodeXML = 228,
|
||||
CodeCSS = 230,
|
||||
@ -208,7 +211,12 @@ class MarkdownHighlighter : public QSyntaxHighlighter {
|
||||
CodeMake = 244,
|
||||
CodeNix = 246,
|
||||
CodeForth = 248,
|
||||
CodeForthComment = 249
|
||||
CodeForthComment = 249,
|
||||
CodeSystemVerilog = 250,
|
||||
CodeSystemVerilogComment = 251,
|
||||
CodeGDScript = 252,
|
||||
CodeTOML = 254,
|
||||
CodeTOMLString = 255
|
||||
};
|
||||
Q_ENUM(HighlighterState)
|
||||
|
||||
@ -242,12 +250,10 @@ class MarkdownHighlighter : public QSyntaxHighlighter {
|
||||
int end;
|
||||
RangeType type;
|
||||
InlineRange() = default;
|
||||
InlineRange(int begin_, int end_, RangeType type_) :
|
||||
begin{begin_}, end{end_}, type{type_}
|
||||
{}
|
||||
InlineRange(int begin_, int end_, RangeType type_)
|
||||
: begin{begin_}, end{end_}, type{type_} {}
|
||||
};
|
||||
|
||||
|
||||
void highlightBlock(const QString &text) override;
|
||||
|
||||
static void initTextFormats(int defaultFontSize = 12);
|
||||
@ -287,8 +293,8 @@ class MarkdownHighlighter : public QSyntaxHighlighter {
|
||||
|
||||
void highlightInlineRules(const QString &text);
|
||||
|
||||
int highlightInlineSpans(const QString &text,
|
||||
int currentPos, const QChar c);
|
||||
int highlightInlineSpans(const QString &text, int currentPos,
|
||||
const QChar c);
|
||||
|
||||
void highlightEmAndStrong(const QString &text, const int pos);
|
||||
|
||||
@ -329,20 +335,21 @@ class MarkdownHighlighter : public QSyntaxHighlighter {
|
||||
void makeHighlighter(const QString &text);
|
||||
|
||||
void forthHighlighter(const QString &text);
|
||||
|
||||
void taggerScriptHighlighter(const QString &text);
|
||||
|
||||
void gdscriptHighlighter(const QString &text);
|
||||
void sqlHighlighter(const QString &text);
|
||||
void tomlHighlighter(const QString &text);
|
||||
|
||||
void addDirtyBlock(const QTextBlock &block);
|
||||
|
||||
void reHighlightDirtyBlocks();
|
||||
|
||||
void clearRangesForBlock(int blockNumber, RangeType type);
|
||||
|
||||
bool _highlightingFinished;
|
||||
HighlightingOptions _highlightingOptions;
|
||||
QTimer *_timer;
|
||||
QVector<QTextBlock> _dirtyTextBlocks;
|
||||
QVector<QPair<int,int>> _linkRanges;
|
||||
QVector<QPair<int, int>> _linkRanges;
|
||||
|
||||
QHash<int, QVector<InlineRange>> _ranges;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@ -37,7 +37,6 @@
|
||||
#include <QRegularExpressionMatch>
|
||||
#include <QRegularExpressionMatchIterator>
|
||||
#include <QScrollBar>
|
||||
#include <QSettings>
|
||||
#include <QTextBlock>
|
||||
#include <QTimer>
|
||||
#include <QWheelEvent>
|
||||
@ -95,22 +94,23 @@ QMarkdownTextEdit::QMarkdownTextEdit(QWidget *parent, bool initHighlighter)
|
||||
&QMarkdownTextEdit::adjustRightMargin);
|
||||
connect(this, &QPlainTextEdit::cursorPositionChanged, this,
|
||||
&QMarkdownTextEdit::centerTheCursor);
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged, this, [this](int) {
|
||||
_lineNumArea->update();
|
||||
});
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged, this,
|
||||
[this](int) { _lineNumArea->update(); });
|
||||
connect(this, &QPlainTextEdit::cursorPositionChanged, this, [this]() {
|
||||
_lineNumArea->update();
|
||||
|
||||
auto oldArea = blockBoundingGeometry(_textCursor.block()).translated(contentOffset());
|
||||
auto oldArea = blockBoundingGeometry(_textCursor.block())
|
||||
.translated(contentOffset());
|
||||
_textCursor = textCursor();
|
||||
auto newArea = blockBoundingGeometry(_textCursor.block()).translated(contentOffset());
|
||||
auto newArea = blockBoundingGeometry(_textCursor.block())
|
||||
.translated(contentOffset());
|
||||
auto areaToUpdate = oldArea | newArea;
|
||||
viewport()->update(areaToUpdate.toRect());
|
||||
});
|
||||
connect(document(), &QTextDocument::blockCountChanged,
|
||||
this, &QMarkdownTextEdit::updateLineNumberAreaWidth);
|
||||
connect(this, &QPlainTextEdit::updateRequest,
|
||||
this, &QMarkdownTextEdit::updateLineNumberArea);
|
||||
connect(document(), &QTextDocument::blockCountChanged, this,
|
||||
&QMarkdownTextEdit::updateLineNumberAreaWidth);
|
||||
connect(this, &QPlainTextEdit::updateRequest, this,
|
||||
&QMarkdownTextEdit::updateLineNumberArea);
|
||||
|
||||
updateSettings();
|
||||
|
||||
@ -126,29 +126,22 @@ void QMarkdownTextEdit::setLineNumbersOtherLineColor(QColor color) {
|
||||
_lineNumArea->setOtherLineColor(std::move(color));
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::setSearchWidgetDebounceDelay(uint debounceDelay)
|
||||
{
|
||||
void QMarkdownTextEdit::setSearchWidgetDebounceDelay(uint debounceDelay) {
|
||||
_debounceDelay = debounceDelay;
|
||||
searchWidget()->setDebounceDelay(_debounceDelay);
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::setHighlightCurrentLine(bool set)
|
||||
{
|
||||
void QMarkdownTextEdit::setHighlightCurrentLine(bool set) {
|
||||
_highlightCurrentLine = set;
|
||||
}
|
||||
|
||||
bool QMarkdownTextEdit::highlightCurrentLine()
|
||||
{
|
||||
return _highlightCurrentLine;
|
||||
}
|
||||
bool QMarkdownTextEdit::highlightCurrentLine() { return _highlightCurrentLine; }
|
||||
|
||||
void QMarkdownTextEdit::setCurrentLineHighlightColor(const QColor &color)
|
||||
{
|
||||
void QMarkdownTextEdit::setCurrentLineHighlightColor(const QColor &color) {
|
||||
_currentLineHighlightColor = color;
|
||||
}
|
||||
|
||||
QColor QMarkdownTextEdit::currentLineHighlightColor()
|
||||
{
|
||||
QColor QMarkdownTextEdit::currentLineHighlightColor() {
|
||||
return _currentLineHighlightColor;
|
||||
}
|
||||
|
||||
@ -218,6 +211,19 @@ bool QMarkdownTextEdit::eventFilter(QObject *obj, QEvent *event) {
|
||||
if ((keyEvent->key() == Qt::Key_Escape) && _searchWidget->isVisible()) {
|
||||
_searchWidget->deactivate();
|
||||
return true;
|
||||
} else if (keyEvent->key() == Qt::Key_Insert &&
|
||||
keyEvent->modifiers().testFlag(Qt::NoModifier)) {
|
||||
setOverwriteMode(!overwriteMode());
|
||||
|
||||
// This solves a UI glitch if the visual cursor was not properly
|
||||
// updated when characters have different widths
|
||||
QTextCursor cursor = this->textCursor();
|
||||
cursor.movePosition(QTextCursor::Right);
|
||||
setTextCursor(cursor);
|
||||
cursor.movePosition(QTextCursor::Left);
|
||||
setTextCursor(cursor);
|
||||
|
||||
return false;
|
||||
} else if ((keyEvent->key() == Qt::Key_Tab) ||
|
||||
(keyEvent->key() == Qt::Key_Backtab)) {
|
||||
// handle entered tab and reverse tab keys
|
||||
@ -277,12 +283,16 @@ bool QMarkdownTextEdit::eventFilter(QObject *obj, QEvent *event) {
|
||||
return bracketClosingCheck(QLatin1Char('['), QLatin1Char(']'));
|
||||
} else if (keyEvent->key() == Qt::Key_Greater) {
|
||||
return bracketClosingCheck(QLatin1Char('<'), QLatin1Char('>'));
|
||||
} else if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) &&
|
||||
} else if ((keyEvent->key() == Qt::Key_Return ||
|
||||
keyEvent->key() == Qt::Key_Enter) &&
|
||||
!isReadOnly() &&
|
||||
keyEvent->modifiers().testFlag(Qt::ShiftModifier)) {
|
||||
QTextCursor cursor = this->textCursor();
|
||||
cursor.insertText(" \n");
|
||||
return true;
|
||||
} else if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) &&
|
||||
} else if ((keyEvent->key() == Qt::Key_Return ||
|
||||
keyEvent->key() == Qt::Key_Enter) &&
|
||||
!isReadOnly() &&
|
||||
keyEvent->modifiers().testFlag(Qt::ControlModifier)) {
|
||||
QTextCursor cursor = this->textCursor();
|
||||
cursor.movePosition(QTextCursor::EndOfBlock);
|
||||
@ -377,7 +387,8 @@ bool QMarkdownTextEdit::eventFilter(QObject *obj, QEvent *event) {
|
||||
}
|
||||
}
|
||||
return QPlainTextEdit::eventFilter(obj, event);
|
||||
} else if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
|
||||
} else if (keyEvent->key() == Qt::Key_Return ||
|
||||
keyEvent->key() == Qt::Key_Enter) {
|
||||
return handleReturnEntered();
|
||||
} else if ((keyEvent->key() == Qt::Key_F3)) {
|
||||
_searchWidget->doSearch(
|
||||
@ -399,26 +410,30 @@ bool QMarkdownTextEdit::eventFilter(QObject *obj, QEvent *event) {
|
||||
moveTextUpDown(true);
|
||||
return true;
|
||||
#ifdef Q_OS_MAC
|
||||
// https://github.com/pbek/QOwnNotes/issues/1593
|
||||
// https://github.com/pbek/QOwnNotes/issues/2643
|
||||
// https://github.com/pbek/QOwnNotes/issues/1593
|
||||
// https://github.com/pbek/QOwnNotes/issues/2643
|
||||
} else if (keyEvent->key() == Qt::Key_Home) {
|
||||
QTextCursor cursor = textCursor();
|
||||
// Meta is Control on macOS
|
||||
cursor.movePosition(
|
||||
keyEvent->modifiers().testFlag(Qt::MetaModifier) ?
|
||||
QTextCursor::Start : QTextCursor::StartOfLine,
|
||||
keyEvent->modifiers().testFlag(Qt::ShiftModifier) ?
|
||||
QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
|
||||
keyEvent->modifiers().testFlag(Qt::MetaModifier)
|
||||
? QTextCursor::Start
|
||||
: QTextCursor::StartOfLine,
|
||||
keyEvent->modifiers().testFlag(Qt::ShiftModifier)
|
||||
? QTextCursor::KeepAnchor
|
||||
: QTextCursor::MoveAnchor);
|
||||
this->setTextCursor(cursor);
|
||||
return true;
|
||||
} else if (keyEvent->key() == Qt::Key_End) {
|
||||
QTextCursor cursor = textCursor();
|
||||
// Meta is Control on macOS
|
||||
cursor.movePosition(
|
||||
keyEvent->modifiers().testFlag(Qt::MetaModifier) ?
|
||||
QTextCursor::End : QTextCursor::EndOfLine,
|
||||
keyEvent->modifiers().testFlag(Qt::ShiftModifier) ?
|
||||
QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
|
||||
keyEvent->modifiers().testFlag(Qt::MetaModifier)
|
||||
? QTextCursor::End
|
||||
: QTextCursor::EndOfLine,
|
||||
keyEvent->modifiers().testFlag(Qt::ShiftModifier)
|
||||
? QTextCursor::KeepAnchor
|
||||
: QTextCursor::MoveAnchor);
|
||||
this->setTextCursor(cursor);
|
||||
return true;
|
||||
#endif
|
||||
@ -452,7 +467,7 @@ bool QMarkdownTextEdit::eventFilter(QObject *obj, QEvent *event) {
|
||||
} else if (event->type() == QEvent::MouseButtonDblClick) {
|
||||
_mouseButtonDown = true;
|
||||
} else if (event->type() == QEvent::Wheel) {
|
||||
auto *wheel = dynamic_cast<QWheelEvent*>(event);
|
||||
auto *wheel = dynamic_cast<QWheelEvent *>(event);
|
||||
|
||||
// emit zoom signals
|
||||
if (wheel->modifiers() == Qt::ControlModifier) {
|
||||
@ -474,7 +489,7 @@ void QMarkdownTextEdit::centerTheCursor() {
|
||||
return;
|
||||
}
|
||||
|
||||
// centers the cursor every time, but not on the top and bottom
|
||||
// Centers the cursor every time, but not on the top and bottom,
|
||||
// bottom is done by setCenterOnScroll() in updateSettings()
|
||||
centerCursor();
|
||||
|
||||
@ -547,6 +562,10 @@ void QMarkdownTextEdit::centerTheCursor() {
|
||||
* bracket closing was used otherwise performs normal undo
|
||||
*/
|
||||
void QMarkdownTextEdit::undo() {
|
||||
if (isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textCursor();
|
||||
// if no text selected, call undo
|
||||
if (!cursor.hasSelection()) {
|
||||
@ -576,6 +595,10 @@ void QMarkdownTextEdit::undo() {
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::moveTextUpDown(bool up) {
|
||||
if (isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textCursor();
|
||||
QTextCursor move = cursor;
|
||||
|
||||
@ -636,8 +659,7 @@ void QMarkdownTextEdit::moveTextUpDown(bool up) {
|
||||
setTextCursor(move);
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::setLineNumberEnabled(bool enabled)
|
||||
{
|
||||
void QMarkdownTextEdit::setLineNumberEnabled(bool enabled) {
|
||||
_lineNumArea->setLineNumAreaEnabled(enabled);
|
||||
updateLineNumberAreaWidth(0);
|
||||
}
|
||||
@ -702,10 +724,12 @@ bool QMarkdownTextEdit::handleBracketClosing(const QChar openingCharacter,
|
||||
|
||||
// get the current text from the block (inserted character not included)
|
||||
// Remove whitespace at start of string (e.g. in multilevel-lists).
|
||||
const QString text = cursor.block().text().remove(QRegularExpression("^\\s+"));
|
||||
static QRegularExpression regex1("^\\s+");
|
||||
const QString text = cursor.block().text().remove(regex1);
|
||||
|
||||
const int pib = cursor.positionInBlock();
|
||||
bool isPreviousAsterisk = pib > 0 && pib < text.length() && text.at(pib - 1) == '*';
|
||||
bool isPreviousAsterisk =
|
||||
pib > 0 && pib < text.length() && text.at(pib - 1) == '*';
|
||||
bool isNextAsterisk = pib < text.length() && text.at(pib) == '*';
|
||||
bool isMaybeBold = isPreviousAsterisk && isNextAsterisk;
|
||||
if (pib < text.length() && !isMaybeBold && !text.at(pib).isSpace()) {
|
||||
@ -746,12 +770,15 @@ bool QMarkdownTextEdit::handleBracketClosing(const QChar openingCharacter,
|
||||
}
|
||||
}
|
||||
|
||||
// Auto completion for ``` pair
|
||||
// Auto-completion for ``` pair
|
||||
if (openingCharacter == QLatin1Char('`')) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
|
||||
if (QRegExp(QStringLiteral("[^`]*``")).exactMatch(text)) {
|
||||
#else
|
||||
if (QRegularExpression(QRegularExpression::anchoredPattern(QStringLiteral("[^`]*``"))).match(text).hasMatch()) {
|
||||
if (QRegularExpression(
|
||||
QRegularExpression::anchoredPattern(QStringLiteral("[^`]*``")))
|
||||
.match(text)
|
||||
.hasMatch()) {
|
||||
#endif
|
||||
cursor.insertText(QStringLiteral("``"));
|
||||
cursorSubtract = 3;
|
||||
@ -942,7 +969,7 @@ bool QMarkdownTextEdit::handleBackspaceEntered() {
|
||||
return handleCharRemoval(MarkdownHighlighter::RangeType::CodeSpan,
|
||||
block, positionInBlock - 1);
|
||||
|
||||
//handle removal of ", ', and brackets
|
||||
// handle removal of ", ', and brackets
|
||||
|
||||
// is it opener?
|
||||
int pos = _openingCharacters.indexOf(charInFront);
|
||||
@ -1007,18 +1034,14 @@ bool QMarkdownTextEdit::handleBackspaceEntered() {
|
||||
}
|
||||
|
||||
bool QMarkdownTextEdit::handleCharRemoval(MarkdownHighlighter::RangeType type,
|
||||
int block, int position)
|
||||
{
|
||||
if (!_highlighter)
|
||||
return false;
|
||||
int block, int position) {
|
||||
if (!_highlighter) return false;
|
||||
|
||||
auto range = _highlighter->findPositionInRanges(type, block, position);
|
||||
if (range == QPair<int, int>{-1, -1})
|
||||
return false;
|
||||
if (range == QPair<int, int>{-1, -1}) return false;
|
||||
|
||||
int charToRemovePos = range.first;
|
||||
if (position == range.first)
|
||||
charToRemovePos = range.second;
|
||||
if (position == range.first) charToRemovePos = range.second;
|
||||
|
||||
QTextCursor cursor = textCursor();
|
||||
auto gpos = cursor.position();
|
||||
@ -1036,19 +1059,18 @@ bool QMarkdownTextEdit::handleCharRemoval(MarkdownHighlighter::RangeType type,
|
||||
return false;
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::updateLineNumAreaGeometry()
|
||||
{
|
||||
void QMarkdownTextEdit::updateLineNumAreaGeometry() {
|
||||
const auto contentsRect = this->contentsRect();
|
||||
const QRect newGeometry = {contentsRect.left(), contentsRect.top(),
|
||||
_lineNumArea->sizeHint().width(), contentsRect.height()};
|
||||
_lineNumArea->sizeHint().width(),
|
||||
contentsRect.height()};
|
||||
auto oldGeometry = _lineNumArea->geometry();
|
||||
if (newGeometry != oldGeometry) {
|
||||
_lineNumArea->setGeometry(newGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
void QMarkdownTextEdit::resizeEvent(QResizeEvent *event) {
|
||||
QPlainTextEdit::resizeEvent(event);
|
||||
updateLineNumAreaGeometry();
|
||||
}
|
||||
@ -1081,7 +1103,6 @@ bool QMarkdownTextEdit::increaseSelectedTextIndention(
|
||||
if (reverse) {
|
||||
// un-indent text
|
||||
|
||||
// QSettings settings;
|
||||
const int indentSize = indentCharacters == QStringLiteral("\t")
|
||||
? 4
|
||||
: indentCharacters.length();
|
||||
@ -1110,7 +1131,8 @@ bool QMarkdownTextEdit::increaseSelectedTextIndention(
|
||||
.prepend(indentCharacters);
|
||||
|
||||
// remove trailing \t
|
||||
newText.remove(QRegularExpression(QStringLiteral("\\t$")));
|
||||
static QRegularExpression regex1(QStringLiteral("\\t$"));
|
||||
newText.remove(regex1);
|
||||
}
|
||||
|
||||
// insert the new text
|
||||
@ -1138,8 +1160,8 @@ bool QMarkdownTextEdit::increaseSelectedTextIndention(
|
||||
}
|
||||
|
||||
// check for \t or space in front of cursor
|
||||
QRegularExpression re(QStringLiteral("[\\t ]"));
|
||||
QRegularExpressionMatch match = re.match(cursor.selectedText());
|
||||
static QRegularExpression regex1(QStringLiteral("[\\t ]"));
|
||||
QRegularExpressionMatch match = regex1.match(cursor.selectedText());
|
||||
|
||||
if (!match.hasMatch()) {
|
||||
// (select to) check for \t or space after the cursor
|
||||
@ -1150,7 +1172,7 @@ bool QMarkdownTextEdit::increaseSelectedTextIndention(
|
||||
}
|
||||
}
|
||||
|
||||
match = re.match(cursor.selectedText());
|
||||
match = regex1.match(cursor.selectedText());
|
||||
|
||||
if (match.hasMatch()) {
|
||||
cursor.removeSelectedText();
|
||||
@ -1218,8 +1240,8 @@ bool QMarkdownTextEdit::openLinkAtCursorPosition() {
|
||||
* @return
|
||||
*/
|
||||
bool QMarkdownTextEdit::isValidUrl(const QString &urlString) {
|
||||
const QRegularExpressionMatch match =
|
||||
QRegularExpression(R"(^\w+:\/\/.+)").match(urlString);
|
||||
static QRegularExpression regex(R"(^\w+:\/\/.+)");
|
||||
const QRegularExpressionMatch match = regex.match(urlString);
|
||||
return match.hasMatch();
|
||||
}
|
||||
|
||||
@ -1271,13 +1293,12 @@ void QMarkdownTextEdit::setIgnoredClickUrlSchemata(
|
||||
QMap<QString, QString> QMarkdownTextEdit::parseMarkdownUrlsFromText(
|
||||
const QString &text) {
|
||||
QMap<QString, QString> urlMap;
|
||||
QRegularExpression regex;
|
||||
QRegularExpressionMatchIterator iterator;
|
||||
|
||||
// match urls like this: <http://mylink>
|
||||
// re = QRegularExpression("(<(.+?:\\/\\/.+?)>)");
|
||||
regex = QRegularExpression(QStringLiteral("(<(.+?)>)"));
|
||||
iterator = regex.globalMatch(text);
|
||||
static QRegularExpression regex1(QStringLiteral("(<(.+?)>)"));
|
||||
iterator = regex1.globalMatch(text);
|
||||
while (iterator.hasNext()) {
|
||||
QRegularExpressionMatch match = iterator.next();
|
||||
QString linkText = match.captured(1);
|
||||
@ -1287,8 +1308,8 @@ QMap<QString, QString> QMarkdownTextEdit::parseMarkdownUrlsFromText(
|
||||
|
||||
// match urls like this: [this url](http://mylink)
|
||||
// QRegularExpression re("(\\[.*?\\]\\((.+?:\\/\\/.+?)\\))");
|
||||
regex = QRegularExpression(R"((\[.*?\]\((.+?)\)))");
|
||||
iterator = regex.globalMatch(text);
|
||||
static QRegularExpression regex2(R"((\[.*?\]\((.+?)\)))");
|
||||
iterator = regex2.globalMatch(text);
|
||||
while (iterator.hasNext()) {
|
||||
QRegularExpressionMatch match = iterator.next();
|
||||
QString linkText = match.captured(1);
|
||||
@ -1297,8 +1318,8 @@ QMap<QString, QString> QMarkdownTextEdit::parseMarkdownUrlsFromText(
|
||||
}
|
||||
|
||||
// match urls like this: http://mylink
|
||||
regex = QRegularExpression(R"(\b\w+?:\/\/[^\s]+[^\s>\)])");
|
||||
iterator = regex.globalMatch(text);
|
||||
static QRegularExpression regex3(R"(\b\w+?:\/\/[^\s]+[^\s>\)])");
|
||||
iterator = regex3.globalMatch(text);
|
||||
while (iterator.hasNext()) {
|
||||
QRegularExpressionMatch match = iterator.next();
|
||||
QString url = match.captured(0);
|
||||
@ -1306,8 +1327,8 @@ QMap<QString, QString> QMarkdownTextEdit::parseMarkdownUrlsFromText(
|
||||
}
|
||||
|
||||
// match urls like this: www.github.com
|
||||
regex = QRegularExpression(R"(\bwww\.[^\s]+\.[^\s]+\b)");
|
||||
iterator = regex.globalMatch(text);
|
||||
static QRegularExpression regex4(R"(\bwww\.[^\s]+\.[^\s]+\b)");
|
||||
iterator = regex4.globalMatch(text);
|
||||
while (iterator.hasNext()) {
|
||||
QRegularExpressionMatch match = iterator.next();
|
||||
QString url = match.captured(0);
|
||||
@ -1316,8 +1337,8 @@ QMap<QString, QString> QMarkdownTextEdit::parseMarkdownUrlsFromText(
|
||||
|
||||
// match reference urls like this: [this url][1] with this later:
|
||||
// [1]: http://domain
|
||||
regex = QRegularExpression(R"((\[.*?\]\[(.+?)\]))");
|
||||
iterator = regex.globalMatch(text);
|
||||
static QRegularExpression regex5(R"((\[.*?\]\[(.+?)\]))");
|
||||
iterator = regex5.globalMatch(text);
|
||||
while (iterator.hasNext()) {
|
||||
QRegularExpressionMatch match = iterator.next();
|
||||
QString linkText = match.captured(1);
|
||||
@ -1380,6 +1401,10 @@ QString QMarkdownTextEdit::getMarkdownUrlAtPosition(const QString &text,
|
||||
* @brief Duplicates the text in the text edit
|
||||
*/
|
||||
void QMarkdownTextEdit::duplicateText() {
|
||||
if (isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTextCursor cursor = this->textCursor();
|
||||
QString selectedText = cursor.selectedText();
|
||||
|
||||
@ -1422,8 +1447,7 @@ void QMarkdownTextEdit::setText(const QString &text) { setPlainText(text); }
|
||||
void QMarkdownTextEdit::setPlainText(const QString &text) {
|
||||
// clear the dirty blocks vector to increase performance and prevent
|
||||
// a possible crash in QSyntaxHighlighter::rehighlightBlock
|
||||
if (_highlighter)
|
||||
_highlighter->clearDirtyBlocks();
|
||||
if (_highlighter) _highlighter->clearDirtyBlocks();
|
||||
|
||||
QPlainTextEdit::setPlainText(text);
|
||||
adjustRightMargin();
|
||||
@ -1468,18 +1492,27 @@ bool QMarkdownTextEdit::handleReturnEntered() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This will be the main cursor to add or remove text
|
||||
QTextCursor cursor = this->textCursor();
|
||||
const int position = cursor.position();
|
||||
|
||||
// We need a 2nd cursor to get the text of the current block without moving
|
||||
// the main cursor that is used to remove the selected text
|
||||
QTextCursor cursor2 = this->textCursor();
|
||||
cursor2.select(QTextCursor::BlockUnderCursor);
|
||||
const QString currentLineText = cursor2.selectedText().trimmed();
|
||||
|
||||
const int position = cursor.position();
|
||||
const bool cursorAtBlockStart = cursor.atBlockStart();
|
||||
cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
|
||||
const QString currentLineText = cursor.selectedText();
|
||||
const QString currentLinePartialText = cursor.selectedText();
|
||||
|
||||
// if return is pressed and there is just an unordered list symbol then we
|
||||
// want to remove the list symbol Valid listCharacters: '+ ', '-' , '* ', '+
|
||||
// [ ] ', '+ [x] ', '- [ ] ', '- [-] ', '- [x] ', '* [ ] ', '* [x] '.
|
||||
QRegularExpression regex(R"(^(\s*)([+|\-|\*] \[(x|-| |)\]|[+\-\*])(\s+)$)");
|
||||
static QRegularExpression regex1(
|
||||
R"(^(\s*)([+|\-|\*] \[(x|-| |)\]|[+\-\*])(\s+)$)");
|
||||
QRegularExpressionMatchIterator iterator =
|
||||
regex.globalMatch(currentLineText);
|
||||
regex1.globalMatch(currentLinePartialText);
|
||||
if (iterator.hasNext()) {
|
||||
cursor.removeSelectedText();
|
||||
return true;
|
||||
@ -1487,8 +1520,8 @@ bool QMarkdownTextEdit::handleReturnEntered() {
|
||||
|
||||
// if return is pressed and there is just an ordered list symbol then we
|
||||
// want to remove the list symbol
|
||||
regex = QRegularExpression(R"(^(\s*)(\d+[\.|\)])(\s+)$)");
|
||||
iterator = regex.globalMatch(currentLineText);
|
||||
static QRegularExpression regex2(R"(^(\s*)(\d+[\.|\)])(\s+)$)");
|
||||
iterator = regex2.globalMatch(currentLinePartialText);
|
||||
if (iterator.hasNext()) {
|
||||
qDebug() << cursor.selectedText();
|
||||
cursor.removeSelectedText();
|
||||
@ -1499,13 +1532,11 @@ bool QMarkdownTextEdit::handleReturnEntered() {
|
||||
// We are in a list when we have '* ', '- ' or '+ ', possibly with preceding
|
||||
// whitespace. If e.g. user has entered '**text**' and pressed enter - we
|
||||
// don't want to do more list-stuff.
|
||||
QString currentLine = currentLineText.trimmed();
|
||||
QString currentLine = currentLinePartialText.trimmed();
|
||||
QChar char0;
|
||||
QChar char1;
|
||||
if (currentLine.length() >= 1)
|
||||
char0 = currentLine.at(0);
|
||||
if (currentLine.length() >= 2)
|
||||
char1 = currentLine.at(1);
|
||||
if (currentLine.length() >= 1) char0 = currentLine.at(0);
|
||||
if (currentLine.length() >= 2) char1 = currentLine.at(1);
|
||||
const bool inList =
|
||||
((char0 == QLatin1Char('*') || char0 == QLatin1Char('-') ||
|
||||
char0 == QLatin1Char('+')) &&
|
||||
@ -1516,21 +1547,21 @@ bool QMarkdownTextEdit::handleReturnEntered() {
|
||||
// whitespaces) add the whitespaces at the next line too
|
||||
// Valid listCharacters: '+ ', '-' , '* ', '+ [ ] ', '+ [x] ', '- [ ] ',
|
||||
// '- [x] ', '- [-] ', '* [ ] ', '* [x] '.
|
||||
regex =
|
||||
QRegularExpression(R"(^(\s*)([+|\-|\*] \[(x|-| |)\]|[+\-\*])(\s+))");
|
||||
iterator = regex.globalMatch(currentLineText);
|
||||
static QRegularExpression regex3(
|
||||
R"(^(\s*)([+|\-|\*] \[(x|-| |)\]|[+\-\*])(\s+))");
|
||||
iterator = regex3.globalMatch(currentLinePartialText);
|
||||
if (iterator.hasNext()) {
|
||||
const QRegularExpressionMatch match = iterator.next();
|
||||
const QString whitespaces = match.captured(1);
|
||||
QString listCharacter = match.captured(2);
|
||||
const QString whitespaceCharacter = match.captured(4);
|
||||
|
||||
static QRegularExpression regex4(R"(^([+|\-|\*]) \[(x| |\-|)\])");
|
||||
// start new checkbox list item with an unchecked checkbox
|
||||
iterator = QRegularExpression(R"(^([+|\-|\*]) \[(x| |)\])")
|
||||
.globalMatch(listCharacter);
|
||||
iterator = regex4.globalMatch(listCharacter);
|
||||
if (iterator.hasNext()) {
|
||||
const QRegularExpressionMatch match = iterator.next();
|
||||
const QString realListCharacter = match.captured(1);
|
||||
const QRegularExpressionMatch match1 = iterator.next();
|
||||
const QString realListCharacter = match1.captured(1);
|
||||
listCharacter = realListCharacter + QStringLiteral(" [ ]");
|
||||
}
|
||||
|
||||
@ -1545,8 +1576,8 @@ bool QMarkdownTextEdit::handleReturnEntered() {
|
||||
}
|
||||
|
||||
// check for ordered lists and increment the list number in the next line
|
||||
regex = QRegularExpression(R"(^(\s*)(\d+)([\.|\)])(\s+))");
|
||||
iterator = regex.globalMatch(currentLineText);
|
||||
static QRegularExpression regex5(R"(^(\s*)(\d+)([\.|\)])(\s+))");
|
||||
iterator = regex5.globalMatch(currentLinePartialText);
|
||||
if (iterator.hasNext()) {
|
||||
const QRegularExpressionMatch match = iterator.next();
|
||||
const QString whitespaces = match.captured(1);
|
||||
@ -1564,8 +1595,8 @@ bool QMarkdownTextEdit::handleReturnEntered() {
|
||||
}
|
||||
|
||||
// intent next line with same whitespaces as in current line
|
||||
regex = QRegularExpression(R"(^(\s+))");
|
||||
iterator = regex.globalMatch(currentLineText);
|
||||
static QRegularExpression regex6(R"(^(\s+))");
|
||||
iterator = regex6.globalMatch(currentLinePartialText);
|
||||
if (iterator.hasNext()) {
|
||||
const QRegularExpressionMatch match = iterator.next();
|
||||
const QString whitespaces = match.captured(1);
|
||||
@ -1578,6 +1609,39 @@ bool QMarkdownTextEdit::handleReturnEntered() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add new list item above current line if we are at the start the line of a
|
||||
// list item
|
||||
if (cursorAtBlockStart) {
|
||||
static QRegularExpression regex7(
|
||||
R"(^([+|\-|\*] \[(x|-| |)\]|[+\-\*])(\s+))");
|
||||
iterator = regex7.globalMatch(currentLineText);
|
||||
if (iterator.hasNext()) {
|
||||
const QRegularExpressionMatch match = iterator.next();
|
||||
QString listCharacter = match.captured(1);
|
||||
const QString whitespaceCharacter = match.captured(3);
|
||||
|
||||
static QRegularExpression regex8(R"(^([+|\-|\*]) \[(x| |\-|)\])");
|
||||
// start new checkbox list item with an unchecked checkbox
|
||||
iterator = regex8.globalMatch(listCharacter);
|
||||
if (iterator.hasNext()) {
|
||||
const QRegularExpressionMatch match1 = iterator.next();
|
||||
const QString realListCharacter = match1.captured(1);
|
||||
listCharacter = realListCharacter + QStringLiteral(" [ ]");
|
||||
}
|
||||
|
||||
cursor.setPosition(position);
|
||||
// Enter new list item above current line
|
||||
cursor.insertText(listCharacter + whitespaceCharacter + "\n");
|
||||
// Move the cursor at the end of the new list item
|
||||
cursor.movePosition(QTextCursor::Left);
|
||||
setTextCursor(cursor);
|
||||
|
||||
// scroll to the cursor if we are at the bottom of the document
|
||||
ensureCursorVisible();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1600,8 +1664,9 @@ bool QMarkdownTextEdit::handleTabEntered(bool reverse,
|
||||
// check if we want to indent or un-indent an ordered list
|
||||
// Valid listCharacters: '+ ', '-' , '* ', '+ [ ] ', '+ [x] ', '- [ ] ',
|
||||
// '- [x] ', '- [-] ', '* [ ] ', '* [x] '.
|
||||
QRegularExpression re(R"(^(\s*)([+|\-|\*] \[(x|-| )\]|[+\-\*])(\s+)$)");
|
||||
QRegularExpressionMatchIterator i = re.globalMatch(currentLineText);
|
||||
static QRegularExpression regex1(
|
||||
R"(^(\s*)([+|\-|\*] \[(x|-| )\]|[+\-\*])(\s+)$)");
|
||||
QRegularExpressionMatchIterator i = regex1.globalMatch(currentLineText);
|
||||
|
||||
if (i.hasNext()) {
|
||||
QRegularExpressionMatch match = i.next();
|
||||
@ -1627,8 +1692,8 @@ bool QMarkdownTextEdit::handleTabEntered(bool reverse,
|
||||
}
|
||||
|
||||
// check if we want to indent or un-indent an ordered list
|
||||
re = QRegularExpression(R"(^(\s*)(\d+)([\.|\)])(\s+)$)");
|
||||
i = re.globalMatch(currentLineText);
|
||||
static QRegularExpression regex2(R"(^(\s*)(\d+)([\.|\)])(\s+)$)");
|
||||
i = regex2.globalMatch(currentLineText);
|
||||
|
||||
if (i.hasNext()) {
|
||||
const QRegularExpressionMatch match = i.next();
|
||||
@ -1661,12 +1726,12 @@ void QMarkdownTextEdit::setAutoTextOptions(AutoTextOptions options) {
|
||||
_autoTextOptions = options;
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::updateLineNumberArea(const QRect rect, int dy)
|
||||
{
|
||||
void QMarkdownTextEdit::updateLineNumberArea(const QRect rect, int dy) {
|
||||
if (dy)
|
||||
_lineNumArea->scroll(0, dy);
|
||||
else
|
||||
_lineNumArea->update(0, rect.y(), _lineNumArea->sizeHint().width(), rect.height());
|
||||
_lineNumArea->update(0, rect.y(), _lineNumArea->sizeHint().width(),
|
||||
rect.height());
|
||||
|
||||
updateLineNumAreaGeometry();
|
||||
|
||||
@ -1675,18 +1740,27 @@ void QMarkdownTextEdit::updateLineNumberArea(const QRect rect, int dy)
|
||||
}
|
||||
}
|
||||
|
||||
void QMarkdownTextEdit::updateLineNumberAreaWidth(int)
|
||||
{
|
||||
void QMarkdownTextEdit::updateLineNumberAreaWidth(int) {
|
||||
QSignalBlocker blocker(this);
|
||||
const auto oldMargins = viewportMargins();
|
||||
const int width = _lineNumArea->isLineNumAreaEnabled() ?
|
||||
_lineNumArea->sizeHint().width() + _lineNumberLeftMarginOffset :
|
||||
oldMargins.left();
|
||||
const auto newMargins = QMargins{width, oldMargins.top(), oldMargins.right(), oldMargins.bottom()};
|
||||
const int width =
|
||||
_lineNumArea->isLineNumAreaEnabled()
|
||||
? _lineNumArea->sizeHint().width() + _lineNumberLeftMarginOffset
|
||||
: oldMargins.left();
|
||||
const auto newMargins = QMargins{width, oldMargins.top(),
|
||||
oldMargins.right(), oldMargins.bottom()};
|
||||
|
||||
if (newMargins != oldMargins) {
|
||||
setViewportMargins(newMargins);
|
||||
}
|
||||
|
||||
// Grow lineNumArea font-size with the font size of the editor
|
||||
const int pointSize = this->font().pointSize();
|
||||
if (pointSize > 0) {
|
||||
QFont font = _lineNumArea->font();
|
||||
font.setPointSize(pointSize);
|
||||
_lineNumArea->setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1820,12 +1894,14 @@ void QMarkdownTextEdit::paintEvent(QPaintEvent *e) {
|
||||
// Current line highlight
|
||||
QTextCursor cursor = textCursor();
|
||||
if (highlightCurrentLine() && cursor.block() == block) {
|
||||
QTextLine line = block.layout()->lineForTextPosition(cursor.positionInBlock());
|
||||
QTextLine line =
|
||||
block.layout()->lineForTextPosition(cursor.positionInBlock());
|
||||
QRectF lineRect = line.rect();
|
||||
lineRect.moveTop(lineRect.top() + r.top());
|
||||
lineRect.setLeft(0.);
|
||||
lineRect.setRight(viewportRect.width());
|
||||
painter.fillRect(lineRect.toAlignedRect(), currentLineHighlightColor());
|
||||
painter.fillRect(lineRect.toAlignedRect(),
|
||||
currentLineHighlightColor());
|
||||
}
|
||||
|
||||
block = block.next();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@ -125,14 +125,12 @@ class QMarkdownTextEdit : public QPlainTextEdit {
|
||||
bool quotationMarkCheck(const QChar quotationCharacter);
|
||||
void focusOutEvent(QFocusEvent *event) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
bool handleCharRemoval(MarkdownHighlighter::RangeType type, int block, int position);
|
||||
bool handleCharRemoval(MarkdownHighlighter::RangeType type, int block,
|
||||
int position);
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void setLineNumberLeftMarginOffset(int offset);
|
||||
int _lineNumberLeftMarginOffset = 0;
|
||||
LineNumArea *lineNumberArea()
|
||||
{
|
||||
return _lineNumArea;
|
||||
}
|
||||
LineNumArea *lineNumberArea() { return _lineNumArea; }
|
||||
void updateLineNumAreaGeometry();
|
||||
void updateLineNumberArea(const QRect rect, int dy);
|
||||
Q_SLOT void updateLineNumberAreaWidth(int);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@ -86,10 +86,10 @@ void loadJSData(QMultiHash<char, QLatin1String> &types,
|
||||
/* JS Data *********************************************/
|
||||
/**********************************************************/
|
||||
void loadNixData(QMultiHash<char, QLatin1String> &types,
|
||||
QMultiHash<char, QLatin1String> &keywords,
|
||||
QMultiHash<char, QLatin1String> &builtin,
|
||||
QMultiHash<char, QLatin1String> &literals,
|
||||
QMultiHash<char, QLatin1String> &other);
|
||||
QMultiHash<char, QLatin1String> &keywords,
|
||||
QMultiHash<char, QLatin1String> &builtin,
|
||||
QMultiHash<char, QLatin1String> &literals,
|
||||
QMultiHash<char, QLatin1String> &other);
|
||||
|
||||
/**********************************************************/
|
||||
/* PHP Data *********************************************/
|
||||
@ -172,6 +172,15 @@ void loadSQLData(QMultiHash<char, QLatin1String> &types,
|
||||
QMultiHash<char, QLatin1String> &literals,
|
||||
QMultiHash<char, QLatin1String> &other);
|
||||
|
||||
/********************************************************/
|
||||
/*** System Verilog DATA *************************/
|
||||
/********************************************************/
|
||||
void loadSystemVerilogData(QMultiHash<char, QLatin1String> &types,
|
||||
QMultiHash<char, QLatin1String> &keywords,
|
||||
QMultiHash<char, QLatin1String> &builtin,
|
||||
QMultiHash<char, QLatin1String> &literals,
|
||||
QMultiHash<char, QLatin1String> &other);
|
||||
|
||||
/********************************************************/
|
||||
/*** JSON DATA ***********************************/
|
||||
/********************************************************/
|
||||
@ -242,4 +251,20 @@ void loadForthData(QMultiHash<char, QLatin1String> &types,
|
||||
QMultiHash<char, QLatin1String> &builtin,
|
||||
QMultiHash<char, QLatin1String> &literals,
|
||||
QMultiHash<char, QLatin1String> &other);
|
||||
/********************************************************/
|
||||
/*** GDScript DATA **************************************/
|
||||
/********************************************************/
|
||||
void loadGDScriptData(QMultiHash<char, QLatin1String> &types,
|
||||
QMultiHash<char, QLatin1String> &keywords,
|
||||
QMultiHash<char, QLatin1String> &builtin,
|
||||
QMultiHash<char, QLatin1String> &literals,
|
||||
QMultiHash<char, QLatin1String> &other);
|
||||
/********************************************************/
|
||||
/*** TOML DATA **************************************/
|
||||
/********************************************************/
|
||||
void loadTOMLData(QMultiHash<char, QLatin1String> &types,
|
||||
QMultiHash<char, QLatin1String> &keywords,
|
||||
QMultiHash<char, QLatin1String> &builtin,
|
||||
QMultiHash<char, QLatin1String> &literals,
|
||||
QMultiHash<char, QLatin1String> &other);
|
||||
#endif
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
@ -59,8 +59,8 @@ QPlainTextEditSearchWidget::QPlainTextEditSearchWidget(QPlainTextEdit *parent)
|
||||
connect(ui->replaceAllButton, &QPushButton::clicked, this,
|
||||
&QPlainTextEditSearchWidget::doReplaceAll);
|
||||
|
||||
connect(&_debounceTimer, &QTimer::timeout,
|
||||
this, &QPlainTextEditSearchWidget::performSearch);
|
||||
connect(&_debounceTimer, &QTimer::timeout, this,
|
||||
&QPlainTextEditSearchWidget::performSearch);
|
||||
|
||||
installEventFilter(this);
|
||||
ui->searchLineEdit->installEventFilter(this);
|
||||
@ -127,15 +127,16 @@ bool QPlainTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) {
|
||||
} else if ((!_debounceTimer.isActive() &&
|
||||
keyEvent->modifiers().testFlag(Qt::ShiftModifier) &&
|
||||
(keyEvent->key() == Qt::Key_Return)) ||
|
||||
(keyEvent->key() == Qt::Key_Up)) {
|
||||
(keyEvent->key() == Qt::Key_Up)) {
|
||||
doSearchUp();
|
||||
return true;
|
||||
} else if (!_debounceTimer.isActive() &&
|
||||
((keyEvent->key() == Qt::Key_Return) ||
|
||||
(keyEvent->key() == Qt::Key_Down))) {
|
||||
((keyEvent->key() == Qt::Key_Return) ||
|
||||
(keyEvent->key() == Qt::Key_Down))) {
|
||||
doSearchDown();
|
||||
return true;
|
||||
} else if (!_debounceTimer.isActive() && keyEvent->key() == Qt::Key_F3) {
|
||||
} else if (!_debounceTimer.isActive() &&
|
||||
keyEvent->key() == Qt::Key_F3) {
|
||||
doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier));
|
||||
return true;
|
||||
}
|
||||
@ -165,8 +166,7 @@ void QPlainTextEditSearchWidget::searchLineEditTextChanged(
|
||||
}
|
||||
}
|
||||
|
||||
void QPlainTextEditSearchWidget::performSearch()
|
||||
{
|
||||
void QPlainTextEditSearchWidget::performSearch() {
|
||||
doSearchCount();
|
||||
updateSearchExtraSelections();
|
||||
doSearchDown();
|
||||
@ -190,7 +190,8 @@ void QPlainTextEditSearchWidget::updateSearchExtraSelections() {
|
||||
while (doSearch(true, false, false)) {
|
||||
findCounter++;
|
||||
|
||||
// prevent infinite loops from regular expression searches like "$", "^" or "\b"
|
||||
// prevent infinite loops from regular expression searches like "$", "^"
|
||||
// or "\b"
|
||||
if (searchMode == RegularExpressionMode && findCounter >= 10000) {
|
||||
break;
|
||||
}
|
||||
@ -210,8 +211,7 @@ void QPlainTextEditSearchWidget::setSearchExtraSelections() const {
|
||||
this->_textEdit->setExtraSelections(this->_searchExtraSelections);
|
||||
}
|
||||
|
||||
void QPlainTextEditSearchWidget::stopDebounce()
|
||||
{
|
||||
void QPlainTextEditSearchWidget::stopDebounce() {
|
||||
_debounceTimer.stop();
|
||||
ui->searchDownButton->setEnabled(true);
|
||||
ui->searchUpButton->setEnabled(true);
|
||||
@ -378,11 +378,11 @@ bool QPlainTextEditSearchWidget::doSearch(bool searchDown,
|
||||
}
|
||||
|
||||
// add a background color according if we found the text or not
|
||||
const QString bgColorCode =
|
||||
_darkMode
|
||||
? (found ? QStringLiteral("#135a13")
|
||||
: QStringLiteral("#8d2b36"))
|
||||
: found ? QStringLiteral("#D5FAE2") : QStringLiteral("#FAE9EB");
|
||||
const QString bgColorCode = _darkMode
|
||||
? (found ? QStringLiteral("#135a13")
|
||||
: QStringLiteral("#8d2b36"))
|
||||
: found ? QStringLiteral("#D5FAE2")
|
||||
: QStringLiteral("#FAE9EB");
|
||||
const QString fgColorCode =
|
||||
_darkMode ? QStringLiteral("#cccccc") : QStringLiteral("#404040");
|
||||
|
||||
@ -418,8 +418,10 @@ void QPlainTextEditSearchWidget::doSearchCount() {
|
||||
_searchResultCount++;
|
||||
}
|
||||
|
||||
// prevent infinite loops from regular expression searches like "$", "^" or "\b"
|
||||
if (searchMode == RegularExpressionMode && _searchResultCount >= 10000) {
|
||||
// prevent infinite loops from regular expression searches like "$", "^"
|
||||
// or "\b"
|
||||
if (searchMode == RegularExpressionMode &&
|
||||
_searchResultCount >= 10000) {
|
||||
break;
|
||||
}
|
||||
} while (found);
|
||||
@ -439,8 +441,7 @@ void QPlainTextEditSearchWidget::setSearchMode(SearchMode searchMode) {
|
||||
ui->modeComboBox->setCurrentIndex(searchMode);
|
||||
}
|
||||
|
||||
void QPlainTextEditSearchWidget::setDebounceDelay(uint debounceDelay)
|
||||
{
|
||||
void QPlainTextEditSearchWidget::setDebounceDelay(uint debounceDelay) {
|
||||
_debounceTimer.setInterval(static_cast<int>(debounceDelay));
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2014-2023 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
* Copyright (c) 2014-2025 Patrizio Bekerle -- <patrizio@bekerle.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -10,8 +10,8 @@
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
||||
@ -12,16 +12,16 @@ FMT=""
|
||||
# that's present, otherwise we work backwards from highest version to lowest
|
||||
# version.
|
||||
for clangfmt in clang-format{,-{4,3}.{9,8,7,6,5,4,3,2,1,0}}; do
|
||||
if which "$clangfmt" &>/dev/null; then
|
||||
FMT="$clangfmt"
|
||||
break
|
||||
fi
|
||||
if which "$clangfmt" &>/dev/null; then
|
||||
FMT="$clangfmt"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if we found a working clang-format
|
||||
if [ -z "$FMT" ]; then
|
||||
echo "failed to find clang-format"
|
||||
exit 1
|
||||
echo "failed to find clang-format"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$FMT -i *.cpp
|
||||
|
||||
BIN
client/qmarkdowntextedit/trans/qmarkdowntextedit_es.qm
Normal file
BIN
client/qmarkdowntextedit/trans/qmarkdowntextedit_es.qm
Normal file
Binary file not shown.
BIN
client/qmarkdowntextedit/trans/qmarkdowntextedit_ur.qm
Normal file
BIN
client/qmarkdowntextedit/trans/qmarkdowntextedit_ur.qm
Normal file
Binary file not shown.
BIN
client/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.qm
Normal file
BIN
client/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.qm
Normal file
Binary file not shown.
39
client/qmarkdowntextedit/treefmt.toml
Normal file
39
client/qmarkdowntextedit/treefmt.toml
Normal file
@ -0,0 +1,39 @@
|
||||
# https://github.com/numtide/treefmt
|
||||
# https://github.com/numtide/treefmt-nix
|
||||
|
||||
on-unmatched = "info"
|
||||
|
||||
[formatter.clang-format]
|
||||
command = "clang-format"
|
||||
|
||||
# Only target the exact directories we want
|
||||
includes = [
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
]
|
||||
|
||||
[formatter.prettier]
|
||||
command = "prettier"
|
||||
options = ["--write"]
|
||||
includes = ["*.md", "*.yaml", "*.yml"]
|
||||
|
||||
[formatter.shfmt]
|
||||
command = "shfmt"
|
||||
excludes = []
|
||||
includes = ["*.sh", "*.bash", "*.envrc", "*.envrc.*"]
|
||||
options = ["-s", "-w", "-i", "2"]
|
||||
|
||||
[formatter.just]
|
||||
command = "just"
|
||||
includes = ["*.just"]
|
||||
|
||||
[formatter.taplo]
|
||||
command = "taplo"
|
||||
includes = ["*.toml"]
|
||||
options = ["format"]
|
||||
|
||||
[formatter.nixfmt-rfc-style]
|
||||
command = "nixfmt"
|
||||
excludes = []
|
||||
includes = ["*.nix"]
|
||||
options = []
|
||||
78
client/qtkeychain/.gitignore
vendored
78
client/qtkeychain/.gitignore
vendored
@ -1,76 +1,3 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
#CMake files
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
@ -110,6 +37,7 @@ testclient
|
||||
install_manifest.txt
|
||||
*.manifest
|
||||
*.lib
|
||||
*.exe
|
||||
|
||||
#Mac build files
|
||||
qtkeychain.xcodeproj
|
||||
@ -117,6 +45,6 @@ qtkeychain.build
|
||||
|
||||
#Temporary files
|
||||
*.sw?
|
||||
*~
|
||||
|
||||
|
||||
/build-*/
|
||||
/compile_commands.json
|
||||
|
||||
@ -1,44 +1,31 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required (VERSION 2.8.11)
|
||||
project (qtkeychain)
|
||||
|
||||
set(QTKEYCHAIN_VERSION 0.14.2)
|
||||
set(QTKEYCHAIN_SOVERSION 1)
|
||||
|
||||
project(qtkeychain VERSION ${QTKEYCHAIN_VERSION} LANGUAGES CXX)
|
||||
|
||||
# Enable C++11
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include(FindPkgConfig)
|
||||
include (FindPkgConfig)
|
||||
|
||||
###
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules")
|
||||
include(GNUInstallDirs)
|
||||
include(GenerateExportHeader)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(ECMSetupVersion)
|
||||
include(ECMGeneratePriFile)
|
||||
include(CMakeDependentOption)
|
||||
set (QTKEYCHAIN_VERSION 0.9.90)
|
||||
set (QTKEYCHAIN_SOVERSION 1)
|
||||
|
||||
option(BUILD_WITH_QT6 "Build qtkeychain with Qt 6" OFF)
|
||||
option(BUILD_TEST_APPLICATION "Build test application" OFF)
|
||||
option(BUILD_TRANSLATIONS "Build translations" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build dynamic library" OFF)
|
||||
if(QTKEYCHAIN_STATIC)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
message(WARNING "QTKEYCHAIN_STATIC is deprecated. Use BUILD_SHARED_LIBS=OFF instead.")
|
||||
endif()
|
||||
CMAKE_DEPENDENT_OPTION(BUILD_TRANSLATIONS_AS_RESOURCES "Bundle translations with the library" OFF
|
||||
"BUILD_TRANSLATIONS" OFF)
|
||||
###
|
||||
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules")
|
||||
include (GNUInstallDirs)
|
||||
include (GenerateExportHeader)
|
||||
include (ECMPackageConfigHelpers)
|
||||
include (ECMSetupVersion)
|
||||
include (ECMGeneratePriFile)
|
||||
|
||||
option (BUILD_WITH_QT4 "Build qtkeychain with Qt4 no matter if Qt5 was found" OFF)
|
||||
option (BUILD_TEST_APPLICATION "Build test application" OFF)
|
||||
option (BUILD_TRANSLATIONS "Build translations" ON)
|
||||
option (QTKEYCHAIN_STATIC "Build static library" ON)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Android)
|
||||
set(ANDROID 1)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Haiku)
|
||||
set(HAIKU 1)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
option(USE_CREDENTIAL_STORE "Build with windows CredentialStore support" ON)
|
||||
|
||||
@ -47,78 +34,79 @@ if (WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( NOT BUILD_WITH_QT6 )
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
if( NOT BUILD_WITH_QT4 )
|
||||
# try Qt5 first, and prefer that if found
|
||||
find_package(Qt5Core QUIET)
|
||||
endif()
|
||||
|
||||
if (Qt5Core_FOUND AND NOT BUILD_WITH_QT6)
|
||||
set(QTKEYCHAIN_VERSION_INFIX 5)
|
||||
if (Qt5Core_FOUND AND NOT BUILD_WITH_QT4)
|
||||
set(QTKEYCHAIN_VERSION_INFIX 5)
|
||||
|
||||
if(ANDROID)
|
||||
if(Qt5Core_VERSION VERSION_LESS 5.7)
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED Private)
|
||||
include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS})
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
find_package(Qt5DBus REQUIRED)
|
||||
include_directories(${Qt5DBus_INCLUDE_DIRS})
|
||||
set(QTDBUS_LIBRARIES ${Qt5DBus_LIBRARIES})
|
||||
macro(qt_add_dbus_interface)
|
||||
qt5_add_dbus_interface(${ARGN})
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
find_package(Qt5 COMPONENTS AndroidExtras REQUIRED)
|
||||
include_directories(${Qt5AndroidExtras_INCLUDE_DIRS})
|
||||
set(QTANDROIDEXTRAS_LIBRARIES ${Qt5AndroidExtras_LIBRARIES})
|
||||
endif()
|
||||
if(BUILD_TRANSLATIONS)
|
||||
find_package(Qt5LinguistTools REQUIRED)
|
||||
macro(qt_add_translation)
|
||||
qt5_add_translation(${ARGN})
|
||||
endmacro(qt_add_translation)
|
||||
macro(qt_create_translation)
|
||||
qt5_create_translation(${ARGN})
|
||||
endmacro(qt_create_translation)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
|
||||
find_package(Qt5 COMPONENTS DBus REQUIRED)
|
||||
include_directories(${Qt5DBus_INCLUDE_DIRS})
|
||||
set(QTDBUS_LIBRARIES ${Qt5DBus_LIBRARIES})
|
||||
macro(qt_add_dbus_interface)
|
||||
qt5_add_dbus_interface(${ARGN})
|
||||
macro(qt_wrap_cpp)
|
||||
qt5_wrap_cpp(${ARGN})
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
if(BUILD_TRANSLATIONS)
|
||||
find_package(Qt5 COMPONENTS LinguistTools REQUIRED)
|
||||
macro(qt_add_translation)
|
||||
qt5_add_translation(${ARGN})
|
||||
endmacro(qt_add_translation)
|
||||
macro(qt_create_translation)
|
||||
qt5_create_translation(${ARGN})
|
||||
endmacro(qt_create_translation)
|
||||
endif()
|
||||
set(QTCORE_LIBRARIES ${Qt5Core_LIBRARIES})
|
||||
include_directories (${Qt5Core_INCLUDE_DIRS})
|
||||
|
||||
macro(qt_wrap_cpp)
|
||||
qt5_wrap_cpp(${ARGN})
|
||||
endmacro()
|
||||
|
||||
set(QTCORE_LIBRARIES ${Qt5Core_LIBRARIES})
|
||||
include_directories(${Qt5Core_INCLUDE_DIRS})
|
||||
if (NOT Qt5Core_VERSION VERSION_LESS "5.7.0")
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
if ((NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.1.0"))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
|
||||
message(FATAL_ERROR "Can't build QtKeychain using g++-${CMAKE_CXX_COMPILER_VERSION} and Qt ${Qt5Core_VERSION}: compiler supporting C++11 is required")
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if (NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.3)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
message(FATAL_ERROR "Can't build QtKeychain using clang++-${CMAKE_CXX_COMPILER_VERSION} and Qt ${Qt5Core_VERSION}: compiler supporting C++11 is required")
|
||||
endif()
|
||||
elseif ((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND (MSVC_VERSION LESS 1700))
|
||||
message(FATAL_ERROR "Can't build QtKeychain using VC++-${MSVC_VERSION} and Qt ${Qt5Core_VERSION}: compiler supporting C++11 is required")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
find_package(Qt6 COMPONENTS Core REQUIRED)
|
||||
set(QTKEYCHAIN_VERSION_INFIX 6)
|
||||
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
|
||||
find_package(Qt6 COMPONENTS DBus REQUIRED)
|
||||
include_directories(${Qt6DBus_INCLUDE_DIRS})
|
||||
set(QTDBUS_LIBRARIES ${Qt6DBus_LIBRARIES})
|
||||
macro(qt_add_dbus_interface)
|
||||
qt6_add_dbus_interface(${ARGN})
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
if(BUILD_TRANSLATIONS)
|
||||
find_package(Qt6 COMPONENTS LinguistTools REQUIRED)
|
||||
set(QTKEYCHAIN_VERSION_INFIX "")
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Qt4 COMPONENTS QtCore QtDBus REQUIRED)
|
||||
set(QTDBUS_LIBRARIES ${QT_QTDBUS_LIBRARY})
|
||||
macro(qt_add_dbus_interface)
|
||||
qt4_add_dbus_interface(${ARGN})
|
||||
endmacro()
|
||||
else()
|
||||
find_package(Qt4 COMPONENTS QtCore REQUIRED)
|
||||
endif()
|
||||
include_directories(${QT_INCLUDES})
|
||||
set(QTCORE_LIBRARIES ${QT_QTCORE_LIBRARY})
|
||||
macro(qt_add_translation)
|
||||
qt6_add_translation(${ARGN})
|
||||
qt4_add_translation(${ARGN})
|
||||
endmacro(qt_add_translation)
|
||||
macro(qt_create_translation)
|
||||
qt6_create_translation(${ARGN})
|
||||
qt4_create_translation(${ARGN})
|
||||
endmacro(qt_create_translation)
|
||||
endif()
|
||||
|
||||
macro(qt_wrap_cpp)
|
||||
qt6_wrap_cpp(${ARGN})
|
||||
endmacro()
|
||||
|
||||
set(QTCORE_LIBRARIES ${Qt6Core_LIBRARIES})
|
||||
macro(qt_wrap_cpp)
|
||||
qt4_wrap_cpp(${ARGN})
|
||||
endmacro()
|
||||
endif()
|
||||
|
||||
|
||||
@ -129,20 +117,9 @@ set(qtkeychain_SOURCES
|
||||
keychain.cpp
|
||||
qkeychain_export.h
|
||||
keychain.h
|
||||
)
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
# CMake < 3.15 sneaks in /W# flags for us, so we need a replacement,
|
||||
# or we'll get a warning (cf. CMP0092)
|
||||
if (CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else()
|
||||
# MSVC's STL / Qt headers are not MSVC -Wall clean, so don't enable it there
|
||||
add_definitions( -Wall -Werror=return-type )
|
||||
endif()
|
||||
add_definitions( -Wall )
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND qtkeychain_SOURCES keychain_win.cpp)
|
||||
@ -157,139 +134,105 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND qtkeychain_SOURCES keychain_apple.mm)
|
||||
list(APPEND qtkeychain_LIBRARIES "-framework Foundation" "-framework Security")
|
||||
if(IOS)
|
||||
list(APPEND qtkeychain_SOURCES keychain_ios.cpp)
|
||||
else()
|
||||
list(APPEND qtkeychain_SOURCES keychain_mac.cpp)
|
||||
endif()
|
||||
|
||||
find_library(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED)
|
||||
list(APPEND qtkeychain_LIBRARIES ${COREFOUNDATION_LIBRARY})
|
||||
|
||||
find_library(SECURITY_LIBRARY Security REQUIRED)
|
||||
list(APPEND qtkeychain_LIBRARIES ${SECURITY_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(HAIKU)
|
||||
list(APPEND qtkeychain_SOURCES keychain_haiku.cpp)
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
option(LIBSECRET_SUPPORT "Build with libsecret support" ON)
|
||||
|
||||
find_library(BE_LIBRARY be REQUIRED)
|
||||
list(APPEND qtkeychain_LIBRARIES ${BE_LIBRARY})
|
||||
endif()
|
||||
if(LIBSECRET_SUPPORT)
|
||||
pkg_check_modules(LIBSECRET libsecret-1)
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
|
||||
option(LIBSECRET_SUPPORT "Build with libsecret support" OFF)
|
||||
if (LIBSECRET_FOUND)
|
||||
add_definitions(-DHAVE_LIBSECRET=1)
|
||||
endif()
|
||||
INCLUDE_DIRECTORIES(${LIBSECRET_INCLUDE_DIRS})
|
||||
list(APPEND qtkeychain_LIBRARIES ${LIBSECRET_LIBRARIES})
|
||||
endif()
|
||||
|
||||
#if(LIBSECRET_SUPPORT)
|
||||
# pkg_check_modules(LIBSECRET REQUIRED libsecret-1)
|
||||
# add_definitions(-DHAVE_LIBSECRET=1)
|
||||
# INCLUDE_DIRECTORIES(${LIBSECRET_INCLUDE_DIRS})
|
||||
# LINK_DIRECTORIES(${LIBSECRET_LIBRARY_DIRS})
|
||||
# list(APPEND qtkeychain_LIBRARIES_PRIVATE ${LIBSECRET_LIBRARIES})
|
||||
#endif()
|
||||
|
||||
add_definitions(-DKEYCHAIN_DBUS=1)
|
||||
list(APPEND qtkeychain_SOURCES keychain_unix.cpp gnomekeyring.cpp libsecret.cpp plaintextstore.cpp)
|
||||
qt_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
|
||||
list(APPEND qtkeychain_LIBRARIES ${QTDBUS_LIBRARIES} )
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
list(APPEND qtkeychain_SOURCES keychain_android.cpp androidkeystore.cpp plaintextstore.cpp)
|
||||
list(APPEND qtkeychain_LIBRARIES_PRIVATE ${QTANDROIDEXTRAS_LIBRARIES} )
|
||||
endif()
|
||||
|
||||
QT_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h gnomekeyring_p.h)
|
||||
|
||||
set(qtkeychain_TR_FILES
|
||||
translations/qtkeychain_de.ts
|
||||
translations/qtkeychain_fr.ts
|
||||
translations/qtkeychain_ro.ts
|
||||
translations/qtkeychain_ru.ts
|
||||
translations/qtkeychain_zh.ts
|
||||
)
|
||||
|
||||
set(QTKEYCHAIN_TARGET_NAME qt${QTKEYCHAIN_VERSION_INFIX}keychain)
|
||||
add_library(${QTKEYCHAIN_TARGET_NAME} ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
|
||||
if(WIN32)
|
||||
set_target_properties( ${QTKEYCHAIN_TARGET_NAME} PROPERTIES DEBUG_POSTFIX "d" )
|
||||
endif()
|
||||
translations/qtkeychain_de.ts
|
||||
translations/qtkeychain_ro.ts
|
||||
)
|
||||
|
||||
file(GLOB qtkeychain_TR_SOURCES *.cpp *.h *.ui)
|
||||
if ( BUILD_TRANSLATIONS )
|
||||
qt_create_translation(qtkeychain_MESSAGES ${qtkeychain_TR_SOURCES} ${qtkeychain_TR_FILES})
|
||||
qt_add_translation(qtkeychain_QM_FILES ${qtkeychain_TR_FILES})
|
||||
add_custom_target(messages DEPENDS ${qtkeychain_MESSAGES})
|
||||
add_custom_target(translations DEPENDS ${qtkeychain_QM_FILES} messages)
|
||||
# https://github.com/frankosterfeld/qtkeychain/issues/185
|
||||
add_dependencies(${QTKEYCHAIN_TARGET_NAME} translations)
|
||||
add_custom_target(translations DEPENDS ${qtkeychain_QM_FILES})
|
||||
|
||||
if (BUILD_TRANSLATIONS_AS_RESOURCES)
|
||||
set(QM_FILE_LIST "")
|
||||
foreach(FILE ${qtkeychain_QM_FILES})
|
||||
list(APPEND QM_FILE_LIST "<file>${FILE}</file>")
|
||||
endforeach()
|
||||
string(REPLACE ";" "" QM_FILE_LIST ${QM_FILE_LIST})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/translations/translations.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
|
||||
target_sources(${QTKEYCHAIN_TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
|
||||
else()
|
||||
if(QTKEYCHAIN_VERSION_INFIX EQUAL 5 AND QT_TRANSLATIONS_DIR AND NOT QTKEYCHAIN_TRANSLATIONS_DIR)
|
||||
# Back compatibility with pre-0.11 versions
|
||||
message (WARNING "QT_TRANSLATIONS_DIR is deprecated, use QTKEYCHAIN_TRANSLATIONS_DIR instead")
|
||||
set(QTKEYCHAIN_TRANSLATIONS_DIR ${QT_TRANSLATIONS_DIR}
|
||||
CACHE PATH "The location of the QtKeychain translations" FORCE)
|
||||
else()
|
||||
set(QTKEYCHAIN_TRANSLATIONS_DIR
|
||||
${CMAKE_INSTALL_DATADIR}/qt${QTKEYCHAIN_VERSION_INFIX}keychain/translations
|
||||
CACHE PATH "The location of the QtKeychain translations" )
|
||||
endif()
|
||||
|
||||
install(FILES ${qtkeychain_QM_FILES} DESTINATION ${QTKEYCHAIN_TRANSLATIONS_DIR})
|
||||
if(NOT QT_TRANSLATIONS_DIR)
|
||||
# If this directory is missing, we are in a Qt5 environment.
|
||||
# Extract the qmake executable location
|
||||
get_target_property(QT5_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
|
||||
# Ask Qt5 where to put the translations
|
||||
execute_process( COMMAND ${QT5_QMAKE_EXECUTABLE} -query QT_INSTALL_TRANSLATIONS
|
||||
OUTPUT_VARIABLE qt_translations_dir OUTPUT_STRIP_TRAILING_WHITESPACE )
|
||||
# make sure we have / and not \ as qmake gives on windows
|
||||
file( TO_CMAKE_PATH "${qt_translations_dir}" qt_translations_dir)
|
||||
set( QT_TRANSLATIONS_DIR ${qt_translations_dir} CACHE PATH
|
||||
"The location of the Qt translations" FORCE)
|
||||
endif()
|
||||
|
||||
install(FILES ${qtkeychain_QM_FILES}
|
||||
DESTINATION ${QT_TRANSLATIONS_DIR})
|
||||
endif( BUILD_TRANSLATIONS )
|
||||
|
||||
target_link_libraries(${QTKEYCHAIN_TARGET_NAME} PUBLIC ${qtkeychain_LIBRARIES} PRIVATE ${qtkeychain_LIBRARIES_PRIVATE})
|
||||
if(NOT INTERFACE_INCLUDE_SUFFIX)
|
||||
set(INTERFACE_INCLUDE_SUFFIX include)
|
||||
set(QTKEYCHAIN_TARGET_NAME qtkeychain)
|
||||
if(NOT QTKEYCHAIN_STATIC)
|
||||
add_library(${QTKEYCHAIN_TARGET_NAME} SHARED ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
|
||||
else()
|
||||
add_library(${QTKEYCHAIN_TARGET_NAME} STATIC ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
|
||||
endif()
|
||||
target_include_directories(${QTKEYCHAIN_TARGET_NAME} PUBLIC $<INSTALL_INTERFACE:${INTERFACE_INCLUDE_SUFFIX}/>)
|
||||
|
||||
target_link_libraries(${QTKEYCHAIN_TARGET_NAME} PUBLIC ${qtkeychain_LIBRARIES})
|
||||
target_include_directories(${QTKEYCHAIN_TARGET_NAME} PUBLIC $<INSTALL_INTERFACE:include/>)
|
||||
|
||||
generate_export_header(${QTKEYCHAIN_TARGET_NAME}
|
||||
EXPORT_FILE_NAME qkeychain_export.h
|
||||
EXPORT_MACRO_NAME QKEYCHAIN_EXPORT
|
||||
)
|
||||
EXPORT_FILE_NAME qkeychain_export.h
|
||||
EXPORT_MACRO_NAME QKEYCHAIN_EXPORT
|
||||
)
|
||||
|
||||
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES
|
||||
VERSION ${QTKEYCHAIN_VERSION}
|
||||
SOVERSION ${QTKEYCHAIN_SOVERSION}
|
||||
MACOSX_RPATH 1
|
||||
INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
|
||||
INSTALL_RPATH_USE_LINK_PATH TRUE
|
||||
)
|
||||
|
||||
if (NOT APPLE)
|
||||
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES
|
||||
INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
|
||||
)
|
||||
endif()
|
||||
)
|
||||
|
||||
install(FILES keychain.h ${CMAKE_CURRENT_BINARY_DIR}/qkeychain_export.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qt${QTKEYCHAIN_VERSION_INFIX}keychain/
|
||||
)
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qt${QTKEYCHAIN_VERSION_INFIX}keychain/
|
||||
)
|
||||
|
||||
install(TARGETS ${QTKEYCHAIN_TARGET_NAME}
|
||||
EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
if(BUILD_TEST_APPLICATION)
|
||||
set( testclient_LIBRARIES ${QTKEYCHAIN_TARGET_NAME} )
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND testclient_LIBRARIES "-framework Cocoa")
|
||||
|
||||
if (BUILD_WITH_QT6)
|
||||
find_package(Qt6 COMPONENTS Gui REQUIRED)
|
||||
list(APPEND testclient_LIBRARIES Qt6::Gui)
|
||||
else()
|
||||
find_package(Qt5 COMPONENTS Gui REQUIRED)
|
||||
list(APPEND testclient_LIBRARIES Qt5::Gui)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
add_executable( testclient testclient.cpp )
|
||||
target_link_libraries( testclient ${testclient_LIBRARIES})
|
||||
target_link_libraries( testclient ${QTKEYCHAIN_TARGET_NAME})
|
||||
endif()
|
||||
|
||||
|
||||
@ -297,32 +240,32 @@ endif()
|
||||
### CMake config file
|
||||
###
|
||||
|
||||
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/QtKeychainConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake"
|
||||
INSTALL_DESTINATION Qt${QTKEYCHAIN_VERSION_INFIX}Keychain)
|
||||
ecm_configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/QtKeychainConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake"
|
||||
INSTALL_DESTINATION Qt${QTKEYCHAIN_VERSION_INFIX}Keychain)
|
||||
|
||||
ecm_setup_version("${QTKEYCHAIN_VERSION}" VARIABLE_PREFIX SNORE
|
||||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake"
|
||||
SOVERSION ${QTKEYCHAIN_VERSION})
|
||||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake"
|
||||
SOVERSION ${QTKEYCHAIN_VERSION})
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
set(PRI_EXTRA_DEPS "dbus")
|
||||
endif()
|
||||
ecm_generate_pri_file(BASE_NAME Qt${QTKEYCHAIN_VERSION_INFIX}Keychain
|
||||
LIB_NAME ${QTKEYCHAIN_TARGET_NAME}
|
||||
DEPS "core ${PRI_EXTRA_DEPS}"
|
||||
INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
FILENAME_VAR pri_filename)
|
||||
LIB_NAME ${QTKEYCHAIN_TARGET_NAME}
|
||||
DEPS "core ${PRI_EXTRA_DEPS}"
|
||||
INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
FILENAME_VAR pri_filename)
|
||||
|
||||
install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
||||
|
||||
|
||||
install(EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain"
|
||||
)
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain
|
||||
)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain
|
||||
)
|
||||
|
||||
|
||||
@ -7,9 +7,6 @@ are met:
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
|
||||
@ -1,65 +1,6 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 0.14.2 (release 2023-12-17)
|
||||
|
||||
- Add support for KWallet 6 (Volker Krause <vkrause@kde.org>)
|
||||
|
||||
version 0.14.1 (release 2023-06-01)
|
||||
|
||||
- Export QKeychain::isAvailable() to make it usable in a shared build (Volker Krause <vkrause@kde.org>)
|
||||
- Protect against creating the QtKeychain::QtKeychain alias target twice (Volker Krause <vkrause@kde.org>)
|
||||
|
||||
version 0.14.0 (release 2023-05-12)
|
||||
|
||||
- Add Qt 6 Android support (Igor Bugaev <freedbrt@gmail.com>)
|
||||
- Add QtQuick client example ((Igor Bugaev <freedbrt@gmail.com>)
|
||||
- Added Dutch translation (Heimen Stoffels <vistausss@fastmail.com>)
|
||||
- Fix potential freezing with Apple keychain (Claudio Cambra <developer@claudiocambra.com>)
|
||||
- Add API to check whether a secure backend is available at all (Volker Krause <vkrause@kde.org>)
|
||||
|
||||
version 0.13.2 (release 2021-11-18)
|
||||
|
||||
- CMake: Deprecate QTKEYCHAIN_STATIC in favor of BUILD_SHARED_LIBS (be@mixxx.org)
|
||||
|
||||
version 0.13.1 (release 2021-11-08)
|
||||
|
||||
- KWallet: Fix deletion of entries (Issue #199)
|
||||
|
||||
version 0.13.0 (release 2021-11-07)
|
||||
|
||||
- Linux: Require libsecret if not explicitly disabled
|
||||
- Unify implementations for macOS and iOS
|
||||
- CMake: lots of fixes
|
||||
|
||||
version 0.12.0 (release 2020-12-16)
|
||||
|
||||
* Add Qt 6 support, drop Qt 4 support
|
||||
* Require C++11
|
||||
* Add Android support (Mathias Hasselmann)
|
||||
|
||||
version 0.11.1 (release 2020-09-08)
|
||||
|
||||
* Build system fixes
|
||||
|
||||
version 0.11.0 (release 2020-09-08)
|
||||
|
||||
* Important: Debug builds on Windows now get the "d" suffix
|
||||
* Various build system fixes
|
||||
* Add Haiku support (François Revol <revol@free.fr>)
|
||||
* Translation: Russian (Alexander Gorishnyak <kefir500@gmail.com>)
|
||||
* Translation: Update French (David Geiger <david.david@mageialinux-online.org>)
|
||||
|
||||
version 0.10.0 (release 2019-12-17)
|
||||
|
||||
* Detect XFCE desktop correctly. (Sandro Knauß <hefee@debian.org>)
|
||||
* Windows Use CRED_PERSIST_ENTERPRISE (Olivier Goffart <ogoffart@woboq.com>)
|
||||
* Windows: Improve CredWrite() error handling (Christian Kamm <mail@ckamm.de>)
|
||||
* Fix build with Qt 5.12.x (Sergey Ilinykh <rion4ik@gmail.com>)
|
||||
* Fix Qt 4 build (Robert-André Mauchin <zebob.m@gmail.com>)
|
||||
* Translation: Mandarin (Taiwan) (Poren Chiang <ren.chiang@gmail.com>)
|
||||
* Translation: French (François Revol <revol@free.fr>)
|
||||
|
||||
version 0.9.1 (release 2018-08-20)
|
||||
* Windows Credential Store: Use CRED_PERSIST_ENTERPRISE (Olivier Goffart <ogoffart@woboq.com>)
|
||||
* Secret: Don't match the schema name #114 (Christian Kamm <mail@ckamm.de>)
|
||||
|
||||
@ -2,27 +2,21 @@
|
||||
# It defines the following variables
|
||||
# QTKEYCHAIN_INCLUDE_DIRS - include directories for QtKeychain
|
||||
# QTKEYCHAIN_LIBRARIES - libraries to link against
|
||||
# as well as the following imported targets
|
||||
# qt5keychain / qt6keychain
|
||||
# Qt5Keychain::Qt5Keychain / Qt6Keychain::Qt6Keychain
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/Qt@QTKEYCHAIN_VERSION_INFIX@KeychainLibraryDepends.cmake")
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(Qt@QTKEYCHAIN_VERSION_INFIX@Core)
|
||||
if("@QTKEYCHAIN_VERSION_INFIX@" STREQUAL "5")
|
||||
find_dependency(Qt5Core)
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
find_dependency(Qt@QTKEYCHAIN_VERSION_INFIX@DBus)
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_dependency(Qt5DBus)
|
||||
endif()
|
||||
else()
|
||||
find_dependency(Qt4 COMPONENTS QtCore)
|
||||
endif()
|
||||
|
||||
set(QTKEYCHAIN_LIBRARIES "@QTKEYCHAIN_TARGET_NAME@")
|
||||
get_target_property(QTKEYCHAIN_INCLUDE_DIRS "@QTKEYCHAIN_TARGET_NAME@" INTERFACE_INCLUDE_DIRECTORIES)
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18.0 AND NOT TARGET Qt@QTKEYCHAIN_VERSION_INFIX@Keychain::Qt@QTKEYCHAIN_VERSION_INFIX@Keychain)
|
||||
add_library(Qt@QTKEYCHAIN_VERSION_INFIX@Keychain::Qt@QTKEYCHAIN_VERSION_INFIX@Keychain ALIAS qt@QTKEYCHAIN_VERSION_INFIX@keychain)
|
||||
endif()
|
||||
|
||||
check_required_components(Qt@QTKEYCHAIN_VERSION_INFIX@Keychain)
|
||||
|
||||
1
client/qtkeychain/ReadMe.markdown
Symbolic link
1
client/qtkeychain/ReadMe.markdown
Symbolic link
@ -0,0 +1 @@
|
||||
ReadMe.txt
|
||||
@ -1,29 +0,0 @@
|
||||
QtKeychain
|
||||
==========
|
||||
|
||||
QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
|
||||
|
||||
* **macOS:** Passwords are stored in the macOS Keychain.
|
||||
|
||||
* **Linux/Unix:** If running, GNOME Keyring is used, otherwise QtKeychain tries to use KWallet (via D-Bus), if available. Libsecret (common API for desktop-specific solutions)
|
||||
is also supported.
|
||||
|
||||
* **Windows:** By default, the Windows Credential Store is used (requires Windows 7 or newer).
|
||||
Pass `-DUSE_CREDENTIAL_STORE=OFF` to cmake to disable it. If disabled, QtKeychain uses the Windows API function
|
||||
[CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function")
|
||||
to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings.
|
||||
|
||||
* **Android and iOS:** Passwords are stored in the Android keystore system and iOS keychain, respectively.
|
||||
|
||||
In unsupported environments QtKeychain will report an error. It will not store any data unencrypted unless explicitly requested (`setInsecureFallback( true )`).
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
QtKeychain 0.12 and newer supports Qt 5 and Qt 6 and requires a compiler with C++11 support. Older versions support Qt 4 and Qt 5.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details.
|
||||
17
client/qtkeychain/ReadMe.txt
Normal file
17
client/qtkeychain/ReadMe.txt
Normal file
@ -0,0 +1,17 @@
|
||||
QtKeychain
|
||||
==========
|
||||
|
||||
QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
|
||||
|
||||
* **Mac OS X:** Passwords are stored in the OS X Keychain.
|
||||
|
||||
* **Linux/Unix:** If running, GNOME Keyring is used, otherwise qtkeychain tries to use KWallet (via D-Bus), if available.
|
||||
|
||||
* **Windows:** By default, the Windows Credential Store is used (requires Windows 7 or newer).
|
||||
Pass -DUSE_CREDENTIAL_STORE=OFF to cmake use disable it. If disabled, QtKeychain uses the Windows API function
|
||||
[CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function")
|
||||
to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings.
|
||||
|
||||
In unsupported environments QtKeychain will report an error. It will not store any data unencrypted unless explicitly requested (setInsecureFallback( true )).
|
||||
|
||||
**License:** QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details.
|
||||
73
client/qtkeychain/TestAppExample/.gitignore
vendored
73
client/qtkeychain/TestAppExample/.gitignore
vendored
@ -1,73 +0,0 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
QT += quick
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
include(../qtkeychain.pri)
|
||||
|
||||
SOURCES += \
|
||||
keychainclass.cpp \
|
||||
main.cpp
|
||||
|
||||
RESOURCES += qml.qrc
|
||||
|
||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||
QML_IMPORT_PATH =
|
||||
|
||||
# Additional import path used to resolve QML modules just for Qt Quick Designer
|
||||
QML_DESIGNER_IMPORT_PATH =
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
HEADERS += \
|
||||
keychainclass.h
|
||||
@ -1,61 +0,0 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "keychainclass.h"
|
||||
|
||||
KeyChainClass::KeyChainClass(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_readCredentialJob(QLatin1String("keychain.example.project.app")),
|
||||
m_writeCredentialJob(QLatin1String("keychain.example.project.app")),
|
||||
m_deleteCredentialJob(QLatin1String("keychain.example.project.app"))
|
||||
{
|
||||
m_readCredentialJob.setAutoDelete(false);
|
||||
m_writeCredentialJob.setAutoDelete(false);
|
||||
m_deleteCredentialJob.setAutoDelete(false);
|
||||
}
|
||||
|
||||
void KeyChainClass::readKey(const QString &key)
|
||||
{
|
||||
m_readCredentialJob.setKey(key);
|
||||
|
||||
QObject::connect(&m_readCredentialJob, &QKeychain::ReadPasswordJob::finished, [=](){
|
||||
if (m_readCredentialJob.error()) {
|
||||
emit error(tr("Read key failed: %1").arg(qPrintable(m_readCredentialJob.errorString())));
|
||||
return;
|
||||
}
|
||||
emit keyRestored(key, m_readCredentialJob.textData());
|
||||
});
|
||||
|
||||
m_readCredentialJob.start();
|
||||
}
|
||||
|
||||
void KeyChainClass::writeKey(const QString &key, const QString &value)
|
||||
{
|
||||
m_writeCredentialJob.setKey(key);
|
||||
|
||||
QObject::connect(&m_writeCredentialJob, &QKeychain::WritePasswordJob::finished, [=](){
|
||||
if (m_writeCredentialJob.error()) {
|
||||
emit error(tr("Write key failed: %1").arg(qPrintable(m_writeCredentialJob.errorString())));
|
||||
return;
|
||||
}
|
||||
|
||||
emit keyStored(key);
|
||||
});
|
||||
|
||||
m_writeCredentialJob.setTextData(value);
|
||||
m_writeCredentialJob.start();
|
||||
}
|
||||
|
||||
void KeyChainClass::deleteKey(const QString &key)
|
||||
{
|
||||
m_deleteCredentialJob.setKey(key);
|
||||
|
||||
QObject::connect(&m_deleteCredentialJob, &QKeychain::DeletePasswordJob::finished, [=](){
|
||||
if (m_deleteCredentialJob.error()) {
|
||||
emit error(tr("Delete key failed: %1").arg(qPrintable(m_deleteCredentialJob.errorString())));
|
||||
return;
|
||||
}
|
||||
emit keyDeleted(key);
|
||||
});
|
||||
|
||||
m_deleteCredentialJob.start();
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
#ifndef KEYCHAINCLASS_H
|
||||
#define KEYCHAINCLASS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <keychain.h>
|
||||
|
||||
class KeyChainClass: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KeyChainClass(QObject* parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void readKey(const QString& key);
|
||||
Q_INVOKABLE void writeKey(const QString& key, const QString& value);
|
||||
Q_INVOKABLE void deleteKey(const QString& key);
|
||||
|
||||
Q_SIGNALS:
|
||||
void keyStored(const QString& key);
|
||||
void keyRestored(const QString& key, const QString& value);
|
||||
void keyDeleted(const QString& key);
|
||||
void error(const QString& errorText);
|
||||
|
||||
private:
|
||||
QKeychain::ReadPasswordJob m_readCredentialJob;
|
||||
QKeychain::WritePasswordJob m_writeCredentialJob;
|
||||
QKeychain::DeletePasswordJob m_deleteCredentialJob;
|
||||
};
|
||||
|
||||
#endif // KEYCHAINCLASS_H
|
||||
@ -1,29 +0,0 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include "keychainclass.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
const QUrl url(QStringLiteral("qrc:/main.qml"));
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
KeyChainClass keyChainClass;
|
||||
|
||||
engine.rootContext()->setContextProperty("KeyChain", &keyChainClass);
|
||||
engine.load(url);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@ -1,131 +0,0 @@
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Window 2.13
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
Window {
|
||||
id: root
|
||||
|
||||
width: 640
|
||||
height: 480
|
||||
visible: true
|
||||
|
||||
Column {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 50
|
||||
}
|
||||
spacing: 20
|
||||
|
||||
Label {
|
||||
text: 'Key name:'
|
||||
font.pixelSize: 20
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: keyNameTextField
|
||||
|
||||
width: parent.width
|
||||
height: 50
|
||||
|
||||
text: 'default key name'
|
||||
}
|
||||
|
||||
Label {
|
||||
text: 'Key value:'
|
||||
font.pixelSize: 20
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: keyValueTextField
|
||||
|
||||
width: parent.width
|
||||
height: 50
|
||||
|
||||
text: 'some value'
|
||||
}
|
||||
|
||||
Label {
|
||||
id: infoLabel
|
||||
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
visible: false
|
||||
|
||||
onVisibleChanged: if (visible) hideAnimation.start();
|
||||
|
||||
SequentialAnimation {
|
||||
id: hideAnimation
|
||||
|
||||
PauseAnimation {
|
||||
duration: 10000
|
||||
}
|
||||
|
||||
ScriptAction {
|
||||
script: infoLabel.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
KeyChain.keyStored.connect((key) => {
|
||||
infoLabel.text = String("Key '%1' successfully stored").arg(key)
|
||||
infoLabel.color = 'green'
|
||||
infoLabel.visible = true
|
||||
})
|
||||
|
||||
KeyChain.keyRestored.connect((key, value) => {
|
||||
infoLabel.text = String("Key '%1' successfully restored with data '%2'").arg(key).arg(value)
|
||||
infoLabel.color = 'green'
|
||||
infoLabel.visible = true
|
||||
})
|
||||
|
||||
KeyChain.keyDeleted.connect((key) => {
|
||||
infoLabel.text = String("Key '%1' successfully deleted").arg(key)
|
||||
infoLabel.color = 'green'
|
||||
infoLabel.visible = true
|
||||
})
|
||||
|
||||
KeyChain.error.connect((errorText) => {
|
||||
infoLabel.text = errorText
|
||||
infoLabel.color = 'red'
|
||||
infoLabel.visible = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 50
|
||||
spacing: 20
|
||||
|
||||
Button {
|
||||
width: 80
|
||||
height: parent.height
|
||||
text: 'Store'
|
||||
|
||||
onClicked: {
|
||||
KeyChain.writeKey(keyNameTextField.text.trim(), keyValueTextField.text.trim())
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
width: 80
|
||||
height: parent.height
|
||||
text: 'Restore'
|
||||
|
||||
onClicked: {
|
||||
KeyChain.readKey(keyNameTextField.text.trim())
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
width: 80
|
||||
height: parent.height
|
||||
text: 'Delete'
|
||||
onClicked: {
|
||||
KeyChain.deleteKey(keyNameTextField.text.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@ -1,304 +0,0 @@
|
||||
#include "androidkeystore_p.h"
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
|
||||
#include "private/qjni_p.h"
|
||||
#endif
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QAndroidJniEnvironment>
|
||||
#endif
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
using namespace android::content;
|
||||
using namespace android::security;
|
||||
|
||||
using namespace java::io;
|
||||
using namespace java::lang;
|
||||
using namespace java::math;
|
||||
using namespace java::util;
|
||||
using namespace java::security;
|
||||
using namespace java::security::spec;
|
||||
|
||||
using namespace javax::crypto;
|
||||
using namespace javax::security::auth::x500;
|
||||
using namespace javax::security::cert;
|
||||
|
||||
const BigInteger BigInteger::ONE = BigInteger::getStaticObjectField("java/math/BigInteger", "ONE", "Ljava/math/BigInteger;");
|
||||
|
||||
const int Calendar::YEAR = Calendar::getStaticField<jint>("java/util/Calendar", "YEAR");
|
||||
|
||||
const int Cipher::DECRYPT_MODE = Cipher::getStaticField<jint>("javax/crypto/Cipher", "DECRYPT_MODE");
|
||||
const int Cipher::ENCRYPT_MODE = Cipher::getStaticField<jint>("javax/crypto/Cipher", "ENCRYPT_MODE");
|
||||
|
||||
namespace {
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
|
||||
|
||||
struct JNIObject
|
||||
{
|
||||
JNIObject(QSharedPointer<QJNIObjectPrivate> d): d(d) {}
|
||||
|
||||
static JNIObject fromLocalRef(jobject o)
|
||||
{
|
||||
return JNIObject(QSharedPointer<QJNIObjectPrivate>::create(QJNIObjectPrivate::fromLocalRef(o)));
|
||||
}
|
||||
|
||||
jobject object() const { return d->object(); }
|
||||
QSharedPointer<QJNIObjectPrivate> d;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
using JNIObject = QAndroidJniObject;
|
||||
|
||||
#endif
|
||||
|
||||
QByteArray fromArray(const jbyteArray array)
|
||||
{
|
||||
QAndroidJniEnvironment env;
|
||||
jbyte *const bytes = env->GetByteArrayElements(array, nullptr);
|
||||
const QByteArray result(reinterpret_cast<const char *>(bytes), env->GetArrayLength(array));
|
||||
env->ReleaseByteArrayElements(array, bytes, JNI_ABORT);
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIObject toArray(const QByteArray &bytes)
|
||||
{
|
||||
QAndroidJniEnvironment env;
|
||||
const int length = bytes.length();
|
||||
JNIObject array = JNIObject::fromLocalRef(env->NewByteArray(length));
|
||||
env->SetByteArrayRegion(static_cast<jbyteArray>(array.object()),
|
||||
0, length, reinterpret_cast<const jbyte *>(bytes.constData()));
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Object::handleExceptions()
|
||||
{
|
||||
QAndroidJniEnvironment env;
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
KeyPairGenerator KeyPairGenerator::getInstance(const QString &algorithm, const QString &provider)
|
||||
{
|
||||
return handleExceptions(callStaticObjectMethod("java/security/KeyPairGenerator", "getInstance",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Ljava/security/KeyPairGenerator;",
|
||||
fromString(algorithm).object(), fromString(provider).object()));
|
||||
}
|
||||
|
||||
KeyPair KeyPairGenerator::generateKeyPair() const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("generateKeyPair", "()Ljava/security/KeyPair;"));
|
||||
}
|
||||
|
||||
bool KeyPairGenerator::initialize(const AlgorithmParameterSpec &spec) const
|
||||
{
|
||||
callMethod<void>("initialize", "(Ljava/security/spec/AlgorithmParameterSpec;)V", spec.object());
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
bool KeyStore::containsAlias(const QString &alias) const
|
||||
{
|
||||
return handleExceptions(callMethod<jboolean>("containsAlias", "(Ljava/lang/String;)Z",
|
||||
fromString(alias).object()));
|
||||
}
|
||||
|
||||
bool KeyStore::deleteEntry(const QString &alias) const
|
||||
{
|
||||
callMethod<void>("deleteEntry", "(Ljava/lang/String;)V", fromString(alias).object());
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
KeyStore KeyStore::getInstance(const QString &type)
|
||||
{
|
||||
return handleExceptions(callStaticObjectMethod("java/security/KeyStore", "getInstance",
|
||||
"(Ljava/lang/String;)Ljava/security/KeyStore;",
|
||||
fromString(type).object()));
|
||||
}
|
||||
|
||||
KeyStore::Entry KeyStore::getEntry(const QString &alias, const KeyStore::ProtectionParameter ¶m) const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("getEntry",
|
||||
"(Ljava/lang/String;Ljava/security/KeyStore$ProtectionParameter;)Ljava/security/KeyStore$Entry;",
|
||||
fromString(alias).object(), param.object()));
|
||||
}
|
||||
|
||||
bool KeyStore::load(const KeyStore::LoadStoreParameter ¶m) const
|
||||
{
|
||||
callMethod<void>("load", "(Ljava/security/KeyStore$LoadStoreParameter;)V", param.object());
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
|
||||
Calendar Calendar::getInstance()
|
||||
{
|
||||
return handleExceptions(callStaticObjectMethod("java/util/Calendar", "getInstance",
|
||||
"()Ljava/util/Calendar;"));
|
||||
|
||||
}
|
||||
|
||||
bool Calendar::add(int field, int amount) const
|
||||
{
|
||||
callMethod<void>("add", "(II)V", field, amount);
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
Date Calendar::getTime() const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("getTime", "()Ljava/util/Date;"));
|
||||
}
|
||||
|
||||
KeyPairGeneratorSpec::Builder::Builder(const Context &context)
|
||||
: Object(QAndroidJniObject("android/security/KeyPairGeneratorSpec$Builder",
|
||||
"(Landroid/content/Context;)V",
|
||||
context.object()))
|
||||
{
|
||||
handleExceptions();
|
||||
}
|
||||
|
||||
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setAlias(const QString &alias) const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("setAlias",
|
||||
"(Ljava/lang/String;)Landroid/security/KeyPairGeneratorSpec$Builder;",
|
||||
fromString(alias).object()));
|
||||
}
|
||||
|
||||
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setSubject(const X500Principal &subject) const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("setSubject",
|
||||
"(Ljavax/security/auth/x500/X500Principal;)Landroid/security/KeyPairGeneratorSpec$Builder;",
|
||||
subject.object()));
|
||||
}
|
||||
|
||||
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setSerialNumber(const BigInteger &serial) const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("setSerialNumber",
|
||||
"(Ljava/math/BigInteger;)Landroid/security/KeyPairGeneratorSpec$Builder;",
|
||||
serial.object()));
|
||||
}
|
||||
|
||||
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setStartDate(const Date &date) const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("setStartDate",
|
||||
"(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;",
|
||||
date.object()));
|
||||
}
|
||||
|
||||
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setEndDate(const Date &date) const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("setEndDate",
|
||||
"(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;",
|
||||
date.object()));
|
||||
}
|
||||
|
||||
KeyPairGeneratorSpec KeyPairGeneratorSpec::Builder::build() const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("build", "()Landroid/security/KeyPairGeneratorSpec;"));
|
||||
}
|
||||
|
||||
X500Principal::X500Principal(const QString &name)
|
||||
: Object(QAndroidJniObject("javax/security/auth/x500/X500Principal",
|
||||
"(Ljava/lang/String;)V",
|
||||
fromString(name).object()))
|
||||
{
|
||||
handleExceptions();
|
||||
}
|
||||
|
||||
Certificate KeyStore::PrivateKeyEntry::getCertificate() const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("getCertificate", "()Ljava/security/cert/Certificate;"));
|
||||
}
|
||||
|
||||
PrivateKey KeyStore::PrivateKeyEntry::getPrivateKey() const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("getPrivateKey", "()Ljava/security/PrivateKey;"));
|
||||
}
|
||||
|
||||
PublicKey Certificate::getPublicKey() const
|
||||
{
|
||||
return handleExceptions(callObjectMethod("getPublicKey", "()Ljava/security/PublicKey;"));
|
||||
}
|
||||
|
||||
ByteArrayInputStream::ByteArrayInputStream(const QByteArray &bytes)
|
||||
: InputStream(QAndroidJniObject("java/io/ByteArrayInputStream", "([B)V", toArray(bytes).object()))
|
||||
{
|
||||
}
|
||||
|
||||
ByteArrayOutputStream::ByteArrayOutputStream()
|
||||
: OutputStream(QAndroidJniObject("java/io/ByteArrayOutputStream"))
|
||||
{
|
||||
handleExceptions();
|
||||
}
|
||||
|
||||
QByteArray ByteArrayOutputStream::toByteArray() const
|
||||
{
|
||||
const QAndroidJniObject wrapper = callObjectMethod<jbyteArray>("toByteArray");
|
||||
|
||||
if (!handleExceptions())
|
||||
return QByteArray();
|
||||
|
||||
return fromArray(static_cast<jbyteArray>(wrapper.object()));
|
||||
}
|
||||
|
||||
int InputStream::read() const
|
||||
{
|
||||
return handleExceptions(callMethod<int>("read"), -1);
|
||||
}
|
||||
|
||||
bool OutputStream::write(const QByteArray &bytes) const
|
||||
{
|
||||
callMethod<void>("write", "([B)V", toArray(bytes).object());
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
bool OutputStream::close() const
|
||||
{
|
||||
callMethod<void>("close");
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
bool OutputStream::flush() const
|
||||
{
|
||||
callMethod<void>("flush");
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
Cipher Cipher::getInstance(const QString &transformation)
|
||||
{
|
||||
return handleExceptions(callStaticObjectMethod("javax/crypto/Cipher", "getInstance",
|
||||
"(Ljava/lang/String;)Ljavax/crypto/Cipher;",
|
||||
fromString(transformation).object()));
|
||||
}
|
||||
|
||||
bool Cipher::init(int opMode, const Key &key) const
|
||||
{
|
||||
callMethod<void>("init", "(ILjava/security/Key;)V", opMode, key.object());
|
||||
return handleExceptions();
|
||||
}
|
||||
|
||||
|
||||
CipherOutputStream::CipherOutputStream(const OutputStream &stream, const Cipher &cipher)
|
||||
: FilterOutputStream(QAndroidJniObject("javax/crypto/CipherOutputStream",
|
||||
"(Ljava/io/OutputStream;Ljavax/crypto/Cipher;)V",
|
||||
stream.object(), cipher.object()))
|
||||
{
|
||||
handleExceptions();
|
||||
}
|
||||
|
||||
CipherInputStream::CipherInputStream(const InputStream &stream, const Cipher &cipher)
|
||||
: FilterInputStream(QAndroidJniObject("javax/crypto/CipherInputStream",
|
||||
"(Ljava/io/InputStream;Ljavax/crypto/Cipher;)V",
|
||||
stream.object(), cipher.object()))
|
||||
{
|
||||
handleExceptions();
|
||||
}
|
||||
@ -1,382 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
|
||||
* *
|
||||
* 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. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QTKEYCHAIN_ANDROIDKEYSTORE_P_H
|
||||
#define QTKEYCHAIN_ANDROIDKEYSTORE_P_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QAndroidJniObject>
|
||||
#else
|
||||
#include <QJniObject>
|
||||
#include <QJniEnvironment>
|
||||
|
||||
typedef QJniObject QAndroidJniObject;
|
||||
typedef QJniEnvironment QAndroidJniEnvironment;
|
||||
|
||||
#endif
|
||||
|
||||
namespace QKeychain {
|
||||
|
||||
namespace javax {
|
||||
namespace security {
|
||||
|
||||
namespace auth { namespace x500 { class X500Principal; } }
|
||||
namespace cert { class Certificate; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace java {
|
||||
namespace lang {
|
||||
|
||||
class Object : protected QAndroidJniObject
|
||||
{
|
||||
public:
|
||||
inline Object(jobject object) : QAndroidJniObject(object) {}
|
||||
inline Object(const QAndroidJniObject &object) : QAndroidJniObject(object) {}
|
||||
inline operator bool() const { return isValid(); }
|
||||
|
||||
using QAndroidJniObject::object;
|
||||
using QAndroidJniObject::toString;
|
||||
|
||||
protected:
|
||||
static bool handleExceptions();
|
||||
|
||||
template<typename T>
|
||||
static T handleExceptions(const T &result, const T &resultOnError = T());
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline T Object::handleExceptions(const T &result, const T &resultOnError)
|
||||
{
|
||||
if (!handleExceptions())
|
||||
return resultOnError;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace lang
|
||||
|
||||
namespace io {
|
||||
|
||||
class InputStream : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
int read() const;
|
||||
};
|
||||
|
||||
class ByteArrayInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
using InputStream::InputStream;
|
||||
|
||||
explicit ByteArrayInputStream(const QByteArray &bytes);
|
||||
};
|
||||
|
||||
class FilterInputStream : public InputStream
|
||||
{
|
||||
public:
|
||||
using InputStream::InputStream;
|
||||
};
|
||||
|
||||
class OutputStream : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
bool write(const QByteArray &bytes) const;
|
||||
bool flush() const;
|
||||
bool close() const;
|
||||
};
|
||||
|
||||
class ByteArrayOutputStream : public OutputStream
|
||||
{
|
||||
public:
|
||||
using OutputStream::OutputStream;
|
||||
|
||||
ByteArrayOutputStream();
|
||||
|
||||
QByteArray toByteArray() const;
|
||||
};
|
||||
|
||||
class FilterOutputStream : public OutputStream
|
||||
{
|
||||
public:
|
||||
using OutputStream::OutputStream;
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
|
||||
namespace math {
|
||||
|
||||
class BigInteger : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
static const BigInteger ZERO;
|
||||
static const BigInteger ONE;
|
||||
static const BigInteger TEN;
|
||||
};
|
||||
|
||||
} // namespace math
|
||||
|
||||
namespace util {
|
||||
|
||||
class Date : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
class Calendar : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
static const int YEAR;
|
||||
static const int MONTH;
|
||||
static const int DAY;
|
||||
static const int HOUR;
|
||||
static const int MINUTE;
|
||||
static const int SECOND;
|
||||
static const int MILLISECOND;
|
||||
|
||||
static Calendar getInstance();
|
||||
|
||||
bool add(int field, int amount) const;
|
||||
Date getTime() const;
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
|
||||
namespace security {
|
||||
namespace spec {
|
||||
|
||||
class AlgorithmParameterSpec : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
} // namespace spec
|
||||
|
||||
class Key : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
class PrivateKey : public Key
|
||||
{
|
||||
public:
|
||||
using Key::Key;
|
||||
|
||||
PrivateKey(const Key &init): Key(init) {}
|
||||
};
|
||||
|
||||
class PublicKey : public Key
|
||||
{
|
||||
public:
|
||||
using Key::Key;
|
||||
|
||||
PublicKey(const Key &init): Key(init) {}
|
||||
};
|
||||
|
||||
class KeyPair : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
class KeyPairGenerator : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
static KeyPairGenerator getInstance(const QString &algorithm, const QString &provider);
|
||||
KeyPair generateKeyPair() const;
|
||||
bool initialize(const spec::AlgorithmParameterSpec &spec) const;
|
||||
|
||||
};
|
||||
|
||||
class KeyStore : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
class Entry : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
class PrivateKeyEntry : public Entry
|
||||
{
|
||||
public:
|
||||
using Entry::Entry;
|
||||
|
||||
inline PrivateKeyEntry(const Entry &init): Entry(init) {}
|
||||
|
||||
javax::security::cert::Certificate getCertificate() const;
|
||||
java::security::PrivateKey getPrivateKey() const;
|
||||
};
|
||||
|
||||
class LoadStoreParameter : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
class ProtectionParameter : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
using Object::Object;
|
||||
|
||||
bool containsAlias(const QString &alias) const;
|
||||
bool deleteEntry(const QString &alias) const;
|
||||
static KeyStore getInstance(const QString &type);
|
||||
Entry getEntry(const QString &alias, const ProtectionParameter ¶m = nullptr) const;
|
||||
bool load(const LoadStoreParameter ¶m = nullptr) const;
|
||||
};
|
||||
|
||||
namespace interfaces {
|
||||
|
||||
class RSAPrivateKey : public PrivateKey
|
||||
{
|
||||
public:
|
||||
using PrivateKey::PrivateKey;
|
||||
|
||||
RSAPrivateKey(const PrivateKey &init): PrivateKey(init) {}
|
||||
};
|
||||
|
||||
class RSAPublicKey : public PublicKey
|
||||
{
|
||||
public:
|
||||
using PublicKey::PublicKey;
|
||||
|
||||
RSAPublicKey(const PublicKey &init): PublicKey(init) {}
|
||||
};
|
||||
|
||||
} // namespace interfaces
|
||||
|
||||
} // namespace security
|
||||
} // namespace java
|
||||
|
||||
namespace android {
|
||||
namespace content {
|
||||
|
||||
class Context : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
|
||||
namespace security {
|
||||
|
||||
class KeyPairGeneratorSpec : public java::security::spec::AlgorithmParameterSpec
|
||||
{
|
||||
public:
|
||||
class Builder : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
explicit Builder(const android::content::Context &context);
|
||||
|
||||
Builder setAlias(const QString &alias) const;
|
||||
Builder setSubject(const javax::security::auth::x500::X500Principal &subject) const;
|
||||
Builder setSerialNumber(const java::math::BigInteger &serial) const;
|
||||
Builder setStartDate(const java::util::Date &date) const;
|
||||
Builder setEndDate(const java::util::Date &date) const;
|
||||
KeyPairGeneratorSpec build() const;
|
||||
|
||||
};
|
||||
|
||||
using AlgorithmParameterSpec::AlgorithmParameterSpec;
|
||||
};
|
||||
|
||||
} // namespace security
|
||||
} // namespace android
|
||||
|
||||
namespace javax {
|
||||
namespace crypto {
|
||||
|
||||
class Cipher : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
static const int DECRYPT_MODE;
|
||||
static const int ENCRYPT_MODE;
|
||||
|
||||
using Object::Object;
|
||||
|
||||
static Cipher getInstance(const QString &transformation);
|
||||
bool init(int opMode, const java::security::Key &key) const;
|
||||
};
|
||||
|
||||
class CipherInputStream : public java::io::FilterInputStream
|
||||
{
|
||||
public:
|
||||
using FilterInputStream::FilterInputStream;
|
||||
|
||||
explicit CipherInputStream(const InputStream &stream, const Cipher &cipher);
|
||||
};
|
||||
|
||||
class CipherOutputStream : public java::io::FilterOutputStream
|
||||
{
|
||||
public:
|
||||
using FilterOutputStream::FilterOutputStream;
|
||||
|
||||
explicit CipherOutputStream(const OutputStream &stream, const Cipher &cipher);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace security {
|
||||
namespace auth {
|
||||
namespace x500 {
|
||||
|
||||
class X500Principal;
|
||||
|
||||
class X500Principal : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
explicit X500Principal(const QString &name);
|
||||
};
|
||||
|
||||
} // namespace x500
|
||||
} // namespace auth
|
||||
|
||||
namespace cert {
|
||||
|
||||
class Certificate : public java::lang::Object
|
||||
{
|
||||
public:
|
||||
using Object::Object;
|
||||
|
||||
java::security::PublicKey getPublicKey() const;
|
||||
};
|
||||
|
||||
} // namespace cert
|
||||
|
||||
} // namespace security
|
||||
} // namespace javax
|
||||
|
||||
} // namespace QKeychain
|
||||
|
||||
#endif // QTKEYCHAIN_ANDROIDKEYSTORE_P_H
|
||||
@ -1,124 +1,125 @@
|
||||
# SPDX-FileCopyrightText: 2014 David Faure <faure@kde.org>
|
||||
#.rst:
|
||||
# ECMGeneratePriFile
|
||||
# ------------------
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Generate a ``.pri`` file for the benefit of qmake-based projects.
|
||||
#
|
||||
# As well as the function below, this module creates the cache variable
|
||||
# ``ECM_MKSPECS_INSTALL_DIR`` and sets the default value to ``mkspecs/modules``.
|
||||
# This assumes Qt and the current project are both installed to the same
|
||||
# non-system prefix. Packagers who use ``-DCMAKE_INSTALL_PREFIX=/usr`` will
|
||||
# certainly want to set ``ECM_MKSPECS_INSTALL_DIR`` to something like
|
||||
# ``share/qt5/mkspecs/modules``.
|
||||
#
|
||||
# The main thing is that this should be the ``modules`` subdirectory of either
|
||||
# the default qmake ``mkspecs`` directory or of a directory that will be in the
|
||||
# ``$QMAKEPATH`` environment variable when qmake is run.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_generate_pri_file(BASE_NAME <baseName>
|
||||
# LIB_NAME <libName>
|
||||
# [DEPS "<dep> [<dep> [...]]"]
|
||||
# [FILENAME_VAR <filename_variable>]
|
||||
# [INCLUDE_INSTALL_DIR <dir>]
|
||||
# [LIB_INSTALL_DIR <dir>])
|
||||
#
|
||||
# If your CMake project produces a Qt-based library, you may expect there to be
|
||||
# applications that wish to use it that use a qmake-based build system, rather
|
||||
# than a CMake-based one. Creating a ``.pri`` file will make use of your
|
||||
# library convenient for them, in much the same way that CMake config files make
|
||||
# things convenient for CMake-based applications.
|
||||
#
|
||||
# ecm_generate_pri_file() generates just such a file. It requires the
|
||||
# ``PROJECT_VERSION_STRING`` variable to be set. This is typically set by
|
||||
# :module:`ECMSetupVersion`, although the project() command in CMake 3.0.0 and
|
||||
# later can also set this.
|
||||
#
|
||||
# BASE_NAME specifies the name qmake project (.pro) files should use to refer to
|
||||
# the library (eg: KArchive). LIB_NAME is the name of the actual library to
|
||||
# link to (ie: the first argument to add_library()). DEPS is a space-separated
|
||||
# list of the base names of other libraries (for Qt libraries, use the same
|
||||
# names you use with the ``QT`` variable in a qmake project file, such as "core"
|
||||
# for QtCore). FILENAME_VAR specifies the name of a variable to store the path
|
||||
# to the generated file in.
|
||||
#
|
||||
# INCLUDE_INSTALL_DIR is the path (relative to ``CMAKE_INSTALL_PREFIX``) that
|
||||
# include files will be installed to. It defaults to
|
||||
# ``${INCLUDE_INSTALL_DIR}/<baseName>`` if the ``INCLUDE_INSTALL_DIR`` variable
|
||||
# is set. If that variable is not set, the ``CMAKE_INSTALL_INCLUDEDIR`` variable
|
||||
# is used instead, and if neither are set ``include`` is used. LIB_INSTALL_DIR
|
||||
# operates similarly for the installation location for libraries; it defaults to
|
||||
# ``${LIB_INSTALL_DIR}``, ``${CMAKE_INSTALL_LIBDIR}`` or ``lib``, in that order.
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# .. code-block:: cmake
|
||||
#
|
||||
# ecm_generate_pri_file(
|
||||
# BASE_NAME KArchive
|
||||
# LIB_NAME KF5KArchive
|
||||
# DEPS "core"
|
||||
# FILENAME_VAR pri_filename
|
||||
# )
|
||||
# install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
||||
#
|
||||
# A qmake-based project that wished to use this would then do::
|
||||
#
|
||||
# QT += KArchive
|
||||
#
|
||||
# in their ``.pro`` file.
|
||||
#
|
||||
# Since pre-1.0.0.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
ECMGeneratePriFile
|
||||
------------------
|
||||
|
||||
Generate a ``.pri`` file for the benefit of qmake-based projects.
|
||||
|
||||
As well as the function below, this module creates the cache variable
|
||||
``ECM_MKSPECS_INSTALL_DIR`` and sets the default value to ``mkspecs/modules``.
|
||||
This assumes Qt and the current project are both installed to the same
|
||||
non-system prefix. Packagers who use ``-DCMAKE_INSTALL_PREFIX=/usr`` will
|
||||
certainly want to set ``ECM_MKSPECS_INSTALL_DIR`` to something like
|
||||
``share/qt5/mkspecs/modules``.
|
||||
|
||||
The main thing is that this should be the ``modules`` subdirectory of either
|
||||
the default qmake ``mkspecs`` directory or of a directory that will be in the
|
||||
``$QMAKEPATH`` environment variable when qmake is run.
|
||||
|
||||
::
|
||||
|
||||
ecm_generate_pri_file(BASE_NAME <baseName>
|
||||
LIB_NAME <libName>
|
||||
[VERSION <version>] # since 5.83
|
||||
[DEPS "<dep> [<dep> [...]]"]
|
||||
[FILENAME_VAR <filename_variable>]
|
||||
[INCLUDE_INSTALL_DIRS <dir> [<dir> [...]]] # since 5.92
|
||||
[INCLUDE_INSTALL_DIR <dir>] # deprecated since 5.92
|
||||
[LIB_INSTALL_DIR <dir>])
|
||||
|
||||
If your CMake project produces a Qt-based library, you may expect there to be
|
||||
applications that wish to use it that use a qmake-based build system, rather
|
||||
than a CMake-based one. Creating a ``.pri`` file will make use of your
|
||||
library convenient for them, in much the same way that CMake config files make
|
||||
things convenient for CMake-based applications. ``ecm_generate_pri_file()``
|
||||
generates just such a file.
|
||||
|
||||
``VERSION`` specifies the version of the library the ``.pri`` file describes. If
|
||||
not set, the value is taken from the context variable ``PROJECT_VERSION``.
|
||||
This variable is usually set by the ``project(... VERSION ...)`` command or,
|
||||
if CMake policy CMP0048 is not ``NEW``, by :module:`ECMSetupVersion`.
|
||||
For backward-compatibility with older ECM versions the
|
||||
``PROJECT_VERSION_STRING`` variable as set by :module:`ECMSetupVersion`
|
||||
will be preferred over ``PROJECT_VERSION`` if set, unless the minimum
|
||||
required version of ECM is 5.83 and newer. Since 5.83.
|
||||
|
||||
``BASE_NAME`` specifies the name qmake project (.pro) files should use to refer to
|
||||
the library (eg: KArchive). ``LIB_NAME`` is the name of the actual library to
|
||||
link to (ie: the first argument to add_library()). ``DEPS`` is a space-separated
|
||||
list of the base names of other libraries (for Qt libraries, use the same
|
||||
names you use with the ``QT`` variable in a qmake project file, such as "core"
|
||||
for QtCore). ``FILENAME_VAR`` specifies the name of a variable to store the path
|
||||
to the generated file in.
|
||||
|
||||
``INCLUDE_INSTALL_DIRS`` are the paths (relative to ``CMAKE_INSTALL_PREFIX``) that
|
||||
include files will be installed to. It defaults to
|
||||
``${INCLUDE_INSTALL_DIR}/<baseName>`` if the ``INCLUDE_INSTALL_DIR`` variable
|
||||
is set. If that variable is not set, the ``CMAKE_INSTALL_INCLUDEDIR`` variable
|
||||
is used instead, and if neither are set ``include`` is used. ``LIB_INSTALL_DIR``
|
||||
operates similarly for the installation location for libraries; it defaults to
|
||||
``${LIB_INSTALL_DIR}``, ``${CMAKE_INSTALL_LIBDIR}`` or ``lib``, in that order.
|
||||
|
||||
``INCLUDE_INSTALL_DIR`` is the old variant of ``INCLUDE_INSTALL_DIRS``, taking only one
|
||||
directory.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
ecm_generate_pri_file(
|
||||
BASE_NAME KArchive
|
||||
LIB_NAME KF5KArchive
|
||||
DEPS "core"
|
||||
FILENAME_VAR pri_filename
|
||||
VERSION 4.2.0
|
||||
)
|
||||
install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
||||
|
||||
A qmake-based project that wished to use this would then do::
|
||||
|
||||
QT += KArchive
|
||||
|
||||
in their ``.pro`` file.
|
||||
|
||||
Since pre-1.0.0.
|
||||
#]=======================================================================]
|
||||
#=============================================================================
|
||||
# Copyright 2014 David Faure <faure@kde.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Replicate the logic from KDEInstallDirs.cmake as we can't depend on it
|
||||
# Ask qmake if we're using the same prefix as Qt
|
||||
set(_should_query_qt OFF)
|
||||
set(_askqmake OFF)
|
||||
if(NOT DEFINED KDE_INSTALL_USE_QT_SYS_PATHS)
|
||||
include(ECMQueryQt)
|
||||
ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX TRY)
|
||||
include(ECMQueryQmake)
|
||||
query_qmake(qt_install_prefix_dir QT_INSTALL_PREFIX)
|
||||
if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
|
||||
set(_should_query_qt ON)
|
||||
set(_askqmake ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(KDE_INSTALL_USE_QT_SYS_PATHS OR _should_query_qt)
|
||||
include(ECMQueryQt)
|
||||
ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX)
|
||||
ecm_query_qt(qt_host_data_dir QT_HOST_DATA)
|
||||
if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
|
||||
file(RELATIVE_PATH qt_host_data_dir ${qt_install_prefix_dir} ${qt_host_data_dir})
|
||||
endif()
|
||||
if(qt_host_data_dir STREQUAL "")
|
||||
set(mkspecs_install_dir mkspecs/modules)
|
||||
else()
|
||||
set(mkspecs_install_dir ${qt_host_data_dir}/mkspecs/modules)
|
||||
endif()
|
||||
set(ECM_MKSPECS_INSTALL_DIR ${mkspecs_install_dir} CACHE PATH "The directory where mkspecs will be installed to.")
|
||||
if(KDE_INSTALL_USE_QT_SYS_PATHS OR _askqmake)
|
||||
include(ECMQueryQmake)
|
||||
query_qmake(qt_host_data_dir QT_HOST_DATA)
|
||||
set(ECM_MKSPECS_INSTALL_DIR ${qt_host_data_dir}/mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.")
|
||||
else()
|
||||
set(ECM_MKSPECS_INSTALL_DIR mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.")
|
||||
endif()
|
||||
|
||||
function(ECM_GENERATE_PRI_FILE)
|
||||
set(options )
|
||||
set(oneValueArgs BASE_NAME LIB_NAME DEPS FILENAME_VAR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR VERSION)
|
||||
set(multiValueArgs INCLUDE_INSTALL_DIRS)
|
||||
set(oneValueArgs BASE_NAME LIB_NAME DEPS FILENAME_VAR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR)
|
||||
set(multiValueArgs )
|
||||
|
||||
cmake_parse_arguments(EGPF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
@ -126,42 +127,22 @@ function(ECM_GENERATE_PRI_FILE)
|
||||
message(FATAL_ERROR "Unknown keywords given to ECM_GENERATE_PRI_FILE(): \"${EGPF_UNPARSED_ARGUMENTS}\"")
|
||||
endif()
|
||||
|
||||
if(ECM_GLOBAL_FIND_VERSION VERSION_LESS 5.83.0)
|
||||
set(_support_backward_compat_version_string_var TRUE)
|
||||
else()
|
||||
set(_support_backward_compat_version_string_var FALSE)
|
||||
endif()
|
||||
|
||||
if(NOT EGPF_BASE_NAME)
|
||||
message(FATAL_ERROR "Required argument BASE_NAME missing in ECM_GENERATE_PRI_FILE() call")
|
||||
endif()
|
||||
if(NOT EGPF_LIB_NAME)
|
||||
message(FATAL_ERROR "Required argument LIB_NAME missing in ECM_GENERATE_PRI_FILE() call")
|
||||
endif()
|
||||
if(NOT EGPF_VERSION)
|
||||
if(_support_backward_compat_version_string_var)
|
||||
if(NOT PROJECT_VERSION_STRING AND NOT PROJECT_VERSION)
|
||||
message(FATAL_ERROR "Required variable PROJECT_VERSION_STRING or PROJECT_VERSION not set before ECM_GENERATE_PRI_FILE() call. Missing call of ecm_setup_version() or project(VERSION)?")
|
||||
endif()
|
||||
else()
|
||||
if(NOT PROJECT_VERSION)
|
||||
message(FATAL_ERROR "Required variable PROJECT_VERSION not set before ECM_GENERATE_PRI_FILE() call. Missing call of ecm_setup_version() or project(VERSION)?")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT PROJECT_VERSION_STRING)
|
||||
message(FATAL_ERROR "Required variable PROJECT_VERSION_STRING not set before ECM_GENERATE_PRI_FILE() call. Did you call ecm_setup_version?")
|
||||
endif()
|
||||
if(EGPF_INCLUDE_INSTALL_DIR)
|
||||
if(EGPF_INCLUDE_INSTALL_DIRS)
|
||||
message(FATAL_ERROR "Only one argument of INCLUDE_INSTALL_DIR & INCLUDE_INSTALL_DIRS can be used in ECM_GENERATE_PRI_FILE() call")
|
||||
endif()
|
||||
set(EGPF_INCLUDE_INSTALL_DIRS ${EGPF_INCLUDE_INSTALL_DIR})
|
||||
endif()
|
||||
if(NOT EGPF_INCLUDE_INSTALL_DIRS)
|
||||
if(NOT EGPF_INCLUDE_INSTALL_DIR)
|
||||
if(INCLUDE_INSTALL_DIR)
|
||||
set(EGPF_INCLUDE_INSTALL_DIRS "${INCLUDE_INSTALL_DIR}/${EGPF_BASE_NAME}")
|
||||
set(EGPF_INCLUDE_INSTALL_DIR "${INCLUDE_INSTALL_DIR}/${EGPF_BASE_NAME}")
|
||||
elseif(CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(EGPF_INCLUDE_INSTALL_DIRS "${CMAKE_INSTALL_INCLUDEDIR}/${EGPF_BASE_NAME}")
|
||||
set(EGPF_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/${EGPF_BASE_NAME}")
|
||||
else()
|
||||
set(EGPF_INCLUDE_INSTALL_DIRS "include/${EGPF_BASE_NAME}")
|
||||
set(EGPF_INCLUDE_INSTALL_DIR "include/${EGPF_BASE_NAME}")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT EGPF_LIB_INSTALL_DIR)
|
||||
@ -174,48 +155,22 @@ function(ECM_GENERATE_PRI_FILE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(EGPF_VERSION)
|
||||
set(PRI_VERSION "${EGPF_VERSION}")
|
||||
else()
|
||||
if(_support_backward_compat_version_string_var AND PROJECT_VERSION_STRING)
|
||||
set(PRI_VERSION "${PROJECT_VERSION_STRING}")
|
||||
if(NOT PROJECT_VERSION_STRING STREQUAL PROJECT_VERSION)
|
||||
message(DEPRECATION "ECM_GENERATE_PRI_FILE() will no longer support PROJECT_VERSION_STRING when the required minimum version of ECM is 5.83 or newer. Set VERSION parameter or use PROJECT_VERSION instead.")
|
||||
endif()
|
||||
else()
|
||||
set(PRI_VERSION "${PROJECT_VERSION}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" PRI_VERSION_MAJOR "${PRI_VERSION}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" PRI_VERSION_MINOR "${PRI_VERSION}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PRI_VERSION_PATCH "${PRI_VERSION}")
|
||||
|
||||
# Prepare the right number of "../.." to go from ECM_MKSPECS_INSTALL_DIR to the install prefix
|
||||
# This allows to make the generated pri files relocatable (no absolute paths)
|
||||
if (IS_ABSOLUTE ${ECM_MKSPECS_INSTALL_DIR})
|
||||
set(BASEPATH ${CMAKE_INSTALL_PREFIX})
|
||||
else()
|
||||
string(REGEX REPLACE "[^/]+" ".." PRI_ROOT_RELATIVE_TO_MKSPECS ${ECM_MKSPECS_INSTALL_DIR})
|
||||
set(BASEPATH "$$PWD/${PRI_ROOT_RELATIVE_TO_MKSPECS}")
|
||||
endif()
|
||||
string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" PROJECT_VERSION_MAJOR "${PROJECT_VERSION_STRING}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" PROJECT_VERSION_MINOR "${PROJECT_VERSION_STRING}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PROJECT_VERSION_PATCH "${PROJECT_VERSION_STRING}")
|
||||
|
||||
set(PRI_TARGET_BASENAME ${EGPF_BASE_NAME})
|
||||
set(PRI_TARGET_LIBNAME ${EGPF_LIB_NAME})
|
||||
set(PRI_TARGET_QTDEPS ${EGPF_DEPS})
|
||||
set(PRI_TARGET_INCLUDES)
|
||||
foreach(_dir ${EGPF_INCLUDE_INSTALL_DIRS})
|
||||
# separate list entries with space
|
||||
if(IS_ABSOLUTE "${_dir}")
|
||||
string(APPEND PRI_TARGET_INCLUDES " ${_dir}")
|
||||
else()
|
||||
string(APPEND PRI_TARGET_INCLUDES " ${BASEPATH}/${_dir}")
|
||||
endif()
|
||||
endforeach()
|
||||
if(IS_ABSOLUTE "${EGPF_INCLUDE_INSTALL_DIR}")
|
||||
set(PRI_TARGET_INCLUDES "${EGPF_INCLUDE_INSTALL_DIR}")
|
||||
else()
|
||||
set(PRI_TARGET_INCLUDES "${CMAKE_INSTALL_PREFIX}/${EGPF_INCLUDE_INSTALL_DIR}")
|
||||
endif()
|
||||
if(IS_ABSOLUTE "${EGPF_LIB_INSTALL_DIR}")
|
||||
set(PRI_TARGET_LIBS "${EGPF_LIB_INSTALL_DIR}")
|
||||
else()
|
||||
set(PRI_TARGET_LIBS "${BASEPATH}/${EGPF_LIB_INSTALL_DIR}")
|
||||
set(PRI_TARGET_LIBS "${CMAKE_INSTALL_PREFIX}/${EGPF_LIB_INSTALL_DIR}")
|
||||
endif()
|
||||
set(PRI_TARGET_DEFINES "")
|
||||
|
||||
@ -224,25 +179,13 @@ function(ECM_GENERATE_PRI_FILE)
|
||||
set(${EGPF_FILENAME_VAR} ${PRI_FILENAME} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
set(PRI_TARGET_MODULE_CONFIG "")
|
||||
# backward compat: it was not obvious LIB_NAME needs to be a target name,
|
||||
# and some projects where the target name was not the actual library output name
|
||||
# passed the output name for LIB_NAME, so .name & .module prperties are correctly set.
|
||||
# TODO: improve API dox, allow control over module name if target name != output name
|
||||
if(TARGET ${EGPF_LIB_NAME})
|
||||
get_target_property(target_type ${EGPF_LIB_NAME} TYPE)
|
||||
if (target_type STREQUAL "STATIC_LIBRARY")
|
||||
set(PRI_TARGET_MODULE_CONFIG "staticlib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
file(GENERATE
|
||||
OUTPUT ${PRI_FILENAME}
|
||||
CONTENT
|
||||
"QT.${PRI_TARGET_BASENAME}.VERSION = ${PRI_VERSION}
|
||||
QT.${PRI_TARGET_BASENAME}.MAJOR_VERSION = ${PRI_VERSION_MAJOR}
|
||||
QT.${PRI_TARGET_BASENAME}.MINOR_VERSION = ${PRI_VERSION_MINOR}
|
||||
QT.${PRI_TARGET_BASENAME}.PATCH_VERSION = ${PRI_VERSION_PATCH}
|
||||
"QT.${PRI_TARGET_BASENAME}.VERSION = ${PROJECT_VERSION_STRING}
|
||||
QT.${PRI_TARGET_BASENAME}.MAJOR_VERSION = ${PROJECT_VERSION_MAJOR}
|
||||
QT.${PRI_TARGET_BASENAME}.MINOR_VERSION = ${PROJECT_VERSION_MINOR}
|
||||
QT.${PRI_TARGET_BASENAME}.PATCH_VERSION = ${PROJECT_VERSION_PATCH}
|
||||
QT.${PRI_TARGET_BASENAME}.name = ${PRI_TARGET_LIBNAME}
|
||||
QT.${PRI_TARGET_BASENAME}.module = ${PRI_TARGET_LIBNAME}
|
||||
QT.${PRI_TARGET_BASENAME}.defines = ${PRI_TARGET_DEFINES}
|
||||
@ -250,7 +193,6 @@ QT.${PRI_TARGET_BASENAME}.includes = ${PRI_TARGET_INCLUDES}
|
||||
QT.${PRI_TARGET_BASENAME}.private_includes =
|
||||
QT.${PRI_TARGET_BASENAME}.libs = ${PRI_TARGET_LIBS}
|
||||
QT.${PRI_TARGET_BASENAME}.depends = ${PRI_TARGET_QTDEPS}
|
||||
QT.${PRI_TARGET_BASENAME}.module_config = ${PRI_TARGET_MODULE_CONFIG}
|
||||
"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#
|
||||
# ``write_basic_package_version_file()`` is the same as the one provided by the
|
||||
# `CMakePackageConfigHelpers
|
||||
# <https://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
|
||||
# <http://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
|
||||
# module in CMake; see that module's documentation for
|
||||
# more information.
|
||||
#
|
||||
@ -23,7 +23,7 @@
|
||||
# 2.8.12, except that it adds an extra helper macro: find_dependency(). It is
|
||||
# highly recommended that you read the `documentation for
|
||||
# CMakePackageConfigHelpers
|
||||
# <https://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
|
||||
# <http://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
|
||||
# for more information, particularly with regard to the PATH_VARS argument.
|
||||
#
|
||||
# Note that there is no argument that will disable the find_dependency() macro;
|
||||
@ -50,10 +50,31 @@
|
||||
# Since pre-1.0.0.
|
||||
|
||||
#=============================================================================
|
||||
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kdemail.net>
|
||||
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
|
||||
# Copyright 2014 Alex Merry <alex.merry@kdemail.net>
|
||||
# Copyright 2013 Stephen Kelly <steveire@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
include(${CMAKE_ROOT}/Modules/CMakePackageConfigHelpers.cmake)
|
||||
|
||||
|
||||
32
client/qtkeychain/cmake/Modules/ECMQueryQmake.cmake
Normal file
32
client/qtkeychain/cmake/Modules/ECMQueryQmake.cmake
Normal file
@ -0,0 +1,32 @@
|
||||
find_package(Qt5Core QUIET)
|
||||
|
||||
if (Qt5Core_FOUND)
|
||||
set(_qmake_executable_default "qmake-qt5")
|
||||
endif ()
|
||||
if (TARGET Qt5::qmake)
|
||||
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
|
||||
endif()
|
||||
set(QMAKE_EXECUTABLE ${_qmake_executable_default}
|
||||
CACHE FILEPATH "Location of the Qt5 qmake executable")
|
||||
|
||||
# This is not public API (yet)!
|
||||
function(query_qmake result_variable qt_variable)
|
||||
if(NOT QMAKE_EXECUTABLE)
|
||||
set(${result_variable} "" PARENT_SCOPE)
|
||||
message(WARNING "Should specify a qmake Qt5 binary. Can't check ${qt_variable}")
|
||||
return()
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${QMAKE_EXECUTABLE} -query "${qt_variable}"
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE output
|
||||
)
|
||||
if(return_code EQUAL 0)
|
||||
string(STRIP "${output}" output)
|
||||
file(TO_CMAKE_PATH "${output}" output_path)
|
||||
set(${result_variable} "${output_path}" PARENT_SCOPE)
|
||||
else()
|
||||
message(WARNING "Failed call: ${QMAKE_EXECUTABLE} -query \"${qt_variable}\"")
|
||||
message(FATAL_ERROR "QMake call failed: ${return_code}")
|
||||
endif()
|
||||
endfunction()
|
||||
@ -1,100 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
|
||||
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
|
||||
# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
|
||||
# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
|
||||
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#[=======================================================================[.rst:
|
||||
ECMQueryQt
|
||||
---------------
|
||||
This module can be used to query the installation paths used by Qt.
|
||||
|
||||
For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
|
||||
support to query the paths of a target platform when cross-compiling).
|
||||
|
||||
This module defines the following function:
|
||||
::
|
||||
|
||||
ecm_query_qt(<result_variable> <qt_variable> [TRY])
|
||||
|
||||
Passing ``TRY`` will result in the method not making the build fail if the executable
|
||||
used for querying has not been found, but instead simply print a warning message and
|
||||
return an empty string.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
include(ECMQueryQt)
|
||||
ecm_query_qt(bin_dir QT_INSTALL_BINS)
|
||||
|
||||
If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
|
||||
``/usr/lib64/qt/bin/``).
|
||||
|
||||
Since: 5.93
|
||||
#]=======================================================================]
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
|
||||
include(CheckLanguage)
|
||||
check_language(CXX)
|
||||
if (CMAKE_CXX_COMPILER)
|
||||
# Enable the CXX language to let CMake look for config files in library dirs.
|
||||
# See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
|
||||
enable_language(CXX)
|
||||
endif()
|
||||
|
||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
||||
# QUIET to accommodate the TRY option
|
||||
find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
|
||||
if(TARGET Qt5::qmake)
|
||||
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
|
||||
|
||||
set(QUERY_EXECUTABLE ${_qmake_executable_default}
|
||||
CACHE FILEPATH "Location of the Qt5 qmake executable")
|
||||
set(_exec_name_text "Qt5 qmake")
|
||||
set(_cli_option "-query")
|
||||
endif()
|
||||
elseif(QT_MAJOR_VERSION STREQUAL "6")
|
||||
# QUIET to accommodate the TRY option
|
||||
find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
|
||||
if (TARGET Qt6::qtpaths)
|
||||
get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)
|
||||
|
||||
set(QUERY_EXECUTABLE ${_qtpaths_executable}
|
||||
CACHE FILEPATH "Location of the Qt6 qtpaths executable")
|
||||
set(_exec_name_text "Qt6 qtpaths")
|
||||
set(_cli_option "--query")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(ecm_query_qt result_variable qt_variable)
|
||||
set(options TRY)
|
||||
set(oneValueArgs)
|
||||
set(multiValueArgs)
|
||||
|
||||
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT QUERY_EXECUTABLE)
|
||||
if(ARGS_TRY)
|
||||
set(${result_variable} "" PARENT_SCOPE)
|
||||
message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
|
||||
return()
|
||||
else()
|
||||
message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
|
||||
endif()
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE output
|
||||
)
|
||||
if(return_code EQUAL 0)
|
||||
string(STRIP "${output}" output)
|
||||
file(TO_CMAKE_PATH "${output}" output_path)
|
||||
set(${result_variable} "${output_path}" PARENT_SCOPE)
|
||||
else()
|
||||
message(WARNING "Failed call: ${_command} \"${qt_variable}\"")
|
||||
message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
|
||||
endif()
|
||||
endfunction()
|
||||
@ -28,7 +28,7 @@
|
||||
# <prefix>_SOVERSION - <soversion>, or <major> if SOVERSION was not given
|
||||
#
|
||||
# If CMake policy CMP0048 is not NEW, the following CMake variables will also
|
||||
# be set::
|
||||
# be set:
|
||||
#
|
||||
# PROJECT_VERSION_MAJOR - <major>
|
||||
# PROJECT_VERSION_MINOR - <minor>
|
||||
@ -75,13 +75,34 @@
|
||||
#
|
||||
# Since pre-1.0.0.
|
||||
#
|
||||
# COMPATIBILITY option available since 1.6.0.
|
||||
# COMPATIBLITY option available since 1.6.0.
|
||||
|
||||
#=============================================================================
|
||||
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
|
||||
# SPDX-FileCopyrightText: 2012 Alexander Neundorf <neundorf@kde.org>
|
||||
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||
# Copyright 2012 Alexander Neundorf <neundorf@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
@ -133,9 +154,9 @@ function(ecm_setup_version _version)
|
||||
set(_minor "${PROJECT_VERSION_MINOR}")
|
||||
set(_patch "${PROJECT_VERSION_PATCH}")
|
||||
else()
|
||||
string(REGEX REPLACE "^0*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" _major "${_version}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.0*([0-9]+)\\.[0-9]+.*" "\\1" _minor "${_version}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.0*([0-9]+).*" "\\1" _patch "${_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" _major "${_version}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" _minor "${_version}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _patch "${_version}")
|
||||
endif()
|
||||
|
||||
if(NOT ESV_SOVERSION)
|
||||
|
||||
188
client/qtkeychain/cmake/Modules/GNUInstallDirs.cmake
Normal file
188
client/qtkeychain/cmake/Modules/GNUInstallDirs.cmake
Normal file
@ -0,0 +1,188 @@
|
||||
# - Define GNU standard installation directories
|
||||
# Provides install directory variables as defined for GNU software:
|
||||
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||
# Inclusion of this module defines the following variables:
|
||||
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
# where <dir> is one of:
|
||||
# BINDIR - user executables (bin)
|
||||
# SBINDIR - system admin executables (sbin)
|
||||
# LIBEXECDIR - program executables (libexec)
|
||||
# SYSCONFDIR - read-only single-machine data (etc)
|
||||
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||
# LIBDIR - object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)
|
||||
# INCLUDEDIR - C header files (include)
|
||||
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
|
||||
# install() commands for the corresponding file type. If the includer does
|
||||
# not define a value the above-shown default will be used and the value will
|
||||
# appear in the cache for editing by the user.
|
||||
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||
# from the corresponding destination by prepending (if necessary) the value
|
||||
# of CMAKE_INSTALL_PREFIX.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Installation directories
|
||||
#
|
||||
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(_LIBDIR_DEFAULT "lib")
|
||||
# Override this default 'lib' with 'lib64' iff:
|
||||
# - we are on Linux system but NOT cross-compiling
|
||||
# - we are NOT on debian
|
||||
# - we are on a 64 bits system
|
||||
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||
# For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
|
||||
# CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
|
||||
# See http://wiki.debian.org/Multiarch
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||
AND NOT CMAKE_CROSSCOMPILING)
|
||||
if (EXISTS "/etc/debian_version") # is this a debian system ?
|
||||
if(CMAKE_LIBRARY_ARCHITECTURE)
|
||||
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
||||
endif()
|
||||
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
message(AUTHOR_WARNING
|
||||
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||
"Please enable at least one language before including GNUInstallDirs.")
|
||||
else()
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_LIBDIR_DEFAULT "lib64")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||
# the cache and store the defaults in local variables if the cache values are
|
||||
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||
|
||||
if(NOT CMAKE_INSTALL_DATADIR)
|
||||
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_INFODIR)
|
||||
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_MANDIR)
|
||||
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_INSTALL_BINDIR
|
||||
CMAKE_INSTALL_SBINDIR
|
||||
CMAKE_INSTALL_LIBEXECDIR
|
||||
CMAKE_INSTALL_SYSCONFDIR
|
||||
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||
CMAKE_INSTALL_LOCALSTATEDIR
|
||||
CMAKE_INSTALL_LIBDIR
|
||||
CMAKE_INSTALL_INCLUDEDIR
|
||||
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||
CMAKE_INSTALL_DATAROOTDIR
|
||||
CMAKE_INSTALL_DATADIR
|
||||
CMAKE_INSTALL_INFODIR
|
||||
CMAKE_INSTALL_LOCALEDIR
|
||||
CMAKE_INSTALL_MANDIR
|
||||
CMAKE_INSTALL_DOCDIR
|
||||
)
|
||||
|
||||
# Result directories
|
||||
#
|
||||
foreach(dir
|
||||
BINDIR
|
||||
SBINDIR
|
||||
LIBEXECDIR
|
||||
SYSCONFDIR
|
||||
SHAREDSTATEDIR
|
||||
LOCALSTATEDIR
|
||||
LIBDIR
|
||||
INCLUDEDIR
|
||||
OLDINCLUDEDIR
|
||||
DATAROOTDIR
|
||||
DATADIR
|
||||
INFODIR
|
||||
LOCALEDIR
|
||||
MANDIR
|
||||
DOCDIR
|
||||
)
|
||||
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||
endif()
|
||||
endforeach()
|
||||
@ -1,36 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
QtVersionOption
|
||||
---------------
|
||||
|
||||
Adds a build option to select the major Qt version if necessary,
|
||||
that is, if the major Qt version has not yet been determined otherwise
|
||||
(e.g. by a corresponding ``find_package()`` call).
|
||||
This module is typically included by other modules requiring knowledge
|
||||
about the major Qt version.
|
||||
|
||||
``QT_MAJOR_VERSION`` is defined to either be "5" or "6".
|
||||
|
||||
Since 5.82.0.
|
||||
#]=======================================================================]
|
||||
|
||||
if (DEFINED QT_MAJOR_VERSION)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (TARGET Qt5::Core)
|
||||
set(QT_MAJOR_VERSION 5)
|
||||
elseif (TARGET Qt6::Core)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
else()
|
||||
option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
|
||||
|
||||
if (BUILD_WITH_QT6)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
else()
|
||||
set(QT_MAJOR_VERSION 5)
|
||||
endif()
|
||||
endif()
|
||||
@ -1,6 +1,6 @@
|
||||
#include "gnomekeyring_p.h"
|
||||
|
||||
const char* GnomeKeyring::GNOME_KEYRING_DEFAULT = nullptr;
|
||||
const char* GnomeKeyring::GNOME_KEYRING_DEFAULT = NULL;
|
||||
|
||||
bool GnomeKeyring::isAvailable()
|
||||
{
|
||||
|
||||
@ -47,7 +47,7 @@ class JobPrivate;
|
||||
class QKEYCHAIN_EXPORT Job : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
~Job() override;
|
||||
~Job();
|
||||
|
||||
/**
|
||||
* @return The QSettings instance used as plaintext storage if insecureFallback() is true.
|
||||
@ -150,7 +150,7 @@ Q_SIGNALS:
|
||||
void finished( QKeychain::Job* );
|
||||
|
||||
protected:
|
||||
explicit Job( JobPrivate *q, QObject* parent=nullptr );
|
||||
explicit Job( JobPrivate *q, QObject* parent=0 );
|
||||
Q_INVOKABLE void doStart();
|
||||
|
||||
private:
|
||||
@ -185,8 +185,8 @@ public:
|
||||
* @param service The service string used by this job (can be empty).
|
||||
* @param parent The parent of this job.
|
||||
*/
|
||||
explicit ReadPasswordJob( const QString& service, QObject* parent=nullptr );
|
||||
~ReadPasswordJob() override;
|
||||
explicit ReadPasswordJob( const QString& service, QObject* parent=0 );
|
||||
~ReadPasswordJob();
|
||||
|
||||
/**
|
||||
* @return The binary data stored as value of this job's key().
|
||||
@ -222,8 +222,8 @@ public:
|
||||
* @param service The service string used by this job (can be empty).
|
||||
* @param parent The parent of this job.
|
||||
*/
|
||||
explicit WritePasswordJob( const QString& service, QObject* parent=nullptr );
|
||||
~WritePasswordJob() override;
|
||||
explicit WritePasswordJob( const QString& service, QObject* parent=0 );
|
||||
~WritePasswordJob();
|
||||
|
||||
/**
|
||||
* Set the @p data that the job will store in the keychain as binary data.
|
||||
@ -259,24 +259,13 @@ public:
|
||||
* @param service The service string used by this job (can be empty).
|
||||
* @param parent The parent of this job.
|
||||
*/
|
||||
explicit DeletePasswordJob( const QString& service, QObject* parent=nullptr );
|
||||
~DeletePasswordJob() override;
|
||||
explicit DeletePasswordJob( const QString& service, QObject* parent=0 );
|
||||
~DeletePasswordJob();
|
||||
|
||||
private:
|
||||
friend class QKeychain::DeletePasswordJobPrivate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether there is a viable secure backend available.
|
||||
* This particularly matters on UNIX platforms where multiple different backends
|
||||
* exist and none might be available.
|
||||
*
|
||||
* Note that using the insecure fallback will work even if no secure backend is available.
|
||||
*
|
||||
* @since 0.14.0
|
||||
*/
|
||||
QKEYCHAIN_EXPORT bool isAvailable();
|
||||
|
||||
} // namespace QtKeychain
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,195 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
|
||||
* *
|
||||
* 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. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "keychain_p.h"
|
||||
|
||||
#include "androidkeystore_p.h"
|
||||
#include "plaintextstore_p.h"
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QtAndroid>
|
||||
#endif
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
using android::content::Context;
|
||||
using android::security::KeyPairGeneratorSpec;
|
||||
|
||||
using java::io::ByteArrayInputStream;
|
||||
using java::io::ByteArrayOutputStream;
|
||||
using java::security::interfaces::RSAPrivateKey;
|
||||
using java::security::interfaces::RSAPublicKey;
|
||||
using java::security::KeyPair;
|
||||
using java::security::KeyPairGenerator;
|
||||
using java::security::KeyStore;
|
||||
using java::util::Calendar;
|
||||
|
||||
using javax::crypto::Cipher;
|
||||
using javax::crypto::CipherInputStream;
|
||||
using javax::crypto::CipherOutputStream;
|
||||
using javax::security::auth::x500::X500Principal;
|
||||
|
||||
namespace {
|
||||
|
||||
inline QString makeAlias(const QString &service, const QString &key)
|
||||
{
|
||||
return service + QLatin1Char('/') + key;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ReadPasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
PlainTextStore plainTextStore(q->service(), q->settings());
|
||||
|
||||
if (!plainTextStore.contains(q->key())) {
|
||||
q->emitFinishedWithError(Error::EntryNotFound, tr("Entry not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray &encryptedData = plainTextStore.readData(q->key());
|
||||
const KeyStore keyStore = KeyStore::getInstance(QStringLiteral("AndroidKeyStore"));
|
||||
|
||||
if (!keyStore || !keyStore.load()) {
|
||||
q->emitFinishedWithError(Error::AccessDenied, tr("Could not open keystore"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &alias = makeAlias(q->service(), q->key());
|
||||
const KeyStore::PrivateKeyEntry entry = keyStore.getEntry(alias);
|
||||
|
||||
if (!entry) {
|
||||
q->emitFinishedWithError(Error::AccessDenied, tr("Could not retrieve private key from keystore"));
|
||||
return;
|
||||
}
|
||||
|
||||
const Cipher cipher = Cipher::getInstance(QStringLiteral("RSA/ECB/PKCS1Padding"));
|
||||
|
||||
if (!cipher || !cipher.init(Cipher::DECRYPT_MODE, entry.getPrivateKey())) {
|
||||
q->emitFinishedWithError(Error::OtherError, tr("Could not create decryption cipher"));
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray plainData;
|
||||
const CipherInputStream inputStream(ByteArrayInputStream(encryptedData), cipher);
|
||||
|
||||
for (int nextByte; (nextByte = inputStream.read()) != -1; )
|
||||
plainData.append(nextByte);
|
||||
|
||||
mode = plainTextStore.readMode(q->key());
|
||||
data = plainData;
|
||||
q->emitFinished();
|
||||
}
|
||||
|
||||
void WritePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
const KeyStore keyStore = KeyStore::getInstance(QStringLiteral("AndroidKeyStore"));
|
||||
|
||||
if (!keyStore || !keyStore.load()) {
|
||||
q->emitFinishedWithError(Error::AccessDenied, tr("Could not open keystore"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &alias = makeAlias(q->service(), q->key());
|
||||
if (!keyStore.containsAlias(alias)) {
|
||||
const Calendar start = Calendar::getInstance();
|
||||
const Calendar end = Calendar::getInstance();
|
||||
end.add(Calendar::YEAR, 99);
|
||||
|
||||
const KeyPairGeneratorSpec spec =
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
KeyPairGeneratorSpec::Builder(Context(QtAndroid::androidActivity())).
|
||||
#elif QT_VERSION < QT_VERSION_CHECK(6, 4, 0)
|
||||
KeyPairGeneratorSpec::Builder(Context(QNativeInterface::QAndroidApplication::context())).
|
||||
#else
|
||||
KeyPairGeneratorSpec::Builder(Context((jobject)QNativeInterface::QAndroidApplication::context())).
|
||||
#endif
|
||||
setAlias(alias).
|
||||
setSubject(X500Principal(QStringLiteral("CN=QtKeychain, O=Android Authority"))).
|
||||
setSerialNumber(java::math::BigInteger::ONE).
|
||||
setStartDate(start.getTime()).
|
||||
setEndDate(end.getTime()).
|
||||
build();
|
||||
|
||||
const KeyPairGenerator generator = KeyPairGenerator::getInstance(QStringLiteral("RSA"),
|
||||
QStringLiteral("AndroidKeyStore"));
|
||||
|
||||
if (!generator) {
|
||||
q->emitFinishedWithError(Error::OtherError, tr("Could not create private key generator"));
|
||||
return;
|
||||
}
|
||||
|
||||
generator.initialize(spec);
|
||||
|
||||
if (!generator.generateKeyPair()) {
|
||||
q->emitFinishedWithError(Error::OtherError, tr("Could not generate new private key"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const KeyStore::PrivateKeyEntry entry = keyStore.getEntry(alias);
|
||||
|
||||
if (!entry) {
|
||||
q->emitFinishedWithError(Error::AccessDenied, tr("Could not retrieve private key from keystore"));
|
||||
return;
|
||||
}
|
||||
|
||||
const RSAPublicKey publicKey = entry.getCertificate().getPublicKey();
|
||||
const Cipher cipher = Cipher::getInstance(QStringLiteral("RSA/ECB/PKCS1Padding"));
|
||||
|
||||
if (!cipher || !cipher.init(Cipher::ENCRYPT_MODE, publicKey)) {
|
||||
q->emitFinishedWithError(Error::OtherError, tr("Could not create encryption cipher"));
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream outputStream;
|
||||
CipherOutputStream cipherOutputStream(outputStream, cipher);
|
||||
|
||||
if (!cipherOutputStream.write(data) || !cipherOutputStream.close()) {
|
||||
q->emitFinishedWithError(Error::OtherError, tr("Could not encrypt data"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlainTextStore plainTextStore(q->service(), q->settings());
|
||||
plainTextStore.write(q->key(), outputStream.toByteArray(), mode);
|
||||
|
||||
if (plainTextStore.error() != NoError)
|
||||
q->emitFinishedWithError(plainTextStore.error(), plainTextStore.errorString());
|
||||
else
|
||||
q->emitFinished();
|
||||
}
|
||||
|
||||
void DeletePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
const KeyStore keyStore = KeyStore::getInstance(QStringLiteral("AndroidKeyStore"));
|
||||
|
||||
if (!keyStore || !keyStore.load()) {
|
||||
q->emitFinishedWithError(Error::AccessDenied, tr("Could not open keystore"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &alias = makeAlias(q->service(), q->key());
|
||||
if (!keyStore.deleteEntry(alias)) {
|
||||
q->emitFinishedWithError(Error::OtherError, tr("Could not remove private key from keystore"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlainTextStore plainTextStore(q->service(), q->settings());
|
||||
plainTextStore.remove(q->key());
|
||||
|
||||
if (plainTextStore.error() != NoError)
|
||||
q->emitFinishedWithError(plainTextStore.error(), plainTextStore.errorString());
|
||||
else
|
||||
q->emitFinished();
|
||||
}
|
||||
|
||||
bool QKeychain::isAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -1,263 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
|
||||
* *
|
||||
* 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. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "keychain_p.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Security/Security.h>
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
struct ErrorDescription
|
||||
{
|
||||
QKeychain::Error code;
|
||||
QString message;
|
||||
|
||||
ErrorDescription(QKeychain::Error code, const QString &message)
|
||||
: code(code), message(message) {}
|
||||
|
||||
static ErrorDescription fromStatus(OSStatus status)
|
||||
{
|
||||
switch(status) {
|
||||
case errSecSuccess:
|
||||
return ErrorDescription(QKeychain::NoError, Job::tr("No error"));
|
||||
case errSecItemNotFound:
|
||||
return ErrorDescription(QKeychain::EntryNotFound, Job::tr("The specified item could not be found in the keychain"));
|
||||
case errSecUserCanceled:
|
||||
return ErrorDescription(QKeychain::AccessDeniedByUser, Job::tr("User canceled the operation"));
|
||||
case errSecInteractionNotAllowed:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("User interaction is not allowed"));
|
||||
case errSecNotAvailable:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("No keychain is available. You may need to restart your computer"));
|
||||
case errSecAuthFailed:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("The user name or passphrase you entered is not correct"));
|
||||
case errSecVerifyFailed:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("A cryptographic verification failure has occurred"));
|
||||
case errSecUnimplemented:
|
||||
return ErrorDescription(QKeychain::NotImplemented, Job::tr("Function or operation not implemented"));
|
||||
case errSecIO:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("I/O error"));
|
||||
case errSecOpWr:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Already open with with write permission"));
|
||||
case errSecParam:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Invalid parameters passed to a function"));
|
||||
case errSecAllocate:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Failed to allocate memory"));
|
||||
case errSecBadReq:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Bad parameter or invalid state for operation"));
|
||||
case errSecInternalComponent:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("An internal component failed"));
|
||||
case errSecDuplicateItem:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("The specified item already exists in the keychain"));
|
||||
case errSecDecode:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Unable to decode the provided data"));
|
||||
}
|
||||
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Unknown error"));
|
||||
}
|
||||
};
|
||||
|
||||
@interface AppleKeychainInterface : NSObject
|
||||
|
||||
- (instancetype)initWithJob:(Job *)job andPrivateJob:(JobPrivate *)privateJob;
|
||||
- (void)keychainTaskFinished;
|
||||
- (void)keychainReadTaskFinished:(NSData *)retrievedData;
|
||||
- (void)keychainTaskFinishedWithError:(OSStatus)status descriptiveMessage:(NSString *)descriptiveMessage;
|
||||
|
||||
@end
|
||||
|
||||
@interface AppleKeychainInterface()
|
||||
{
|
||||
QPointer<Job> _job;
|
||||
QPointer<JobPrivate> _privateJob;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation AppleKeychainInterface
|
||||
|
||||
- (instancetype)initWithJob:(Job *)job andPrivateJob:(JobPrivate *)privateJob
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_job = job;
|
||||
_privateJob = privateJob;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)keychainTaskFinished
|
||||
{
|
||||
if (_job) {
|
||||
_job->emitFinished();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keychainReadTaskFinished:(NSData *)retrievedData
|
||||
{
|
||||
_privateJob->data.clear();
|
||||
_privateJob->mode = JobPrivate::Binary;
|
||||
|
||||
if (retrievedData != nil) {
|
||||
if (_privateJob) {
|
||||
_privateJob->data = QByteArray::fromNSData(retrievedData);
|
||||
}
|
||||
}
|
||||
|
||||
if (_job) {
|
||||
_job->emitFinished();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keychainTaskFinishedWithError:(OSStatus)status descriptiveMessage:(NSString *)descriptiveMessage
|
||||
{
|
||||
const auto localisedDescriptiveMessage = Job::tr([descriptiveMessage UTF8String]);
|
||||
|
||||
const ErrorDescription error = ErrorDescription::fromStatus(status);
|
||||
const auto fullMessage = localisedDescriptiveMessage.isEmpty() ? error.message : QStringLiteral("%1: %2").arg(localisedDescriptiveMessage, error.message);
|
||||
|
||||
if (_job) {
|
||||
_job->emitFinishedWithError(error.code, fullMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
static void StartReadPassword(const QString &service, const QString &key, AppleKeychainInterface * const interface)
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
|
||||
NSDictionary * const query = @{
|
||||
(__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
|
||||
(__bridge NSString *)kSecAttrService: service.toNSString(),
|
||||
(__bridge NSString *)kSecAttrAccount: key.toNSString(),
|
||||
(__bridge NSString *)kSecReturnData: @YES,
|
||||
};
|
||||
|
||||
CFTypeRef dataRef = nil;
|
||||
const OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &dataRef);
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
const CFDataRef castedDataRef = (CFDataRef)dataRef;
|
||||
NSData * const data = (__bridge NSData *)castedDataRef;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[interface keychainReadTaskFinished:data];
|
||||
[interface release];
|
||||
});
|
||||
} else {
|
||||
NSString * const descriptiveErrorString = @"Could not retrieve private key from keystore";
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[interface keychainTaskFinishedWithError:status descriptiveMessage:descriptiveErrorString];
|
||||
[interface release];
|
||||
});
|
||||
}
|
||||
|
||||
if (dataRef) {
|
||||
CFRelease(dataRef);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void StartWritePassword(const QString &service, const QString &key, const QByteArray &data, AppleKeychainInterface * const interface)
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
|
||||
NSDictionary * const query = @{
|
||||
(__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
|
||||
(__bridge NSString *)kSecAttrService: service.toNSString(),
|
||||
(__bridge NSString *)kSecAttrAccount: key.toNSString(),
|
||||
};
|
||||
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, nil);
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
NSDictionary * const update = @{
|
||||
(__bridge NSString *)kSecValueData: data.toNSData(),
|
||||
};
|
||||
|
||||
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);
|
||||
} else {
|
||||
NSDictionary * const insert = @{
|
||||
(__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
|
||||
(__bridge NSString *)kSecAttrService: service.toNSString(),
|
||||
(__bridge NSString *)kSecAttrAccount: key.toNSString(),
|
||||
(__bridge NSString *)kSecValueData: data.toNSData(),
|
||||
};
|
||||
|
||||
status = SecItemAdd((__bridge const CFDictionaryRef)insert, nil);
|
||||
}
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[interface keychainTaskFinished];
|
||||
[interface release];
|
||||
});
|
||||
} else {
|
||||
NSString * const descriptiveErrorString = @"Could not store data in settings";
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[interface keychainTaskFinishedWithError:status descriptiveMessage:descriptiveErrorString];
|
||||
[interface release];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void StartDeletePassword(const QString &service, const QString &key, AppleKeychainInterface * const interface)
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
|
||||
NSDictionary * const query = @{
|
||||
(__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
|
||||
(__bridge NSString *)kSecAttrService: service.toNSString(),
|
||||
(__bridge NSString *)kSecAttrAccount: key.toNSString(),
|
||||
};
|
||||
|
||||
const OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[interface keychainTaskFinished];
|
||||
[interface release];
|
||||
});
|
||||
} else {
|
||||
NSString * const descriptiveErrorString = @"Could not remove private key from keystore";
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[interface keychainTaskFinishedWithError:status descriptiveMessage:descriptiveErrorString];
|
||||
[interface release];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ReadPasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
AppleKeychainInterface * const interface = [[AppleKeychainInterface alloc] initWithJob:q andPrivateJob:this];
|
||||
StartReadPassword(service, key, interface);
|
||||
}
|
||||
|
||||
void WritePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
AppleKeychainInterface * const interface = [[AppleKeychainInterface alloc] initWithJob:q andPrivateJob:this];
|
||||
StartWritePassword(service, key, data, interface);
|
||||
}
|
||||
|
||||
void DeletePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
AppleKeychainInterface * const interface = [[AppleKeychainInterface alloc] initWithJob:q andPrivateJob:this];
|
||||
StartDeletePassword(service, key, interface);
|
||||
}
|
||||
|
||||
bool QKeychain::isAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -1,192 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2018 François Revol <revol@free.fr> *
|
||||
* *
|
||||
* 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. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
#include "keychain_p.h"
|
||||
|
||||
#include <KeyStore.h>
|
||||
|
||||
#include <Application.h>
|
||||
#include <AppFileInfo.h>
|
||||
#include <File.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
class AutoApp {
|
||||
public:
|
||||
AutoApp();
|
||||
~AutoApp();
|
||||
BApplication *app;
|
||||
};
|
||||
|
||||
|
||||
AutoApp::AutoApp()
|
||||
: app(nullptr)
|
||||
{
|
||||
if (be_app)
|
||||
return;
|
||||
|
||||
// no BApplication object, probably using QCoreApplication
|
||||
// but we need one around
|
||||
|
||||
QString appSignature;
|
||||
|
||||
char signature[B_MIME_TYPE_LENGTH];
|
||||
signature[0] = '\0';
|
||||
|
||||
QString appPath = QCoreApplication::applicationFilePath();
|
||||
|
||||
BFile appFile(appPath.toUtf8(), B_READ_ONLY);
|
||||
if (appFile.InitCheck() == B_OK) {
|
||||
BAppFileInfo info(&appFile);
|
||||
if (info.InitCheck() == B_OK) {
|
||||
if (info.GetSignature(signature) != B_OK)
|
||||
signature[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (signature[0] != '\0')
|
||||
appSignature = QLatin1String(signature);
|
||||
else
|
||||
appSignature = QLatin1String("application/x-vnd.qtkeychain-") +
|
||||
QCoreApplication::applicationName().remove("_x86");
|
||||
|
||||
app = new BApplication(appSignature.toUtf8().constData());
|
||||
}
|
||||
|
||||
AutoApp::~AutoApp()
|
||||
{
|
||||
delete app;
|
||||
}
|
||||
|
||||
static QString strForStatus( status_t os ) {
|
||||
const char * const buf = strerror(os) ;
|
||||
return QObject::tr( "error 0x%1: %2" )
|
||||
.arg( os, 8, 16 ).arg( QString::fromUtf8( buf, strlen( buf ) ) );
|
||||
}
|
||||
|
||||
void ReadPasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
AutoApp aa;
|
||||
QString errorString;
|
||||
Error error = NoError;
|
||||
BKeyStore keyStore;
|
||||
BPasswordKey password;
|
||||
|
||||
status_t result = keyStore.GetKey(B_KEY_TYPE_PASSWORD,
|
||||
q->service().toUtf8().constData(),
|
||||
q->key().toUtf8().constData(),
|
||||
false, password);
|
||||
|
||||
data = QByteArray(reinterpret_cast<const char*>(password.Data()), password.DataLength());
|
||||
|
||||
switch ( result ) {
|
||||
case B_OK:
|
||||
q->emitFinished();
|
||||
return;
|
||||
case B_ENTRY_NOT_FOUND:
|
||||
errorString = tr("Password not found");
|
||||
error = EntryNotFound;
|
||||
break;
|
||||
default:
|
||||
errorString = strForStatus( result );
|
||||
error = OtherError;
|
||||
break;
|
||||
}
|
||||
|
||||
q->emitFinishedWithError( error, errorString );
|
||||
}
|
||||
|
||||
void WritePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
AutoApp aa;
|
||||
QString errorString;
|
||||
Error error = NoError;
|
||||
BKeyStore keyStore;
|
||||
BPasswordKey password(data.constData(),
|
||||
B_KEY_PURPOSE_GENERIC,
|
||||
q->service().toUtf8().constData(),
|
||||
q->key().toUtf8().constData());
|
||||
status_t result = B_OK;
|
||||
|
||||
// re-add as binary if it's not text
|
||||
if (mode == Binary)
|
||||
result = password.SetData(reinterpret_cast<const uint8*>(data.constData()), data.size());
|
||||
|
||||
if (result == B_OK)
|
||||
result = keyStore.AddKey(password);
|
||||
|
||||
if (result == B_NAME_IN_USE) {
|
||||
BPasswordKey old_password;
|
||||
result = keyStore.GetKey(B_KEY_TYPE_PASSWORD,
|
||||
q->service().toUtf8().constData(),
|
||||
q->key().toUtf8().constData(),
|
||||
false, old_password);
|
||||
if (result == B_OK)
|
||||
result = keyStore.RemoveKey(old_password);
|
||||
if (result == B_OK)
|
||||
result = keyStore.AddKey(password);
|
||||
}
|
||||
|
||||
switch ( result ) {
|
||||
case B_OK:
|
||||
q->emitFinished();
|
||||
return;
|
||||
case B_ENTRY_NOT_FOUND:
|
||||
errorString = tr("Password not found");
|
||||
error = EntryNotFound;
|
||||
break;
|
||||
default:
|
||||
errorString = strForStatus( result );
|
||||
error = OtherError;
|
||||
break;
|
||||
}
|
||||
|
||||
q->emitFinishedWithError( error, errorString );
|
||||
}
|
||||
|
||||
void DeletePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
AutoApp aa;
|
||||
QString errorString;
|
||||
Error error = NoError;
|
||||
BKeyStore keyStore;
|
||||
BPasswordKey password;
|
||||
|
||||
status_t result = keyStore.GetKey(B_KEY_TYPE_PASSWORD,
|
||||
q->service().toUtf8().constData(),
|
||||
q->key().toUtf8().constData(),
|
||||
false, password);
|
||||
|
||||
if (result == B_OK)
|
||||
result = keyStore.RemoveKey(password);
|
||||
|
||||
switch ( result ) {
|
||||
case B_OK:
|
||||
q->emitFinished();
|
||||
return;
|
||||
case B_ENTRY_NOT_FOUND:
|
||||
errorString = tr("Password not found");
|
||||
error = EntryNotFound;
|
||||
break;
|
||||
default:
|
||||
errorString = strForStatus( result );
|
||||
error = CouldNotDeleteEntry;
|
||||
break;
|
||||
}
|
||||
|
||||
q->emitFinishedWithError( error, errorString );
|
||||
}
|
||||
|
||||
bool QKeychain::isAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
146
client/qtkeychain/keychain_ios.mm
Normal file
146
client/qtkeychain/keychain_ios.mm
Normal file
@ -0,0 +1,146 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
|
||||
* *
|
||||
* 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. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
|
||||
#include "keychain_p.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Security/Security.h>
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
struct ErrorDescription
|
||||
{
|
||||
QKeychain::Error code;
|
||||
QString message;
|
||||
|
||||
ErrorDescription(QKeychain::Error code, const QString &message)
|
||||
: code(code), message(message) {}
|
||||
|
||||
static ErrorDescription fromStatus(OSStatus status)
|
||||
{
|
||||
switch(status) {
|
||||
case errSecSuccess:
|
||||
return ErrorDescription(QKeychain::NoError, Job::tr("No error"));
|
||||
case errSecItemNotFound:
|
||||
return ErrorDescription(QKeychain::EntryNotFound, Job::tr("The specified item could not be found in the keychain"));
|
||||
case errSecUserCanceled:
|
||||
return ErrorDescription(QKeychain::AccessDeniedByUser, Job::tr("User canceled the operation"));
|
||||
case errSecInteractionNotAllowed:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("User interaction is not allowed"));
|
||||
case errSecNotAvailable:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("No keychain is available. You may need to restart your computer"));
|
||||
case errSecAuthFailed:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("The user name or passphrase you entered is not correct"));
|
||||
case errSecVerifyFailed:
|
||||
return ErrorDescription(QKeychain::AccessDenied, Job::tr("A cryptographic verification failure has occurred"));
|
||||
case errSecUnimplemented:
|
||||
return ErrorDescription(QKeychain::NotImplemented, Job::tr("Function or operation not implemented"));
|
||||
case errSecIO:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("I/O error"));
|
||||
case errSecOpWr:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Already open with with write permission"));
|
||||
case errSecParam:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Invalid parameters passed to a function"));
|
||||
case errSecAllocate:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Failed to allocate memory"));
|
||||
case errSecBadReq:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Bad parameter or invalid state for operation"));
|
||||
case errSecInternalComponent:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("An internal component failed"));
|
||||
case errSecDuplicateItem:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("The specified item already exists in the keychain"));
|
||||
case errSecDecode:
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Unable to decode the provided data"));
|
||||
}
|
||||
|
||||
return ErrorDescription(QKeychain::OtherError, Job::tr("Unknown error"));
|
||||
}
|
||||
};
|
||||
|
||||
void ReadPasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
NSDictionary *const query = @{
|
||||
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
|
||||
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
|
||||
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
|
||||
(__bridge id) kSecReturnData: @YES,
|
||||
};
|
||||
|
||||
CFTypeRef dataRef = nil;
|
||||
const OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &dataRef);
|
||||
|
||||
data.clear();
|
||||
mode = Binary;
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
if (dataRef)
|
||||
data = QByteArray::fromCFData((CFDataRef) dataRef);
|
||||
|
||||
q->emitFinished();
|
||||
} else {
|
||||
const ErrorDescription error = ErrorDescription::fromStatus(status);
|
||||
q->emitFinishedWithError(error.code, Job::tr("Could not retrieve private key from keystore: %1").arg(error.message));
|
||||
}
|
||||
|
||||
if (dataRef)
|
||||
[dataRef release];
|
||||
}
|
||||
|
||||
void WritePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
NSDictionary *const query = @{
|
||||
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
|
||||
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
|
||||
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
|
||||
};
|
||||
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, nil);
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
NSDictionary *const update = @{
|
||||
(__bridge id) kSecValueData: (__bridge NSData *) data.toCFData(),
|
||||
};
|
||||
|
||||
status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef) update);
|
||||
} else {
|
||||
NSDictionary *const insert = @{
|
||||
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
|
||||
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
|
||||
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
|
||||
(__bridge id) kSecValueData: (__bridge NSData *) data.toCFData(),
|
||||
};
|
||||
|
||||
status = SecItemAdd((__bridge CFDictionaryRef) insert, nil);
|
||||
}
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
q->emitFinished();
|
||||
} else {
|
||||
const ErrorDescription error = ErrorDescription::fromStatus(status);
|
||||
q->emitFinishedWithError(error.code, tr("Could not store data in settings: %1").arg(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
void DeletePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
const NSDictionary *const query = @{
|
||||
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
|
||||
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
|
||||
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
|
||||
};
|
||||
|
||||
const OSStatus status = SecItemDelete((__bridge CFDictionaryRef) query);
|
||||
|
||||
if (status == errSecSuccess) {
|
||||
q->emitFinished();
|
||||
} else {
|
||||
const ErrorDescription error = ErrorDescription::fromStatus(status);
|
||||
q->emitFinishedWithError(error.code, Job::tr("Could not remove private key from keystore: %1").arg(error.message));
|
||||
}
|
||||
}
|
||||
163
client/qtkeychain/keychain_mac.cpp
Normal file
163
client/qtkeychain/keychain_mac.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
|
||||
* *
|
||||
* 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. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
#include "keychain_p.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
#include <QDebug>
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
template <typename T>
|
||||
struct Releaser {
|
||||
explicit Releaser( const T& v ) : value( v ) {}
|
||||
~Releaser() {
|
||||
CFRelease( value );
|
||||
}
|
||||
|
||||
const T value;
|
||||
};
|
||||
|
||||
static QString strForStatus( OSStatus os ) {
|
||||
const Releaser<CFStringRef> str( SecCopyErrorMessageString( os, 0 ) );
|
||||
const char * const buf = CFStringGetCStringPtr( str.value, kCFStringEncodingUTF8 );
|
||||
if ( !buf )
|
||||
return QObject::tr( "OS X Keychain error (OSStatus %1)" ).arg( os );
|
||||
return QObject::tr( "%1 (OSStatus %2)" )
|
||||
.arg( QString::fromUtf8( buf, strlen( buf ) ) ).arg( os );
|
||||
}
|
||||
|
||||
static OSStatus readPw( QByteArray* pw,
|
||||
const QString& service,
|
||||
const QString& account,
|
||||
SecKeychainItemRef* ref ) {
|
||||
Q_ASSERT( pw );
|
||||
pw->clear();
|
||||
const QByteArray serviceData = service.toUtf8();
|
||||
const QByteArray accountData = account.toUtf8();
|
||||
|
||||
void* data = 0;
|
||||
UInt32 len = 0;
|
||||
|
||||
const OSStatus ret = SecKeychainFindGenericPassword( NULL, // default keychain
|
||||
serviceData.size(),
|
||||
serviceData.constData(),
|
||||
accountData.size(),
|
||||
accountData.constData(),
|
||||
&len,
|
||||
&data,
|
||||
ref );
|
||||
if ( ret == noErr ) {
|
||||
*pw = QByteArray( reinterpret_cast<const char*>( data ), len );
|
||||
const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data );
|
||||
if ( ret2 != noErr )
|
||||
qWarning() << "Could not free item content: " << strForStatus( ret2 );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ReadPasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
QString errorString;
|
||||
Error error = NoError;
|
||||
const OSStatus ret = readPw( &data, q->service(), q->key(), 0 );
|
||||
|
||||
switch ( ret ) {
|
||||
case noErr:
|
||||
break;
|
||||
case errSecItemNotFound:
|
||||
errorString = tr("Password not found");
|
||||
error = EntryNotFound;
|
||||
break;
|
||||
default:
|
||||
errorString = strForStatus( ret );
|
||||
error = OtherError;
|
||||
break;
|
||||
}
|
||||
q->emitFinishedWithError( error, errorString );
|
||||
}
|
||||
|
||||
|
||||
static QKeychain::Error deleteEntryImpl( const QString& service, const QString& account, QString* err ) {
|
||||
SecKeychainItemRef ref;
|
||||
QByteArray pw;
|
||||
const OSStatus ret1 = readPw( &pw, service, account, &ref );
|
||||
if ( ret1 == errSecItemNotFound )
|
||||
return NoError; // No item stored, we're done
|
||||
if ( ret1 != noErr ) {
|
||||
*err = strForStatus( ret1 );
|
||||
//TODO map error code, set errstr
|
||||
return OtherError;
|
||||
}
|
||||
const Releaser<SecKeychainItemRef> releaser( ref );
|
||||
|
||||
const OSStatus ret2 = SecKeychainItemDelete( ref );
|
||||
|
||||
if ( ret2 == noErr )
|
||||
return NoError;
|
||||
//TODO map error code
|
||||
*err = strForStatus( ret2 );
|
||||
return CouldNotDeleteEntry;
|
||||
}
|
||||
|
||||
static QKeychain::Error writeEntryImpl( const QString& service,
|
||||
const QString& account,
|
||||
const QByteArray& data,
|
||||
QString* err ) {
|
||||
Q_ASSERT( err );
|
||||
err->clear();
|
||||
const QByteArray serviceData = service.toUtf8();
|
||||
const QByteArray accountData = account.toUtf8();
|
||||
const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain
|
||||
serviceData.size(),
|
||||
serviceData.constData(),
|
||||
accountData.size(),
|
||||
accountData.constData(),
|
||||
data.size(),
|
||||
data.constData(),
|
||||
NULL //item reference
|
||||
);
|
||||
if ( ret != noErr ) {
|
||||
switch ( ret ) {
|
||||
case errSecDuplicateItem:
|
||||
{
|
||||
Error derr = deleteEntryImpl( service, account, err );
|
||||
if ( derr != NoError )
|
||||
return CouldNotDeleteEntry;
|
||||
else
|
||||
return writeEntryImpl( service, account, data, err );
|
||||
}
|
||||
default:
|
||||
*err = strForStatus( ret );
|
||||
return OtherError;
|
||||
}
|
||||
}
|
||||
|
||||
return NoError;
|
||||
}
|
||||
|
||||
void WritePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
QString errorString;
|
||||
Error error = NoError;
|
||||
|
||||
error = writeEntryImpl( q->service(), key, data, &errorString );
|
||||
q->emitFinishedWithError( error, errorString );
|
||||
}
|
||||
|
||||
void DeletePasswordJobPrivate::scheduledStart()
|
||||
{
|
||||
QString errorString;
|
||||
Error error = NoError;
|
||||
|
||||
const Error derr = deleteEntryImpl( q->service(), key, &errorString );
|
||||
if ( derr != NoError )
|
||||
error = CouldNotDeleteEntry;
|
||||
q->emitFinishedWithError( error, errorString );
|
||||
}
|
||||
@ -15,7 +15,7 @@
|
||||
#include <QSettings>
|
||||
#include <QQueue>
|
||||
|
||||
#if defined(KEYCHAIN_DBUS)
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
|
||||
|
||||
#include <QDBusPendingCallWatcher>
|
||||
|
||||
@ -49,7 +49,7 @@ public:
|
||||
Mode mode;
|
||||
QByteArray data;
|
||||
|
||||
#if defined(KEYCHAIN_DBUS)
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
|
||||
org::kde::KWallet* iface;
|
||||
int walletHandle;
|
||||
|
||||
@ -91,20 +91,20 @@ class ReadPasswordJobPrivate : public JobPrivate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ReadPasswordJobPrivate( const QString &service_, ReadPasswordJob* qq );
|
||||
void scheduledStart() override;
|
||||
void scheduledStart();
|
||||
|
||||
#if defined(KEYCHAIN_DBUS)
|
||||
void fallbackOnError(const QDBusError& err) override;
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
|
||||
void fallbackOnError(const QDBusError& err);
|
||||
|
||||
private Q_SLOTS:
|
||||
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) override;
|
||||
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
|
||||
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher );
|
||||
void kwalletFinished( QDBusPendingCallWatcher* watcher ) override;
|
||||
void kwalletFinished( QDBusPendingCallWatcher* watcher );
|
||||
#else //moc's too dumb to respect above macros, so just define empty slot implementations
|
||||
private Q_SLOTS:
|
||||
void kwalletOpenFinished( QDBusPendingCallWatcher* ) override {}
|
||||
void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
|
||||
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* ) {}
|
||||
void kwalletFinished( QDBusPendingCallWatcher* ) override {}
|
||||
void kwalletFinished( QDBusPendingCallWatcher* ) {}
|
||||
#endif
|
||||
|
||||
friend class ReadPasswordJob;
|
||||
@ -114,10 +114,10 @@ class WritePasswordJobPrivate : public JobPrivate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WritePasswordJobPrivate( const QString &service_, WritePasswordJob* qq );
|
||||
void scheduledStart() override;
|
||||
void scheduledStart();
|
||||
|
||||
#if defined(KEYCHAIN_DBUS)
|
||||
void fallbackOnError(const QDBusError& err) override;
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
|
||||
void fallbackOnError(const QDBusError& err);
|
||||
#endif
|
||||
|
||||
friend class WritePasswordJob;
|
||||
@ -128,10 +128,10 @@ class DeletePasswordJobPrivate : public JobPrivate {
|
||||
public:
|
||||
explicit DeletePasswordJobPrivate( const QString &service_, DeletePasswordJob* qq );
|
||||
|
||||
void scheduledStart() override;
|
||||
void scheduledStart();
|
||||
|
||||
#if defined(KEYCHAIN_DBUS)
|
||||
void fallbackOnError(const QDBusError& err) override;
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
|
||||
void fallbackOnError(const QDBusError& err);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
@ -19,35 +19,24 @@ enum KeyringBackend {
|
||||
Backend_LibSecretKeyring,
|
||||
Backend_GnomeKeyring,
|
||||
Backend_Kwallet4,
|
||||
Backend_Kwallet5,
|
||||
Backend_Kwallet6,
|
||||
Backend_Kwallet5
|
||||
};
|
||||
|
||||
enum DesktopEnvironment {
|
||||
DesktopEnv_Gnome,
|
||||
DesktopEnv_Kde4,
|
||||
DesktopEnv_Plasma5,
|
||||
DesktopEnv_Plasma6,
|
||||
DesktopEnv_Unity,
|
||||
DesktopEnv_Xfce,
|
||||
DesktopEnv_Other
|
||||
};
|
||||
|
||||
static constexpr const char KWALLET6_DBUS_IFACE[] = "org.kde.kwalletd6";
|
||||
static constexpr const char KWALLET6_DBUS_PATH[] = "/modules/kwalletd6";
|
||||
static constexpr const char KWALLET5_DBUS_IFACE[] = "org.kde.kwalletd5";
|
||||
static constexpr const char KWALLET5_DBUS_PATH[] = "/modules/kwalletd5";
|
||||
static constexpr const char KWALLET4_DBUS_IFACE[] = "org.kde.kwalletd";
|
||||
static constexpr const char KWALLET4_DBUS_PATH[] = "/modules/kwalletd";
|
||||
|
||||
// the following detection algorithm is derived from chromium,
|
||||
// licensed under BSD, see base/nix/xdg_util.cc
|
||||
|
||||
static DesktopEnvironment getKdeVersion() {
|
||||
QByteArray value = qgetenv("KDE_SESSION_VERSION");
|
||||
if ( value == "6" ) {
|
||||
return DesktopEnv_Plasma6;
|
||||
} else if ( value == "5" ) {
|
||||
if ( value == "5" ) {
|
||||
return DesktopEnv_Plasma5;
|
||||
} else if (value == "4" ) {
|
||||
return DesktopEnv_Kde4;
|
||||
@ -89,14 +78,14 @@ static DesktopEnvironment detectDesktopEnvironment() {
|
||||
return DesktopEnv_Other;
|
||||
}
|
||||
|
||||
static bool isKwalletAvailable(const char *dbusIface, const char *dbusPath)
|
||||
static bool isKwallet5Available()
|
||||
{
|
||||
if (!QDBusConnection::sessionBus().isConnected())
|
||||
return false;
|
||||
|
||||
org::kde::KWallet iface(
|
||||
QLatin1String(dbusIface),
|
||||
QLatin1String(dbusPath),
|
||||
QLatin1String("org.kde.kwalletd5"),
|
||||
QLatin1String("/modules/kwalletd5"),
|
||||
QDBusConnection::sessionBus());
|
||||
|
||||
// At this point iface.isValid() can return false even though the
|
||||
@ -104,7 +93,7 @@ static bool isKwalletAvailable(const char *dbusIface, const char *dbusPath)
|
||||
// a wallet can be opened.
|
||||
|
||||
iface.setTimeout(500);
|
||||
QDBusMessage reply = iface.call(QLatin1String("networkWallet"));
|
||||
QDBusMessage reply = iface.call(QStringLiteral("networkWallet"));
|
||||
return reply.type() == QDBusMessage::ReplyMessage;
|
||||
}
|
||||
|
||||
@ -129,7 +118,7 @@ static KeyringBackend detectKeyringBackend()
|
||||
return Backend_Kwallet4;
|
||||
|
||||
case DesktopEnv_Plasma5:
|
||||
if (isKwalletAvailable(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH)) {
|
||||
if (isKwallet5Available()) {
|
||||
return Backend_Kwallet5;
|
||||
}
|
||||
if (LibSecretKeyring::isAvailable()) {
|
||||
@ -141,19 +130,6 @@ static KeyringBackend detectKeyringBackend()
|
||||
// During startup the keychain backend might just not have started yet
|
||||
return Backend_Kwallet5;
|
||||
|
||||
case DesktopEnv_Plasma6:
|
||||
if (isKwalletAvailable(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH)) {
|
||||
return Backend_Kwallet6;
|
||||
}
|
||||
if (LibSecretKeyring::isAvailable()) {
|
||||
return Backend_LibSecretKeyring;
|
||||
}
|
||||
if (GnomeKeyring::isAvailable()) {
|
||||
return Backend_GnomeKeyring;
|
||||
}
|
||||
// During startup the keychain backend might just not have started yet
|
||||
return Backend_Kwallet6;
|
||||
|
||||
case DesktopEnv_Gnome:
|
||||
case DesktopEnv_Unity:
|
||||
case DesktopEnv_Xfce:
|
||||
@ -165,10 +141,7 @@ static KeyringBackend detectKeyringBackend()
|
||||
if (GnomeKeyring::isAvailable()) {
|
||||
return Backend_GnomeKeyring;
|
||||
}
|
||||
if (isKwalletAvailable(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH)) {
|
||||
return Backend_Kwallet6;
|
||||
}
|
||||
if (isKwalletAvailable(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH)) {
|
||||
if (isKwallet5Available()) {
|
||||
return Backend_Kwallet5;
|
||||
}
|
||||
// During startup the keychain backend might just not have started yet
|
||||
@ -225,13 +198,10 @@ void ReadPasswordJobPrivate::scheduledStart() {
|
||||
break;
|
||||
|
||||
case Backend_Kwallet4:
|
||||
kwalletReadPasswordScheduledStartImpl(KWALLET4_DBUS_IFACE, KWALLET4_DBUS_PATH, this);
|
||||
kwalletReadPasswordScheduledStartImpl("org.kde.kwalletd", "/modules/kwalletd", this);
|
||||
break;
|
||||
case Backend_Kwallet5:
|
||||
kwalletReadPasswordScheduledStartImpl(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH, this);
|
||||
break;
|
||||
case Backend_Kwallet6:
|
||||
kwalletReadPasswordScheduledStartImpl(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH, this);
|
||||
kwalletReadPasswordScheduledStartImpl("org.kde.kwalletd5", "/modules/kwalletd5", this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -484,13 +454,10 @@ void WritePasswordJobPrivate::scheduledStart() {
|
||||
break;
|
||||
|
||||
case Backend_Kwallet4:
|
||||
kwalletWritePasswordScheduledStart(KWALLET4_DBUS_IFACE, KWALLET4_DBUS_PATH, this);
|
||||
kwalletWritePasswordScheduledStart("org.kde.kwalletd", "/modules/kwalletd", this);
|
||||
break;
|
||||
case Backend_Kwallet5:
|
||||
kwalletWritePasswordScheduledStart(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH, this);
|
||||
break;
|
||||
case Backend_Kwallet6:
|
||||
kwalletWritePasswordScheduledStart(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH, this);
|
||||
kwalletWritePasswordScheduledStart("org.kde.kwalletd5", "/modules/kwalletd5", this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -545,16 +512,12 @@ void JobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
|
||||
|
||||
QDBusPendingReply<int> nextReply;
|
||||
|
||||
if ( !data.isNull() ) {
|
||||
if ( mode == Text ) {
|
||||
nextReply = iface->writePassword( handle, q->service(), key, QString::fromUtf8(data), q->service() );
|
||||
} else {
|
||||
Q_ASSERT( mode == Binary );
|
||||
nextReply = iface->writeEntry( handle, q->service(), key, data, q->service() );
|
||||
}
|
||||
} else {
|
||||
if ( mode == Text )
|
||||
nextReply = iface->writePassword( handle, q->service(), key, QString::fromUtf8(data), q->service() );
|
||||
else if ( mode == Binary )
|
||||
nextReply = iface->writeEntry( handle, q->service(), key, data, q->service() );
|
||||
else
|
||||
nextReply = iface->removeEntry( handle, q->service(), key, q->service() );
|
||||
}
|
||||
|
||||
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
|
||||
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletFinished(QDBusPendingCallWatcher*)) );
|
||||
@ -595,13 +558,10 @@ void DeletePasswordJobPrivate::scheduledStart() {
|
||||
break;
|
||||
|
||||
case Backend_Kwallet4:
|
||||
kwalletWritePasswordScheduledStart(KWALLET4_DBUS_IFACE, KWALLET4_DBUS_PATH, this);
|
||||
kwalletWritePasswordScheduledStart("org.kde.kwalletd", "/modules/kwalletd", this);
|
||||
break;
|
||||
case Backend_Kwallet5:
|
||||
kwalletWritePasswordScheduledStart(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH, this);
|
||||
break;
|
||||
case Backend_Kwallet6:
|
||||
kwalletWritePasswordScheduledStart(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH, this);
|
||||
kwalletWritePasswordScheduledStart("org.kde.kwalletd5", "/modules/kwalletd5", this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -624,10 +584,3 @@ void DeletePasswordJobPrivate::fallbackOnError(const QDBusError &err) {
|
||||
|
||||
q->emitFinished();
|
||||
}
|
||||
|
||||
bool QKeychain::isAvailable()
|
||||
{
|
||||
return LibSecretKeyring::isAvailable() || GnomeKeyring::isAvailable()
|
||||
|| isKwalletAvailable(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH)
|
||||
|| isKwalletAvailable(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH);
|
||||
}
|
||||
|
||||
@ -24,20 +24,20 @@ void ReadPasswordJobPrivate::scheduledStart() {
|
||||
PCREDENTIALW cred;
|
||||
|
||||
if (!CredReadW(name, CRED_TYPE_GENERIC, 0, &cred)) {
|
||||
Error err;
|
||||
Error error;
|
||||
QString msg;
|
||||
switch(GetLastError()) {
|
||||
case ERROR_NOT_FOUND:
|
||||
err = EntryNotFound;
|
||||
error = EntryNotFound;
|
||||
msg = tr("Password entry not found");
|
||||
break;
|
||||
default:
|
||||
err = OtherError;
|
||||
error = OtherError;
|
||||
msg = tr("Could not decrypt data");
|
||||
break;
|
||||
}
|
||||
|
||||
q->emitFinishedWithError( err, msg );
|
||||
q->emitFinishedWithError( error, msg );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -96,20 +96,20 @@ void DeletePasswordJobPrivate::scheduledStart() {
|
||||
LPCWSTR name = (LPCWSTR)key.utf16();
|
||||
|
||||
if (!CredDeleteW(name, CRED_TYPE_GENERIC, 0)) {
|
||||
Error err;
|
||||
Error error;
|
||||
QString msg;
|
||||
switch(GetLastError()) {
|
||||
case ERROR_NOT_FOUND:
|
||||
err = EntryNotFound;
|
||||
error = EntryNotFound;
|
||||
msg = tr("Password entry not found");
|
||||
break;
|
||||
default:
|
||||
err = OtherError;
|
||||
error = OtherError;
|
||||
msg = tr("Could not decrypt data");
|
||||
break;
|
||||
}
|
||||
|
||||
q->emitFinishedWithError( err, msg );
|
||||
q->emitFinishedWithError( error, msg );
|
||||
} else {
|
||||
q->emitFinished();
|
||||
}
|
||||
@ -129,10 +129,10 @@ void ReadPasswordJobPrivate::scheduledStart() {
|
||||
blob_in.cbData = encrypted.size();
|
||||
|
||||
const BOOL ret = CryptUnprotectData( &blob_in,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
&blob_out );
|
||||
if ( !ret ) {
|
||||
@ -153,9 +153,9 @@ void WritePasswordJobPrivate::scheduledStart() {
|
||||
blob_in.cbData = data.size();
|
||||
const BOOL res = CryptProtectData( &blob_in,
|
||||
L"QKeychain-encrypted data",
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
&blob_out );
|
||||
if ( !res ) {
|
||||
@ -186,8 +186,3 @@ void DeletePasswordJobPrivate::scheduledStart() {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool QKeychain::isAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "libsecret_p.h"
|
||||
|
||||
#include <QLibrary>
|
||||
#include <QDebug>
|
||||
|
||||
#if defined(HAVE_LIBSECRET)
|
||||
const SecretSchema* qtkeychainSchema(void) {
|
||||
@ -53,14 +54,14 @@ typedef gboolean (*secret_password_clear_finish_t) (GAsyncResult *result,
|
||||
typedef void (*secret_password_free_t) (gchar *password);
|
||||
typedef GQuark (*secret_error_get_quark_t) (void) G_GNUC_CONST;
|
||||
|
||||
static secret_password_lookup_t secret_password_lookup_fn = nullptr;
|
||||
static secret_password_lookup_finish_t secret_password_lookup_finish_fn = nullptr;
|
||||
static secret_password_store_t secret_password_store_fn = nullptr;
|
||||
static secret_password_store_finish_t secret_password_store_finish_fn = nullptr;
|
||||
static secret_password_clear_t secret_password_clear_fn = nullptr;
|
||||
static secret_password_clear_finish_t secret_password_clear_finish_fn = nullptr;
|
||||
static secret_password_free_t secret_password_free_fn = nullptr;
|
||||
static secret_error_get_quark_t secret_error_get_quark_fn = nullptr;
|
||||
static secret_password_lookup_t secret_password_lookup_fn = NULL;
|
||||
static secret_password_lookup_finish_t secret_password_lookup_finish_fn = NULL;
|
||||
static secret_password_store_t secret_password_store_fn = NULL;
|
||||
static secret_password_store_finish_t secret_password_store_finish_fn = NULL;
|
||||
static secret_password_clear_t secret_password_clear_fn = NULL;
|
||||
static secret_password_clear_finish_t secret_password_clear_finish_fn = NULL;
|
||||
static secret_password_free_t secret_password_free_fn = NULL;
|
||||
static secret_error_get_quark_t secret_error_get_quark_fn = NULL;
|
||||
|
||||
static QKeychain::Error gerrorToCode(const GError *error) {
|
||||
if (error->domain != secret_error_get_quark_fn()) {
|
||||
@ -82,7 +83,7 @@ on_password_lookup (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer inst)
|
||||
{
|
||||
GError *error = nullptr;
|
||||
GError *error = NULL;
|
||||
callbackArg *arg = (callbackArg*)inst;
|
||||
gchar *password = secret_password_lookup_finish_fn (result, &error);
|
||||
|
||||
@ -94,7 +95,7 @@ on_password_lookup (GObject *source,
|
||||
|
||||
arg->self->q->emitFinishedWithError( code, QString::fromUtf8(error->message) );
|
||||
} else {
|
||||
if (password) {
|
||||
if (password != NULL) {
|
||||
QByteArray raw = QByteArray(password);
|
||||
switch(arg->self->mode) {
|
||||
case QKeychain::JobPrivate::Binary:
|
||||
@ -108,12 +109,12 @@ on_password_lookup (GObject *source,
|
||||
arg->self->q->emitFinished();
|
||||
} else if (arg->self->mode == QKeychain::JobPrivate::Text) {
|
||||
arg->self->mode = QKeychain::JobPrivate::Binary;
|
||||
secret_password_lookup_fn (qtkeychainSchema(), nullptr,
|
||||
secret_password_lookup_fn (qtkeychainSchema(), NULL,
|
||||
on_password_lookup, arg,
|
||||
"user", arg->user.toUtf8().constData(),
|
||||
"server", arg->server.toUtf8().constData(),
|
||||
"type", "base64",
|
||||
nullptr);
|
||||
NULL);
|
||||
return;
|
||||
} else {
|
||||
arg->self->q->emitFinishedWithError( QKeychain::EntryNotFound, QObject::tr("Entry not found") );
|
||||
@ -138,7 +139,7 @@ on_password_stored (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer inst)
|
||||
{
|
||||
GError *error = nullptr;
|
||||
GError *error = NULL;
|
||||
QKeychain::JobPrivate *self = (QKeychain::JobPrivate*)inst;
|
||||
|
||||
Q_UNUSED(source);
|
||||
@ -146,14 +147,14 @@ on_password_stored (GObject *source,
|
||||
secret_password_store_finish_fn (result, &error);
|
||||
|
||||
if (self) {
|
||||
if (error) {
|
||||
if (error != NULL) {
|
||||
self->q->emitFinishedWithError( gerrorToCode(error),
|
||||
QString::fromUtf8(error->message) );
|
||||
} else {
|
||||
self->q->emitFinished();
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
if (error != NULL) {
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
@ -163,7 +164,7 @@ on_password_cleared (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer inst)
|
||||
{
|
||||
GError *error = nullptr;
|
||||
GError *error = NULL;
|
||||
QKeychain::JobPrivate *self = (QKeychain::JobPrivate*)inst;
|
||||
gboolean removed = secret_password_clear_finish_fn (result, &error);
|
||||
|
||||
@ -177,7 +178,7 @@ on_password_cleared (GObject *source,
|
||||
self->q->emitFinished();
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
if (error != NULL) {
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
@ -197,21 +198,21 @@ bool LibSecretKeyring::isAvailable() {
|
||||
const LibSecretKeyring& keyring = instance();
|
||||
if (!keyring.isLoaded())
|
||||
return false;
|
||||
if (secret_password_lookup_fn == nullptr)
|
||||
if (secret_password_lookup_fn == NULL)
|
||||
return false;
|
||||
if (secret_password_lookup_finish_fn == nullptr)
|
||||
if (secret_password_lookup_finish_fn == NULL)
|
||||
return false;
|
||||
if (secret_password_store_fn == nullptr)
|
||||
if (secret_password_store_fn == NULL)
|
||||
return false;
|
||||
if (secret_password_store_finish_fn == nullptr)
|
||||
if (secret_password_store_finish_fn == NULL)
|
||||
return false;
|
||||
if (secret_password_clear_fn == nullptr)
|
||||
if (secret_password_clear_fn == NULL)
|
||||
return false;
|
||||
if (secret_password_clear_finish_fn == nullptr)
|
||||
if (secret_password_clear_finish_fn == NULL)
|
||||
return false;
|
||||
if (secret_password_free_fn == nullptr)
|
||||
if (secret_password_free_fn == NULL)
|
||||
return false;
|
||||
if (secret_error_get_quark_fn == nullptr)
|
||||
if (secret_error_get_quark_fn == NULL)
|
||||
return false;
|
||||
return true;
|
||||
#else
|
||||
@ -235,16 +236,14 @@ bool LibSecretKeyring::findPassword(const QString &user, const QString &server,
|
||||
arg->user = user;
|
||||
arg->server = server;
|
||||
|
||||
secret_password_lookup_fn (qtkeychainSchema(), nullptr, on_password_lookup, arg,
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
secret_password_lookup_fn (qtkeychainSchema(), NULL, on_password_lookup, arg,
|
||||
"user", user.toUtf8().constData(),
|
||||
"server", server.toUtf8().constData(),
|
||||
"type", "plaintext",
|
||||
nullptr);
|
||||
NULL);
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(user)
|
||||
Q_UNUSED(server)
|
||||
Q_UNUSED(self)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@ -272,21 +271,16 @@ bool LibSecretKeyring::writePassword(const QString &display_name,
|
||||
break;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
secret_password_store_fn (qtkeychainSchema(), SECRET_COLLECTION_DEFAULT,
|
||||
display_name.toUtf8().constData(),
|
||||
pwd.constData(), nullptr, on_password_stored, self,
|
||||
pwd.constData(), NULL, on_password_stored, self,
|
||||
"user", user.toUtf8().constData(),
|
||||
"server", server.toUtf8().constData(),
|
||||
"type", type.toUtf8().constData(),
|
||||
nullptr);
|
||||
NULL);
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(display_name)
|
||||
Q_UNUSED(user)
|
||||
Q_UNUSED(server)
|
||||
Q_UNUSED(mode)
|
||||
Q_UNUSED(password)
|
||||
Q_UNUSED(self)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@ -299,21 +293,19 @@ bool LibSecretKeyring::deletePassword(const QString &key, const QString &service
|
||||
return false;
|
||||
}
|
||||
|
||||
secret_password_clear_fn (qtkeychainSchema(), nullptr, on_password_cleared, self,
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
secret_password_clear_fn (qtkeychainSchema(), NULL, on_password_cleared, self,
|
||||
"user", key.toUtf8().constData(),
|
||||
"server", service.toUtf8().constData(),
|
||||
nullptr);
|
||||
NULL);
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(key)
|
||||
Q_UNUSED(service)
|
||||
Q_UNUSED(self)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
LibSecretKeyring::LibSecretKeyring()
|
||||
: QLibrary(QLatin1String("secret-1"), 0)
|
||||
: QLibrary(QStringLiteral("secret-1"), 0)
|
||||
{
|
||||
#ifdef HAVE_LIBSECRET
|
||||
if (load()) {
|
||||
|
||||
@ -156,7 +156,7 @@
|
||||
</method>
|
||||
<method name="readEntryList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
@ -164,7 +164,7 @@
|
||||
</method>
|
||||
<method name="readMapList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
@ -172,7 +172,7 @@
|
||||
</method>
|
||||
<method name="readPasswordList">
|
||||
<arg type="a{sv}" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
|
||||
<arg name="handle" type="i" direction="in"/>
|
||||
<arg name="folder" type="s" direction="in"/>
|
||||
<arg name="key" type="s" direction="in"/>
|
||||
|
||||
@ -2,27 +2,23 @@
|
||||
# This file is provided as is without any warranty.
|
||||
# It can break at anytime or be removed without notice.
|
||||
|
||||
lessThan(QT_MAJOR_VERSION, 5) {
|
||||
error("qtkeychain requires Qt 5 or later")
|
||||
}
|
||||
|
||||
QTKEYCHAIN_PWD = $$PWD
|
||||
QT5KEYCHAIN_PWD = $$PWD
|
||||
|
||||
CONFIG += depend_includepath
|
||||
DEFINES += QTKEYCHAIN_NO_EXPORT
|
||||
|
||||
INCLUDEPATH += \
|
||||
$$PWD/.. \
|
||||
$$QTKEYCHAIN_PWD
|
||||
$$QT5KEYCHAIN_PWD
|
||||
|
||||
HEADERS += \
|
||||
$$QTKEYCHAIN_PWD/keychain_p.h \
|
||||
$$QTKEYCHAIN_PWD/keychain.h
|
||||
$$QT5KEYCHAIN_PWD/keychain_p.h \
|
||||
$$QT5KEYCHAIN_PWD/keychain.h
|
||||
|
||||
SOURCES += \
|
||||
$$QTKEYCHAIN_PWD/keychain.cpp
|
||||
$$QT5KEYCHAIN_PWD/keychain.cpp
|
||||
|
||||
unix:!android:!macx:!ios {
|
||||
unix:!macx:!ios {
|
||||
# Remove the following LIBSECRET_SUPPORT line
|
||||
# to build without libsecret support.
|
||||
DEFINES += LIBSECRET_SUPPORT
|
||||
@ -41,34 +37,19 @@ unix:!android:!macx:!ios {
|
||||
}
|
||||
|
||||
# Generate D-Bus interface:
|
||||
DEFINES += KEYCHAIN_DBUS
|
||||
QT += dbus
|
||||
kwallet_interface.files = $$PWD/org.kde.KWallet.xml
|
||||
DBUS_INTERFACES += kwallet_interface
|
||||
|
||||
HEADERS += \
|
||||
$$QTKEYCHAIN_PWD/gnomekeyring_p.h \
|
||||
$$QTKEYCHAIN_PWD/plaintextstore_p.h \
|
||||
$$QTKEYCHAIN_PWD/libsecret_p.h
|
||||
$$QT5KEYCHAIN_PWD/gnomekeyring_p.h \
|
||||
$$QT5KEYCHAIN_PWD/plaintextstore_p.h \
|
||||
$$QT5KEYCHAIN_PWD/libsecret_p.h
|
||||
SOURCES += \
|
||||
$$QTKEYCHAIN_PWD/keychain_unix.cpp \
|
||||
$$QTKEYCHAIN_PWD/plaintextstore.cpp \
|
||||
$$QTKEYCHAIN_PWD/gnomekeyring.cpp \
|
||||
$$QTKEYCHAIN_PWD/libsecret.cpp
|
||||
}
|
||||
|
||||
android {
|
||||
lessThan(QT_MAJOR_VERSION, 6) {
|
||||
QT += androidextras
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
$$QTKEYCHAIN_PWD/androidkeystore_p.h \
|
||||
$$QTKEYCHAIN_PWD/plaintextstore_p.h
|
||||
SOURCES += \
|
||||
$$QTKEYCHAIN_PWD/androidkeystore.cpp \
|
||||
$$QTKEYCHAIN_PWD/keychain_android.cpp \
|
||||
$$QTKEYCHAIN_PWD/plaintextstore.cpp
|
||||
$$QT5KEYCHAIN_PWD/keychain_unix.cpp \
|
||||
$$QT5KEYCHAIN_PWD/plaintextstore.cpp \
|
||||
$$QT5KEYCHAIN_PWD/gnomekeyring.cpp \
|
||||
$$QT5KEYCHAIN_PWD/libsecret.cpp
|
||||
}
|
||||
|
||||
win32 {
|
||||
@ -78,20 +59,25 @@ win32 {
|
||||
DEFINES += USE_CREDENTIAL_STORE
|
||||
contains(DEFINES, USE_CREDENTIAL_STORE) {
|
||||
!build_pass:message("Windows Credential Store support: on")
|
||||
LIBS += -ladvapi32
|
||||
LIBS += -lAdvapi32
|
||||
} else {
|
||||
!build_pass:message("Windows Credential Store support: off")
|
||||
LIBS += -lcrypt32
|
||||
HEADERS += $$QTKEYCHAIN_PWD/plaintextstore_p.h
|
||||
SOURCES += $$QTKEYCHAIN_PWD/plaintextstore.cpp
|
||||
LIBS += -lCrypt32
|
||||
HEADERS += $$QT5KEYCHAIN_PWD/plaintextstore_p.h
|
||||
SOURCES += $$QT5KEYCHAIN_PWD/plaintextstore.cpp
|
||||
}
|
||||
HEADERS += $$QTKEYCHAIN_PWD/libsecret_p.h
|
||||
HEADERS += $$QT5KEYCHAIN_PWD/libsecret_p.h
|
||||
SOURCES += \
|
||||
$$QTKEYCHAIN_PWD/keychain_win.cpp \
|
||||
$$QTKEYCHAIN_PWD/libsecret.cpp
|
||||
$$QT5KEYCHAIN_PWD/keychain_win.cpp \
|
||||
$$QT5KEYCHAIN_PWD/libsecret.cpp
|
||||
}
|
||||
|
||||
macx|ios {
|
||||
LIBS += -framework Security -framework Foundation
|
||||
OBJECTIVE_SOURCES += $$QTKEYCHAIN_PWD/keychain_apple.mm
|
||||
macx:!ios {
|
||||
LIBS += "-framework Security" "-framework Foundation"
|
||||
SOURCES += $$QT5KEYCHAIN_PWD/keychain_mac.cpp
|
||||
}
|
||||
|
||||
ios {
|
||||
LIBS += "-framework Security" "-framework Foundation"
|
||||
OBJECTIVE_SOURCES += $$QT5KEYCHAIN_PWD/keychain_ios.mm
|
||||
}
|
||||
@ -6,14 +6,7 @@
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
|
||||
* details, check the accompanying file 'COPYING'. *
|
||||
*****************************************************************************/
|
||||
|
||||
#include <QtGlobal>
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QCoreApplication>
|
||||
#endif
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include "keychain.h"
|
||||
@ -29,14 +22,7 @@ static int printUsage() {
|
||||
}
|
||||
|
||||
int main( int argc, char** argv ) {
|
||||
#ifdef Q_OS_DARWIN
|
||||
// Since we use NSNotificationCenter under the hood in keychain_apple,
|
||||
// we use QGuiApplication to automatically configure the platform
|
||||
// integration stuff done in this class and not in QCoreApplication
|
||||
QGuiApplication app( argc, argv );
|
||||
#else
|
||||
QCoreApplication app( argc, argv );
|
||||
#endif
|
||||
const QStringList args = app.arguments();
|
||||
if ( args.count() < 2 )
|
||||
return printUsage();
|
||||
|
||||
@ -1,175 +1,239 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.0" language="de_DE">
|
||||
<TS version="2.1" language="de_DE">
|
||||
<context>
|
||||
<name>QKeychain::DeletePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="104"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="108"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="548"/>
|
||||
<location filename="../keychain_unix.cpp" line="556"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="574"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::JobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="265"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="509"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::PlainTextStore</name>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="65"/>
|
||||
<source>Could not store data in settings: access error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="67"/>
|
||||
<source>Could not store data in settings: format error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="85"/>
|
||||
<source>Could not delete data from settings: access error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="87"/>
|
||||
<source>Could not delete data from settings: format error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="104"/>
|
||||
<source>Entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::ReadPasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="119"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Unbekannter Fehler</translation>
|
||||
<location filename="../keychain_win.cpp" line="32"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="133"/>
|
||||
<location filename="../keychain_win.cpp" line="36"/>
|
||||
<location filename="../keychain_win.cpp" line="139"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="178"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="210"/>
|
||||
<location filename="../keychain_unix.cpp" line="187"/>
|
||||
<location filename="../keychain_unix.cpp" line="197"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="286"/>
|
||||
<source>No keychain service available</source>
|
||||
<translation>Kein Schlüsselbund-Dienst verfügbar</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="212"/>
|
||||
<location filename="../keychain_unix.cpp" line="288"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="258"/>
|
||||
<location filename="../keychain_unix.cpp" line="333"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Zugriff auf Schlüsselbund verweigert</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="279"/>
|
||||
<location filename="../keychain_unix.cpp" line="354"/>
|
||||
<source>Could not determine data type: %1; %2</source>
|
||||
<translation>Datentyp kann nicht ermittelt werden: %1: %2</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="297"/>
|
||||
<location filename="../keychain_unix.cpp" line="363"/>
|
||||
<source>Entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="372"/>
|
||||
<source>Unsupported entry type 'Map'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="300"/>
|
||||
<location filename="../keychain_unix.cpp" line="375"/>
|
||||
<source>Unknown kwallet entry type '%1'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="315"/>
|
||||
<source>Could not read password: %1; %2</source>
|
||||
<translation>Passwort konnte nicht ausgelesen werden: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="76"/>
|
||||
<location filename="../keychain_mac.cpp" line="75"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Passwort nicht gefunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="288"/>
|
||||
<location filename="../keychain_win.cpp" line="27"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Eintrag nicht gefunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="44"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>Kann Daten nicht entschlüsseln</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::WritePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="336"/>
|
||||
<location filename="../keychain_unix.cpp" line="344"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Unbekannter Fehler</translation>
|
||||
<location filename="../keychain_win.cpp" line="78"/>
|
||||
<source>Credential size exceeds maximum size of %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="359"/>
|
||||
<location filename="../keychain_win.cpp" line="87"/>
|
||||
<source>Credential key exceeds maximum size of %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="92"/>
|
||||
<source>Writing credentials failed: Win32 error code %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="162"/>
|
||||
<source>Encryption failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="415"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="400"/>
|
||||
<location filename="../keychain_unix.cpp" line="485"/>
|
||||
<location filename="../keychain_unix.cpp" line="425"/>
|
||||
<location filename="../keychain_unix.cpp" line="452"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="468"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="463"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Zugriff auf Schlüsselbund verweigert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="64"/>
|
||||
<source>Could not delete encrypted data from settings: access error</source>
|
||||
<translation>Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Zugriffsfehler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="65"/>
|
||||
<source>Could not delete encrypted data from settings: format error</source>
|
||||
<translation>Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Formatfehler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="85"/>
|
||||
<source>Encryption failed</source>
|
||||
<translation>Verschlüsselung fehlgeschlagen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="100"/>
|
||||
<source>Could not store encrypted data in settings: access error</source>
|
||||
<translation>Kann verschlüsselte Daten nicht in den Einstellungen speichern: Zugriffsfehler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="101"/>
|
||||
<source>Could not store encrypted data in settings: format error</source>
|
||||
<translation>Kann verschlüsselte Daten nicht in den Einstellungen speichern: Formatfehler</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="155"/>
|
||||
<location filename="../libsecret.cpp" line="120"/>
|
||||
<source>Entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="225"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Zugriff auf Schlüsselbund verweigert</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="157"/>
|
||||
<location filename="../keychain_unix.cpp" line="227"/>
|
||||
<source>No keyring daemon</source>
|
||||
<translation>Kein Schlüsselbund-Dienst </translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="159"/>
|
||||
<location filename="../keychain_unix.cpp" line="229"/>
|
||||
<source>Already unlocked</source>
|
||||
<translation>Bereits entsperrt</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="161"/>
|
||||
<location filename="../keychain_unix.cpp" line="231"/>
|
||||
<source>No such keyring</source>
|
||||
<translation>Kein solcher Schlüsselbund</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="163"/>
|
||||
<location filename="../keychain_unix.cpp" line="233"/>
|
||||
<source>Bad arguments</source>
|
||||
<translation>Ungültige Argumente</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="165"/>
|
||||
<location filename="../keychain_unix.cpp" line="235"/>
|
||||
<source>I/O error</source>
|
||||
<translation>Ein-/Ausgabe-Fehler</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="167"/>
|
||||
<location filename="../keychain_unix.cpp" line="237"/>
|
||||
<source>Cancelled</source>
|
||||
<translation>Abgebrochen</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="169"/>
|
||||
<location filename="../keychain_unix.cpp" line="239"/>
|
||||
<source>Keyring already exists</source>
|
||||
<translation>Schlüsselbund existiert bereits</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="171"/>
|
||||
<location filename="../keychain_unix.cpp" line="241"/>
|
||||
<source>No match</source>
|
||||
<translation>Kein Treffer</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="176"/>
|
||||
<location filename="../keychain_unix.cpp" line="246"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Unbekannter Fehler</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="31"/>
|
||||
<location filename="../keychain_mac.cpp" line="33"/>
|
||||
<source>OS X Keychain error (OSStatus %1)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="32"/>
|
||||
<source>%1 (OSStatus %2)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
||||
@ -1,267 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="fr_FR">
|
||||
<context>
|
||||
<name>QKeychain::DeletePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="79"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation>Mot de passe introuvable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="83"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>Impossible de déchiffrer les données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="546"/>
|
||||
<location filename="../keychain_unix.cpp" line="554"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Erreur inconnue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="572"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Impossible d'ouvrir le portefeuille : %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_haiku.cpp" line="120"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Mot de passe introuvable</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::JobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="263"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Erreur inconnue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="507"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Accès au trousseau refusé</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::PlainTextStore</name>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="65"/>
|
||||
<source>Could not store data in settings: access error</source>
|
||||
<translation>Impossible de stocker les données dans les paramètres : Erreur d'accès</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="67"/>
|
||||
<source>Could not store data in settings: format error</source>
|
||||
<translation>Impossible de stocker les données dans les paramètres : Erreur de format</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="85"/>
|
||||
<source>Could not delete data from settings: access error</source>
|
||||
<translation>Impossible de supprimer les données depuis les paramètres : Erreur d'accès</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="87"/>
|
||||
<source>Could not delete data from settings: format error</source>
|
||||
<translation>Impossible de supprimer les données depuis les paramètres : Erreur de format</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="104"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Entrée introuvable</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::ReadPasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="185"/>
|
||||
<location filename="../keychain_unix.cpp" line="195"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Erreur inconnue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="176"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus n'est pas en cours d'exécution</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="284"/>
|
||||
<source>No keychain service available</source>
|
||||
<translation>Aucun service de trousseau disponible</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="286"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Impossible d'ouvrir le trousseau : %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="331"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Accès au trousseau refusé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="352"/>
|
||||
<source>Could not determine data type: %1; %2</source>
|
||||
<translation>Impossible de déterminer le type de données : %1: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="370"/>
|
||||
<source>Unsupported entry type 'Map'</source>
|
||||
<translation>Type d'entrée non supporté 'Map'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="373"/>
|
||||
<source>Unknown kwallet entry type '%1'</source>
|
||||
<translation>Type de trousseau inconnu '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not read password: %1; %2</source>
|
||||
<translation type="vanished">Impossible de lire le mot de passe : %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="75"/>
|
||||
<location filename="../keychain_haiku.cpp" line="41"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Mot de passe introuvable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="361"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Entrée introuvable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="32"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation>Entrée de mot de passe introuvable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="36"/>
|
||||
<location filename="../keychain_win.cpp" line="114"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>Impossible de déchiffrer les données</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::WritePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="423"/>
|
||||
<location filename="../keychain_unix.cpp" line="450"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Erreur inconnue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="413"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus n'est pas en cours d'exécution</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="466"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Impossible d'ouvrir le trousseau : %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation type="vanished">Accès au trousseau refusé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not delete encrypted data from settings: access error</source>
|
||||
<translation type="vanished">Impossible de supprimer des données chiffrées dans les paramètres : Erreur d'accès</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not delete encrypted data from settings: format error</source>
|
||||
<translation type="vanished">Impossible de supprimer des données chiffrées dans les paramètres : Erreur de format</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="64"/>
|
||||
<location filename="../keychain_win.cpp" line="137"/>
|
||||
<source>Encryption failed</source>
|
||||
<translation>Le chiffrement a échoué</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not store encrypted data in settings: access error</source>
|
||||
<translation type="vanished">Impossible de stocker des données chiffrées dans les paramètres : Erreur d'accès</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not store encrypted data in settings: format error</source>
|
||||
<translation type="vanished">Impossible de stocker des données chiffrées dans les paramètres : Erreur de format</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_haiku.cpp" line="88"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Mot de passe introuvable</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="223"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Accès au trousseau refusé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="225"/>
|
||||
<source>No keyring daemon</source>
|
||||
<translation>Aucun démon de trousseau</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="227"/>
|
||||
<source>Already unlocked</source>
|
||||
<translation>Déjà déverrouillé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="229"/>
|
||||
<source>No such keyring</source>
|
||||
<translation>Aucun trousseau</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="231"/>
|
||||
<source>Bad arguments</source>
|
||||
<translation>Mauvais arguments</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="233"/>
|
||||
<source>I/O error</source>
|
||||
<translation>Erreur d'E/S</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="235"/>
|
||||
<source>Cancelled</source>
|
||||
<translation>Annulé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="237"/>
|
||||
<source>Keyring already exists</source>
|
||||
<translation>Trousseau déjà existant</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="239"/>
|
||||
<source>No match</source>
|
||||
<translation>Aucune correspondance</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="244"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Erreur inconnue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="31"/>
|
||||
<source>OS X Keychain error (OSStatus %1)</source>
|
||||
<translation>OS X Keychain error (OSStatus %1)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="32"/>
|
||||
<source>%1 (OSStatus %2)</source>
|
||||
<translation>%1 (OSStatus %2)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libsecret.cpp" line="120"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Entrée introuvable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_haiku.cpp" line="18"/>
|
||||
<source>error 0x%1: %2</source>
|
||||
<translation>Erreur 0x%1 : %2</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -1,320 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="nl_NL">
|
||||
<context>
|
||||
<name>KeyChainClass</name>
|
||||
<message>
|
||||
<location filename="TestAppExample/keychainclass.cpp" line="22"/>
|
||||
<source>Read key failed: %1</source>
|
||||
<translation>De sleutel kan niet worden ingelezen: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="TestAppExample/keychainclass.cpp" line="37"/>
|
||||
<source>Write key failed: %1</source>
|
||||
<translation>De sleutel kan niet worden weggeschreven: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="TestAppExample/keychainclass.cpp" line="54"/>
|
||||
<source>Delete key failed: %1</source>
|
||||
<translation>De sleutel kan niet worden verwijderd: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::DeletePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="173"/>
|
||||
<source>Could not open keystore</source>
|
||||
<translation>De sleutelbos kan niet worden geopend</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="179"/>
|
||||
<source>Could not remove private key from keystore</source>
|
||||
<translation>De privésleutel kan niet worden verwijderd uit de sleutelbos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_haiku.cpp" line="177"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Het wachtwoord is niet gevonden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="552"/>
|
||||
<location filename="keychain_unix.cpp" line="560"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Onbekende foutmelding</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="578"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>De sleutelbos kan niet worden geopend: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="104"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation>Het wachtwoord is niet gevonden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="108"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>De gegevens kunnen niet worden ongrendeld</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::JobPrivate</name>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="265"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Onbekende foutmelding</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="509"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>U heeft geen toegang tot de sleutelbos</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::PlainTextStore</name>
|
||||
<message>
|
||||
<location filename="plaintextstore.cpp" line="65"/>
|
||||
<source>Could not store data in settings: access error</source>
|
||||
<translation>De gegevens kunnen niet worden opgeslagen in de instellingen: toegangsfout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="plaintextstore.cpp" line="67"/>
|
||||
<source>Could not store data in settings: format error</source>
|
||||
<translation>De gegevens kunnen niet worden opgeslagen in de instellingen: opmaakfout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="plaintextstore.cpp" line="85"/>
|
||||
<source>Could not delete data from settings: access error</source>
|
||||
<translation>De gegevens kunnen niet worden verwijderd uit de instellingen: toegangsfout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="plaintextstore.cpp" line="87"/>
|
||||
<source>Could not delete data from settings: format error</source>
|
||||
<translation>De gegevens kunnen niet worden verwijderd uit de instellingen: opmaakfout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="plaintextstore.cpp" line="104"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Het item is niet gevonden</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::ReadPasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="52"/>
|
||||
<location filename="keychain_unix.cpp" line="363"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Het item is niet gevonden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="60"/>
|
||||
<source>Could not open keystore</source>
|
||||
<translation>De sleutelbos kan niet worden geopend</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="68"/>
|
||||
<source>Could not retrieve private key from keystore</source>
|
||||
<translation>De privésleutel kan niet worden verwijderd uit de sleutelbos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="75"/>
|
||||
<source>Could not create decryption cipher</source>
|
||||
<translation>De ontgrendelcode kan niet worden aangemaakt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_haiku.cpp" line="96"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Het wachtwoord is niet gevonden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="178"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus is niet actief</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="187"/>
|
||||
<location filename="keychain_unix.cpp" line="197"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Onbekende foutmelding</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="286"/>
|
||||
<source>No keychain service available</source>
|
||||
<translation>De sleutelbosdienst is niet beschikbaar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="288"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>De sleutelbos kan niet worden geopend: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="333"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>U heeft geen toegang tot de sleutelbos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="354"/>
|
||||
<source>Could not determine data type: %1; %2</source>
|
||||
<translation>De gegevensdrager kan niet worden bepaald: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="372"/>
|
||||
<source>Unsupported entry type 'Map'</source>
|
||||
<translation>Niet-ondersteund itemtype ‘Map’</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="375"/>
|
||||
<source>Unknown kwallet entry type '%1'</source>
|
||||
<translation>Onbekend KWallet-item van type ‘%1’</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="32"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation>Het wachtwoord is niet gevonden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="36"/>
|
||||
<location filename="keychain_win.cpp" line="139"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>De gegevens kunnen niet worden ongrendeld</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::WritePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="95"/>
|
||||
<source>Could not open keystore</source>
|
||||
<translation>De sleutelbos kan niet worden geopend</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="124"/>
|
||||
<source>Could not create private key generator</source>
|
||||
<translation>De privésleutelgenerator kan niet worden gestart</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="131"/>
|
||||
<source>Could not generate new private key</source>
|
||||
<translation>Er kan geen nieuwe privésleutel worden gegenereerd</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="139"/>
|
||||
<source>Could not retrieve private key from keystore</source>
|
||||
<translation>De privésleutel kan niet worden opgehaald uit de sleutelbos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="147"/>
|
||||
<source>Could not create encryption cipher</source>
|
||||
<translation>De vergrendelcode kan niet worden aangemaakt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_android.cpp" line="155"/>
|
||||
<source>Could not encrypt data</source>
|
||||
<translation>De gegevens kunnen niet worden ontgrendeld</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_haiku.cpp" line="144"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Het wachtwoord is niet gevonden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="415"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus is niet actief</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="425"/>
|
||||
<location filename="keychain_unix.cpp" line="452"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Onbekende foutmelding</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="468"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>De sleutelbos kan niet worden geopend: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="78"/>
|
||||
<source>Credential size exceeds maximum size of %1</source>
|
||||
<translation>De omvang overschrijdt de maximumomvang van %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="87"/>
|
||||
<source>Credential key exceeds maximum size of %1</source>
|
||||
<translation>De sleutel overschrijdt de maximumomvang van %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="92"/>
|
||||
<source>Writing credentials failed: Win32 error code %1</source>
|
||||
<translation>De gegevens kunnen niet worden weggeschreven: Win32-foutcode %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_win.cpp" line="162"/>
|
||||
<source>Encryption failed</source>
|
||||
<translation>Het ontgrendelen is mislukt</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="keychain_haiku.cpp" line="72"/>
|
||||
<source>error 0x%1: %2</source>
|
||||
<translation>foutmelding 0x%1: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="225"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>U heeft geen toegang tot de sleutelbos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="227"/>
|
||||
<source>No keyring daemon</source>
|
||||
<translation>De sleutelbosdienst is niet actief</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="229"/>
|
||||
<source>Already unlocked</source>
|
||||
<translation>De sleutelbos is reeds ontgrendeld</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="231"/>
|
||||
<source>No such keyring</source>
|
||||
<translation>De sleutelbos bestaat niet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="233"/>
|
||||
<source>Bad arguments</source>
|
||||
<translation>Onjuiste opties</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="235"/>
|
||||
<source>I/O error</source>
|
||||
<translation>I/O-fout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="237"/>
|
||||
<source>Cancelled</source>
|
||||
<translation>Geannuleerd</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="239"/>
|
||||
<source>Keyring already exists</source>
|
||||
<translation>De sleutelbos bestaat reeds</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="241"/>
|
||||
<source>No match</source>
|
||||
<translation>Er zijn geen overeenkomsten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="keychain_unix.cpp" line="246"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Onbekende foutmelding</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="libsecret.cpp" line="119"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Het item is niet gevonden</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -1,178 +1,241 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.0" language="ro_RO">
|
||||
<TS version="2.1" language="ro_RO">
|
||||
<context>
|
||||
<name>QKeychain::DeletePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="104"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="108"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="548"/>
|
||||
<location filename="../keychain_unix.cpp" line="556"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="574"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::JobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="265"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="509"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::PlainTextStore</name>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="65"/>
|
||||
<source>Could not store data in settings: access error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="67"/>
|
||||
<source>Could not store data in settings: format error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="85"/>
|
||||
<source>Could not delete data from settings: access error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="87"/>
|
||||
<source>Could not delete data from settings: format error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="104"/>
|
||||
<source>Entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::ReadPasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="119"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Eroare necunoscută</translation>
|
||||
<location filename="../keychain_win.cpp" line="32"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="133"/>
|
||||
<location filename="../keychain_win.cpp" line="36"/>
|
||||
<location filename="../keychain_win.cpp" line="139"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="178"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus nu rulează</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="210"/>
|
||||
<location filename="../keychain_unix.cpp" line="187"/>
|
||||
<location filename="../keychain_unix.cpp" line="197"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="286"/>
|
||||
<source>No keychain service available</source>
|
||||
<translatorcomment>Nu există niciun serviciu de chei disponibil</translatorcomment>
|
||||
<translation>Kein Schlüsselbund-Dienst verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="212"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Nu se poate deschide portofelul: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="258"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Acces interzis la serviciul de chei</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="279"/>
|
||||
<source>Could not determine data type: %1; %2</source>
|
||||
<translation>Nu se poate stabili tipul de date: %1: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="297"/>
|
||||
<source>Unsupported entry type 'Map'</source>
|
||||
<translation>Tip de înregistrare nesuportat 'Map'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="300"/>
|
||||
<source>Unknown kwallet entry type '%1'</source>
|
||||
<translation>Tip de înregistrare kwallet necunoscut '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="315"/>
|
||||
<source>Could not read password: %1; %2</source>
|
||||
<translation>Nu se poate citi parola: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="76"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Parola nu a fost găsită</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="288"/>
|
||||
<location filename="../keychain_win.cpp" line="27"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Înregistrarea nu a fost găsită</translation>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="44"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>Nu se poate decripta data</translation>
|
||||
<location filename="../keychain_unix.cpp" line="333"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="354"/>
|
||||
<source>Could not determine data type: %1; %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="363"/>
|
||||
<source>Entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="372"/>
|
||||
<source>Unsupported entry type 'Map'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="375"/>
|
||||
<source>Unknown kwallet entry type '%1'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="75"/>
|
||||
<source>Password not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::WritePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="336"/>
|
||||
<location filename="../keychain_unix.cpp" line="344"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Eroare necunoscută</translation>
|
||||
<location filename="../keychain_win.cpp" line="78"/>
|
||||
<source>Credential size exceeds maximum size of %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="359"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus nu rulează</translation>
|
||||
<location filename="../keychain_win.cpp" line="87"/>
|
||||
<source>Credential key exceeds maximum size of %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="400"/>
|
||||
<location filename="../keychain_unix.cpp" line="485"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Nu se poate deschide portofelul: %1; %2</translation>
|
||||
<location filename="../keychain_win.cpp" line="92"/>
|
||||
<source>Writing credentials failed: Win32 error code %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="463"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Acces interzis la serviciul de chei</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="64"/>
|
||||
<source>Could not delete encrypted data from settings: access error</source>
|
||||
<translation>Nu se pot șterge datele criptate din setări: eroare de acces</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="65"/>
|
||||
<source>Could not delete encrypted data from settings: format error</source>
|
||||
<translation>Nu se pot șterge datele criptate din setări: eroare de format</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="85"/>
|
||||
<location filename="../keychain_win.cpp" line="162"/>
|
||||
<source>Encryption failed</source>
|
||||
<translation>Criptarea a eșuat</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="100"/>
|
||||
<source>Could not store encrypted data in settings: access error</source>
|
||||
<translation>Nu se pot stoca datele criptate în setări: eroare de acces</translation>
|
||||
<location filename="../keychain_unix.cpp" line="415"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="101"/>
|
||||
<source>Could not store encrypted data in settings: format error</source>
|
||||
<translation>Nu se pot stoca datele criptate în setări: eroare de format</translation>
|
||||
<location filename="../keychain_unix.cpp" line="425"/>
|
||||
<location filename="../keychain_unix.cpp" line="452"/>
|
||||
<source>Unknown error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="468"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="155"/>
|
||||
<location filename="../libsecret.cpp" line="120"/>
|
||||
<source>Entry not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="225"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Acces interzis la serviciul de chei</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="157"/>
|
||||
<location filename="../keychain_unix.cpp" line="227"/>
|
||||
<source>No keyring daemon</source>
|
||||
<translation>Niciun demon pentru inelul de chei</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="159"/>
|
||||
<location filename="../keychain_unix.cpp" line="229"/>
|
||||
<source>Already unlocked</source>
|
||||
<translation>Deja deblocat</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="161"/>
|
||||
<location filename="../keychain_unix.cpp" line="231"/>
|
||||
<source>No such keyring</source>
|
||||
<translation>Nu există astfel de inel de chei</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="163"/>
|
||||
<location filename="../keychain_unix.cpp" line="233"/>
|
||||
<source>Bad arguments</source>
|
||||
<translation>Argumente greșite</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="165"/>
|
||||
<location filename="../keychain_unix.cpp" line="235"/>
|
||||
<source>I/O error</source>
|
||||
<translation>Eroare de I/E</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="167"/>
|
||||
<location filename="../keychain_unix.cpp" line="237"/>
|
||||
<source>Cancelled</source>
|
||||
<translation>Anulat</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="169"/>
|
||||
<location filename="../keychain_unix.cpp" line="239"/>
|
||||
<source>Keyring already exists</source>
|
||||
<translation>Inelul de chei deja există</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="171"/>
|
||||
<location filename="../keychain_unix.cpp" line="241"/>
|
||||
<source>No match</source>
|
||||
<translation>Nicio potrivire</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="176"/>
|
||||
<location filename="../keychain_unix.cpp" line="246"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Eroare necunoscută</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="31"/>
|
||||
<location filename="../keychain_mac.cpp" line="33"/>
|
||||
<source>OS X Keychain error (OSStatus %1)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="32"/>
|
||||
<source>%1 (OSStatus %2)</source>
|
||||
<translation>%1 (OSStatus %2)</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
||||
@ -1,241 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="ru_RU">
|
||||
<context>
|
||||
<name>QKeychain::DeletePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="548"/>
|
||||
<location filename="../keychain_unix.cpp" line="556"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Неизвестная ошибка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="574"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Не удалось открыть бумажник: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="104"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation>Пароль не найден</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="108"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>Не удалось расшифровать данные</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::JobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="265"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Неизвестная ошибка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="509"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Доступ к связке ключей запрещён</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::PlainTextStore</name>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="65"/>
|
||||
<source>Could not store data in settings: access error</source>
|
||||
<translation>Не удалось сохранить данные в настройках: ошибка доступа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="67"/>
|
||||
<source>Could not store data in settings: format error</source>
|
||||
<translation>Не удалось сохранить данные в настройках: ошибка формата</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="85"/>
|
||||
<source>Could not delete data from settings: access error</source>
|
||||
<translation>Не удалось удалить данные из настроек: ошибка доступа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="87"/>
|
||||
<source>Could not delete data from settings: format error</source>
|
||||
<translation>Не удалось удалить данные из настроек: ошибка формата</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plaintextstore.cpp" line="104"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Запись не найдена</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::ReadPasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="75"/>
|
||||
<source>Password not found</source>
|
||||
<translation>Пароль не найден</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="178"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus не запущен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="187"/>
|
||||
<location filename="../keychain_unix.cpp" line="197"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Неизвестная ошибка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="286"/>
|
||||
<source>No keychain service available</source>
|
||||
<translation>Служба связки ключей недоступна</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="288"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Не удалось открыть кошелёк: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="333"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Доступ к связке ключей запрещён</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="354"/>
|
||||
<source>Could not determine data type: %1; %2</source>
|
||||
<translation>Не удалось определить тип данных: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="363"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Запись не найдена</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="372"/>
|
||||
<source>Unsupported entry type 'Map'</source>
|
||||
<translation>Неподдерживаемый тип записи 'Map'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="375"/>
|
||||
<source>Unknown kwallet entry type '%1'</source>
|
||||
<translation>Неизвестный тип записи kwallet '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="32"/>
|
||||
<source>Password entry not found</source>
|
||||
<translation>Пароль не найден</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="36"/>
|
||||
<location filename="../keychain_win.cpp" line="139"/>
|
||||
<source>Could not decrypt data</source>
|
||||
<translation>Не удалось расшифровать данные</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QKeychain::WritePasswordJobPrivate</name>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="415"/>
|
||||
<source>D-Bus is not running</source>
|
||||
<translation>D-Bus не запущен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="425"/>
|
||||
<location filename="../keychain_unix.cpp" line="452"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Неизвестная ошибка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="468"/>
|
||||
<source>Could not open wallet: %1; %2</source>
|
||||
<translation>Не удалось открыть кошелёк: %1; %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="78"/>
|
||||
<source>Credential size exceeds maximum size of %1</source>
|
||||
<translation>Учётные данные превышают максимальный размер %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="87"/>
|
||||
<source>Credential key exceeds maximum size of %1</source>
|
||||
<translation>Ключ учётных данных превышает максимальный размер %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="92"/>
|
||||
<source>Writing credentials failed: Win32 error code %1</source>
|
||||
<translation>Не удалось сохранить учётные данные: код ошибки win32 %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_win.cpp" line="162"/>
|
||||
<source>Encryption failed</source>
|
||||
<translation>Шифрование не удалось</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="31"/>
|
||||
<source>OS X Keychain error (OSStatus %1)</source>
|
||||
<translation>Ошибка связки ключей OS X (OSStatus %1)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_mac.cpp" line="32"/>
|
||||
<source>%1 (OSStatus %2)</source>
|
||||
<translation>%1 (OSStatus %2)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="225"/>
|
||||
<source>Access to keychain denied</source>
|
||||
<translation>Доступ к связке ключей запрещён</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="227"/>
|
||||
<source>No keyring daemon</source>
|
||||
<translation>Нет демона связки ключей</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="229"/>
|
||||
<source>Already unlocked</source>
|
||||
<translation>Уже разблокировано</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="231"/>
|
||||
<source>No such keyring</source>
|
||||
<translation>Связка ключей не найдена</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="233"/>
|
||||
<source>Bad arguments</source>
|
||||
<translation>Неверные аргументы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="235"/>
|
||||
<source>I/O error</source>
|
||||
<translation>Ошибка ввода/вывода</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="237"/>
|
||||
<source>Cancelled</source>
|
||||
<translation>Отменено</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="239"/>
|
||||
<source>Keyring already exists</source>
|
||||
<translation>Связка ключей уже существует</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="241"/>
|
||||
<source>No match</source>
|
||||
<translation>Нет совпадений</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../keychain_unix.cpp" line="246"/>
|
||||
<source>Unknown error</source>
|
||||
<translation>Неизвестная ошибка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../libsecret.cpp" line="120"/>
|
||||
<source>Entry not found</source>
|
||||
<translation>Запись не найдена</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/translations">
|
||||
@QM_FILE_LIST@
|
||||
</qresource>
|
||||
</RCC>
|
||||
@ -228,6 +228,7 @@ bool Storage::open()
|
||||
mDatabase->exec("pragma locking_mode=EXCLUSIVE");
|
||||
mDatabase->exec("pragma journal_mode=MEMORY");
|
||||
mDatabase->exec("pragma temp_store=MEMORY");
|
||||
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include "helper.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(TARGET_OSX) || defined(TARGET_LINUX)
|
||||
# include <uuid/uuid.h>
|
||||
@ -606,14 +606,10 @@ int TimeLine::getTime(int year, int month, int day, std::vector<TimeRecord>* int
|
||||
QDate d(year, month, day);
|
||||
|
||||
// Find range of related records [lowest, higher)
|
||||
TimeArray::iterator lowest = std::lower_bound(mData.begin(),
|
||||
mData.end(),
|
||||
d,
|
||||
[] (const TimeRecord& tr, const QDate& d)
|
||||
{
|
||||
return tr.endTime() < QDateTime(d, QTime()).toSecsSinceEpoch();
|
||||
});
|
||||
|
||||
TimeArray::iterator lowest = std::lower_bound(mData.begin(), mData.end(), d, [] (const TimeRecord& tr, const QDate& d)
|
||||
{
|
||||
return tr.endTime() < QDateTime(d, QTime()).toSecsSinceEpoch();
|
||||
});
|
||||
//TimeArray::iterator higher = std::upper_bound(mData.begin(), mData.end(), d, [] (const QDate& d, const TimeRecord& tr) { return tr.startTime().toLocalTime().date() < d;});
|
||||
|
||||
for (;lowest != mData.end();/*&& lowest != higher;*/ lowest++)
|
||||
@ -720,16 +716,6 @@ int TimeLine::month()
|
||||
|
||||
if (date::fromTimestamp(lowIter->endTime(), date::To_LocalTime).mMonth >= this_month.mMonth)
|
||||
{
|
||||
// For tests only
|
||||
// auto date_start = date::fromTimestamp(lowIter->startTime(), date::To_LocalTime);
|
||||
// auto time_start = time::fromTimestamp(lowIter->startTime(), date::To_LocalTime);
|
||||
|
||||
// auto date_end = date::fromTimestamp(lowIter->endTime(), date::To_LocalTime);
|
||||
// auto time_end = time::fromTimestamp(lowIter->endTime(), date::To_LocalTime);
|
||||
// std::cout << date_start.toString() << " " << time_start.toString() << " - "
|
||||
// << date_end.toString() << " " << time_end.toString()
|
||||
// << " id: " << lowIter->id() << std::endl;
|
||||
|
||||
// GMT time!
|
||||
time_t month_begin = this_month.toTimestamp();
|
||||
time_t month_end = month_begin + date::daysInMonth(this_month.mYear, this_month.mMonth) * 86400 - 1;
|
||||
|
||||
@ -268,14 +268,14 @@ int TimeTreeModel::rowCount(const QModelIndex &parent) const
|
||||
return result;
|
||||
}
|
||||
|
||||
int TimeTreeModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
int TimeTreeModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static QString monthToString(int month)
|
||||
{
|
||||
return QLocale().monthName(month, QLocale::FormatType::LongFormat);
|
||||
return QLocale::system().monthName(month);
|
||||
}
|
||||
|
||||
QVariant TimeTreeModel::data(const QModelIndex &index, int role) const
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
# I use this script on two different hosts so there are logic to find proper Qt installation
|
||||
|
||||
export QT_HOME=/home/$USER/qt5.15/5.15.2/gcc_64
|
||||
export QT_HOME=/home/$USER/tools/qt/6.8.0/gcc_64
|
||||
if [ ! -d "$QT_HOME" ] ; then
|
||||
export QT_HOME=/home/$USER/qt5.15/5.15.2/gcc_64
|
||||
export QT_HOME=/home/$USER/tools/qt/6.8.0/gcc_64
|
||||
fi
|
||||
|
||||
# Build .appimage
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user