diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 43a43f4..0000000 --- a/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ -# C++ objects and libs -*.slo -*.lo -*.o -*.a -*.la -*.lai -*.so -*.so.* -*.rc -*.dll -*.dylib - -# Qt-es -object_script.*.Release -object_script.*.Debug -*_plugin_import.cpp -/.qmake.cache -/.qmake.stash -*.pro.user -*.pro.user.* -*.qbs.user -*.qbs.user.* -*.moc -moc_*.cpp -moc_*.h -qrc_*.cpp -ui_*.h -*.qmlc -*.jsc -Makefile* -*build-* -*.qm -*.prl - -# Qt unit tests -target_wrapper.* - -# QtCreator -*.autosave - -# QtCreator Qml -*.qmlproject.user -*.qmlproject.user.* - -# QtCreator CMake -CMakeLists.txt.user* - -# QtCreator 4.8< compilation database -compile_commands.json - -# QtCreator local machine specific files for imported projects -*creator.user* diff --git a/3rd-parties/SingleApplication/CHANGELOG.md b/3rd-parties/SingleApplication/CHANGELOG.md deleted file mode 100644 index 9efd3fd..0000000 --- a/3rd-parties/SingleApplication/CHANGELOG.md +++ /dev/null @@ -1,224 +0,0 @@ -Changelog -========= - -__3.0.18__ ----------- - -* Fallback to standard QApplication class on iOS and Android systems where - the library is not supported. - -__3.0.17__ ----------- - -* Fixed compilation warning/error caused by `geteuid()` on unix based systems. - - _Iakov Kirilenko_ - -* Added CMake support - - _Hennadii Chernyshchyk_ - -__3.0.16__ ----------- - -* Use geteuid and getpwuid to get username on Unix, fallback to environment variable. - - _Jonas Kvinge_ - -__3.0.15__ ----------- - -* Bug Fix: sendMessage() might return false even though data was actually written. - - _Jonas Kvinge_ - -__3.0.14__ ----------- - -* Fixed uninitialised variables in the `SingleApplicationPrivate` constructor. - -__3.0.13a__ ----------- - -* Process socket events asynchronously -* Fix undefined variable error on Windows - - _Francis Giraldeau_ - -__3.0.12a__ ----------- - -* Removed signal handling. - -__3.0.11a__ ----------- - -* Fixed bug where the message sent by the second process was not received - correctly when the message is sent immediately following a connection. - - _Francis Giraldeau_ - -* Refactored code and implemented shared memory block consistency checks - via `qChecksum()` (CRC-16). -* Explicit `qWarning` and `qCritical` when the library is unable to initialise - correctly. - -__3.0.10__ ----------- - -* Removed C style casts and eliminated all clang warnings. Fixed `instanceId` - reading from only one byte in the message deserialization. Cleaned up - serialization code using `QDataStream`. Changed connection type to use - `quint8 enum` rather than `char`. -* Renamed `SingleAppConnectionType` to `ConnectionType`. Added initialization - values to all `ConnectionType` enum cases. - - _Jedidiah Buck McCready_ - -__3.0.9__ ---------- - -* Added SingleApplicationPrivate::primaryPid() as a solution to allow - bringing the primary window of an application to the foreground on - Windows. - - _Eelco van Dam from Peacs BV_ - -__3.0.8__ ---------- - -* Bug fix - changed QApplication::instance() to QCoreApplication::instance() - - _Evgeniy Bazhenov_ - -__3.0.7a__ ----------- - -* Fixed compilation error with Mingw32 in MXE thanks to Vitaly Tonkacheyev. -* Removed QMutex used for thread safe behaviour. The implementation now uses - QCoreApplication::instance() to get an instance to SingleApplication for - memory deallocation. - -__3.0.6a__ ----------- - -* Reverted GetUserName API usage on Windows. Fixed bug with missing library. -* Fixed bug in the Calculator example, preventing it's window to be raised - on Windows. - - Special thanks to Charles Gunawan. - -__3.0.5a__ ----------- - -* Fixed a memory leak in the SingleApplicationPrivate destructor. - - _Sergei Moiseev_ - -__3.0.4a__ ----------- - -* Fixed shadow and uninitialised variable warnings. - - _Paul Walmsley_ - -__3.0.3a__ ----------- - -* Removed Microsoft Windows specific code for getting username due to - multiple problems and compiler differences on Windows platforms. On - Windows the shared memory block in User mode now includes the user's - home path (which contains the user's username). - -* Explicitly getting absolute path of the user's home directory as on Unix - a relative path (`~`) may be returned. - -__3.0.2a__ ----------- - -* Fixed bug on Windows when username containing wide characters causes the - library to crash. - - _Le Liu_ - -__3.0.1a__ ----------- - -* Allows the application path and version to be excluded from the server name - hash. The following flags were added for this purpose: - * `SingleApplication::Mode::ExcludeAppVersion` - * `SingleApplication::Mode::ExcludeAppPath` -* Allow a non elevated process to connect to a local server created by an - elevated process run by the same user on Windows -* Fixes a problem with upper case letters in paths on Windows - - _Le Liu_ - -__v3.0a__ ---------- - -* Deprecated secondary instances count. -* Added a sendMessage() method to send a message to the primary instance. -* Added a receivedMessage() signal, emitted when a message is received from a - secondary instance. -* The SingleApplication constructor's third parameter is now a bool - specifying if the current instance should be allowed to run as a secondary - instance if there is already a primary instance. -* The SingleApplication constructor accept a fourth parameter specifying if - the SingleApplication block should be User-wide or System-wide. -* SingleApplication no longer relies on `applicationName` and - `organizationName` to be set. It instead concatenates all of the following - data and computes a `SHA256` hash which is used as the key of the - `QSharedMemory` block and the `QLocalServer`. Since at least - `applicationFilePath` is always present there is no need to explicitly set - any of the following prior to initialising `SingleApplication`. - * `QCoreApplication::applicationName` - * `QCoreApplication::applicationVersion` - * `QCoreApplication::applicationFilePath` - * `QCoreApplication::organizationName` - * `QCoreApplication::organizationDomain` - * User name or home directory path if in User mode -* The primary instance is no longer notified when a secondary instance had - been started by default. A `Mode` flag for this feature exists. -* Added `instanceNumber()` which represents a unique identifier for each - secondary instance started. When called from the primary instance will - return `0`. - -__v2.4__ --------- - -* Stability improvements -* Support for secondary instances. -* The library now recovers safely after the primary process has crashed -and the shared memory had not been deleted. - -__v2.3__ --------- - -* Improved pimpl design and inheritance safety. - - _Vladislav Pyatnichenko_ - -__v2.2__ --------- - -* The `QAPPLICATION_CLASS` macro can now be defined in the file including the -Single Application header or with a `DEFINES+=` statement in the project file. - -__v2.1__ --------- - -* A race condition can no longer occur when starting two processes nearly - simultaneously. - - Fix issue [#3](https://github.com/itay-grudev/SingleApplication/issues/3) - -__v2.0__ --------- - -* SingleApplication is now being passed a reference to `argc` instead of a - copy. - - Fix issue [#1](https://github.com/itay-grudev/SingleApplication/issues/1) - -* Improved documentation. diff --git a/3rd-parties/SingleApplication/CMakeLists.txt b/3rd-parties/SingleApplication/CMakeLists.txt deleted file mode 100644 index d619230..0000000 --- a/3rd-parties/SingleApplication/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -cmake_minimum_required(VERSION 3.1.0) - -project(SingleApplication) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) - -# SingleApplication base class -set(QAPPLICATION_CLASS QCoreApplication CACHE STRING "Inheritance class for SingleApplication") -set_property(CACHE QAPPLICATION_CLASS PROPERTY STRINGS QApplication QGuiApplication QCoreApplication) - -# Libary target -add_library(${PROJECT_NAME} STATIC - singleapplication.cpp - singleapplication_p.cpp - ) - -# Find dependencies -find_package(Qt5Network) -if(QAPPLICATION_CLASS STREQUAL QApplication) - find_package(Qt5 COMPONENTS Widgets REQUIRED) -elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication) - find_package(Qt5 COMPONENTS Gui REQUIRED) -else() - find_package(Qt5 COMPONENTS Core REQUIRED) -endif() -add_compile_definitions(QAPPLICATION_CLASS=${QAPPLICATION_CLASS}) - -# Link dependencies -target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Network) -if(QAPPLICATION_CLASS STREQUAL QApplication) - target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets) -elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication) - target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Gui) -else() - target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core) -endif() - -if(WIN32) - target_link_libraries(${PROJECT_NAME} PRIVATE advapi32) -endif() - -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/3rd-parties/SingleApplication/LICENSE b/3rd-parties/SingleApplication/LICENSE deleted file mode 100644 index 85b2a14..0000000 --- a/3rd-parties/SingleApplication/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Itay Grudev 2015 - 2016 - -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: - -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, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -Note: Some of the examples include code not distributed under the terms of the -MIT License. diff --git a/3rd-parties/SingleApplication/README.md b/3rd-parties/SingleApplication/README.md deleted file mode 100644 index 5d60986..0000000 --- a/3rd-parties/SingleApplication/README.md +++ /dev/null @@ -1,277 +0,0 @@ -SingleApplication -================= - -This is a replacement of the QtSingleApplication for `Qt5`. - -Keeps the Primary Instance of your Application and kills each subsequent -instances. It can (if enabled) spawn secondary (non-related to the primary) -instances and can send data to the primary instance from secondary instances. - -Usage ------ - -The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application` -class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the -default). Further usage is similar to the use of the `Q[Core|Gui]Application` -classes. - -The library sets up a `QLocalServer` and a `QSharedMemory` block. The first -instance of your Application is your Primary Instance. It would check if the -shared memory block exists and if not it will start a `QLocalServer` and listen -for connections. Each subsequent instance of your application would check if the -shared memory block exists and if it does, it will connect to the QLocalServer -to notify the primary instance that a new instance had been started, after which -it would terminate with status code `0`. In the Primary Instance -`SingleApplication` would emit the `instanceStarted()` signal upon detecting -that a new instance had been started. - -The library uses `stdlib` to terminate the program with the `exit()` function. - -You can use the library as if you use any other `QCoreApplication` derived -class: - -```cpp -#include -#include - -int main( int argc, char* argv[] ) -{ - SingleApplication app( argc, argv ); - - return app.exec(); -} -``` - -To include the library files I would recommend that you add it as a git -submodule to your project and include it's contents with a `.pri` file. Here is -how: - -```bash -git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication -``` - -**Qmake:** - -Then include the `singleapplication.pri` file in your `.pro` project file. - -```qmake -include(singleapplication/singleapplication.pri) -DEFINES += QAPPLICATION_CLASS=QApplication -``` - -**CMake:** - -Then include the subdirectory in your `CMakeLists.txt` project file. - -```cmake -set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication") -add_subdirectory(src/third-party/singleapplication) -``` - -Also don't forget to specify which `QCoreApplication` class your app is using if it -is not `QCoreApplication` as in examples above. - -The `Instance Started` signal ------------------------- - -The SingleApplication class implements a `instanceStarted()` signal. You can -bind to that signal to raise your application's window when a new instance had -been started, for example. - -```cpp -// window is a QWindow instance -QObject::connect( - &app, - &SingleApplication::instanceStarted, - &window, - &QWindow::raise -); -``` - -Using `SingleApplication::instance()` is a neat way to get the -`SingleApplication` instance for binding to it's signals anywhere in your -program. - -__Note:__ On Windows the ability to bring the application windows to the -foreground is restricted. See [Windows specific implementations](Windows.md) -for a workaround and an example implementation. - - -Secondary Instances -------------------- - -If you want to be able to launch additional Secondary Instances (not related to -your Primary Instance) you have to enable that with the third parameter of the -`SingleApplication` constructor. The default is `false` meaning no Secondary -Instances. Here is an example of how you would start a Secondary Instance send -a message with the command line arguments to the primary instance and then shut -down. - -```cpp -int main(int argc, char *argv[]) -{ - SingleApplication app( argc, argv, true ); - - if( app.isSecondary() ) { - app.sendMessage( app.arguments().join(' ')).toUtf8() ); - app.exit( 0 ); - } - - return app.exec(); -} -``` - -*__Note:__ A secondary instance won't cause the emission of the -`instanceStarted()` signal by default. See `SingleApplication::Mode` for more -details.* - -You can check whether your instance is a primary or secondary with the following -methods: - -```cpp -app.isPrimary(); -// or -app.isSecondary(); -``` - -*__Note:__ If your Primary Instance is terminated a newly launched instance -will replace the Primary one even if the Secondary flag has been set.* - -API ---- - -### Members - -```cpp -SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 ) -``` - -Depending on whether `allowSecondary` is set, this constructor may terminate -your app if there is already a primary instance running. Additional `Options` -can be specified to set whether the SingleApplication block should work -user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be -used to notify the primary instance whenever a secondary instance had been -started (disabled by default). `timeout` specifies the maximum time in -milliseconds to wait for blocking operations. - -*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it -recognizes.* - -*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary -and the secondary instance.* - -*__Note:__ Operating system can restrict the shared memory blocks to the same -user, in which case the User/System modes will have no effect and the block will -be user wide.* - ---- - -```cpp -bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 ) -``` - -Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout -in milliseconds for blocking functions - ---- - -```cpp -bool SingleApplication::isPrimary() -``` - -Returns if the instance is the primary instance. - ---- - -```cpp -bool SingleApplication::isSecondary() -``` -Returns if the instance is a secondary instance. - ---- - -```cpp -quint32 SingleApplication::instanceId() -``` - -Returns a unique identifier for the current instance. - ---- - -```cpp -qint64 SingleApplication::primaryPid() -``` - -Returns the process ID (PID) of the primary instance. - -### Signals - -```cpp -void SingleApplication::instanceStarted() -``` - -Triggered whenever a new instance had been started, except for secondary -instances if the `Mode::SecondaryNotification` flag is not specified. - ---- - -```cpp -void SingleApplication::receivedMessage( quint32 instanceId, QByteArray message ) -``` - -Triggered whenever there is a message received from a secondary instance. - ---- - -### Flags - -```cpp -enum SingleApplication::Mode -``` - -* `Mode::User` - The SingleApplication block should apply user wide. This adds - user specific data to the key used for the shared memory and server name. - This is the default functionality. -* `Mode::System` – The SingleApplication block applies system-wide. -* `Mode::SecondaryNotification` – Whether to trigger `instanceStarted()` even - whenever secondary instances are started. -* `Mode::ExcludeAppPath` – Excludes the application path from the server name - (and memory block) hash. -* `Mode::ExcludeAppVersion` – Excludes the application version from the server - name (and memory block) hash. - -*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary -and the secondary instance.* - -*__Note:__ Operating system can restrict the shared memory blocks to the same -user, in which case the User/System modes will have no effect and the block will -be user wide.* - ---- - -Versioning ----------- - -Each major version introduces either very significant changes or is not -backwards compatible with the previous version. Minor versions only add -additional features, bug fixes or performance improvements and are backwards -compatible with the previous release. See [`CHANGELOG.md`](CHANGELOG.md) for -more details. - -Implementation --------------- - -The library is implemented with a QSharedMemory block which is thread safe and -guarantees a race condition will not occur. It also uses a QLocalSocket to -notify the main process that a new instance had been spawned and thus invoke the -`instanceStarted()` signal and for messaging the primary instance. - -Additionally the library can recover from being forcefully killed on *nix -systems and will reset the memory block given that there are no other -instances running. - -License -------- -This library and it's supporting documentation are released under -`The MIT License (MIT)` with the exception of the Qt calculator examples which -is distributed under the BSD license. diff --git a/3rd-parties/SingleApplication/Windows.md b/3rd-parties/SingleApplication/Windows.md deleted file mode 100644 index 13c52da..0000000 --- a/3rd-parties/SingleApplication/Windows.md +++ /dev/null @@ -1,46 +0,0 @@ -Windows Specific Implementations -================================ - -Setting the foreground window ------------------------------ - -In the `instanceStarted()` example in the `README` we demonstrated how an -application can bring it's primary instance window whenever a second copy -of the application is started. - -On Windows the ability to bring the application windows to the foreground is -restricted, see [`AllowSetForegroundWindow()`][AllowSetForegroundWindow] for more -details. - -The background process (the primary instance) can bring its windows to the -foreground if it is allowed by the current foreground process (the secondary -instance). To bypass this `SingleApplication` must be initialized with the -`allowSecondary` parameter set to `true` and the `options` parameter must -include `Mode::SecondaryNotification`, See `SingleApplication::Mode` for more -details. - -Here is an example: - -```cpp -if( app.isSecondary() ) { - // This API requires LIBS += User32.lib to be added to the project - AllowSetForegroundWindow( DWORD( app.primaryPid() ) ); -} - -if( app.isPrimary() ) { - QObject::connect( - &app, - &SingleApplication::instanceStarted, - this, - &App::instanceStarted - ); -} -``` - -```cpp -void App::instanceStarted() { - QApplication::setActiveWindow( [window/widget to set to the foreground] ); -} -``` - -[AllowSetForegroundWindow]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632668.aspx diff --git a/3rd-parties/SingleApplication/singleapplication.cpp b/3rd-parties/SingleApplication/singleapplication.cpp deleted file mode 100644 index d434b40..0000000 --- a/3rd-parties/SingleApplication/singleapplication.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) Itay Grudev 2015 - 2018 -// -// 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: -// -// 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, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include -#include -#include - -#include "singleapplication.h" -#include "singleapplication_p.h" - -/** - * @brief Constructor. Checks and fires up LocalServer or closes the program - * if another instance already exists - * @param argc - * @param argv - * @param {bool} allowSecondaryInstances - */ -SingleApplication::SingleApplication(int &argc, char *argv[], const char* appName, bool allowSecondary, Options options, int timeout ) - : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) ) -{ - Q_D(SingleApplication); - -#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) - // On Android and iOS since the library is not supported fallback to - // standard QApplication behaviour by simply returning at this point. - qWarning() << "SingleApplication is not supported on Android and iOS systems."; - return; -#endif - - // Store the current mode of the program - d->options = options; - - // Generating an application ID used for identifying the shared memory - // block and QLocalServer - d->genBlockServerName(appName); - -#ifdef Q_OS_UNIX - // By explicitly attaching it and then deleting it we make sure that the - // memory is deleted even after the process has crashed on Unix. - d->memory = new QSharedMemory( d->blockServerName ); - d->memory->attach(); - delete d->memory; -#endif - // Guarantee thread safe behaviour with a shared memory block. - d->memory = new QSharedMemory( d->blockServerName ); - - // Create a shared memory block - if( d->memory->create( sizeof( InstancesInfo ) ) ) { - // Initialize the shared memory block - d->memory->lock(); - d->initializeMemoryBlock(); - d->memory->unlock(); - } else { - // Attempt to attach to the memory segment - if( ! d->memory->attach() ) { - qCritical() << "SingleApplication: Unable to attach to shared memory block."; - qCritical() << d->memory->errorString(); - delete d; - ::exit( EXIT_FAILURE ); - } - } - - InstancesInfo* inst = static_cast( d->memory->data() ); - QTime time; - time.start(); - - // Make sure the shared memory block is initialised and in consistent state - while( true ) { - d->memory->lock(); - - if( d->blockChecksum() == inst->checksum ) break; - - if( time.elapsed() > 5000 ) { - qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure."; - d->initializeMemoryBlock(); - } - - d->memory->unlock(); - - // Random sleep here limits the probability of a collision between two racing apps - qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits::max() ); - QThread::sleep( 8 + static_cast ( static_cast ( qrand() ) / RAND_MAX * 10 ) ); - } - - if( inst->primary == false) { - d->startPrimary(); - d->memory->unlock(); - return; - } - - // Check if another instance can be started - if( allowSecondary ) { - inst->secondary += 1; - inst->checksum = d->blockChecksum(); - d->instanceNumber = inst->secondary; - d->startSecondary(); - if( d->options & Mode::SecondaryNotification ) { - d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance ); - } - d->memory->unlock(); - return; - } - - d->memory->unlock(); - - d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance ); - - delete d; - - ::exit( EXIT_SUCCESS ); -} - -/** - * @brief Destructor - */ -SingleApplication::~SingleApplication() -{ - Q_D(SingleApplication); - delete d; -} - -bool SingleApplication::isPrimary() -{ - Q_D(SingleApplication); - return d->server != nullptr; -} - -bool SingleApplication::isSecondary() -{ - Q_D(SingleApplication); - return d->server == nullptr; -} - -quint32 SingleApplication::instanceId() -{ - Q_D(SingleApplication); - return d->instanceNumber; -} - -qint64 SingleApplication::primaryPid() -{ - Q_D(SingleApplication); - return d->primaryPid(); -} - -bool SingleApplication::sendMessage( QByteArray message, int timeout ) -{ - Q_D(SingleApplication); - - // Nobody to connect to - if( isPrimary() ) return false; - - // Make sure the socket is connected - d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect ); - - d->socket->write( message ); - bool dataWritten = d->socket->waitForBytesWritten( timeout ); - d->socket->flush(); - return dataWritten; -} diff --git a/3rd-parties/SingleApplication/singleapplication.h b/3rd-parties/SingleApplication/singleapplication.h deleted file mode 100644 index 1fedd4c..0000000 --- a/3rd-parties/SingleApplication/singleapplication.h +++ /dev/null @@ -1,135 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) Itay Grudev 2015 - 2018 -// -// 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: -// -// 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, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef SINGLE_APPLICATION_H -#define SINGLE_APPLICATION_H - -#include -#include - -#ifndef QAPPLICATION_CLASS -#define QAPPLICATION_CLASS QCoreApplication -#endif - -#include QT_STRINGIFY(QAPPLICATION_CLASS) - -class SingleApplicationPrivate; - -/** - * @brief The SingleApplication class handles multiple instances of the same - * Application - * @see QCoreApplication - */ -class SingleApplication : public QAPPLICATION_CLASS -{ - Q_OBJECT - - typedef QAPPLICATION_CLASS app_t; - -public: - /** - * @brief Mode of operation of SingleApplication. - * Whether the block should be user-wide or system-wide and whether the - * primary instance should be notified when a secondary instance had been - * started. - * @note Operating system can restrict the shared memory blocks to the same - * user, in which case the User/System modes will have no effect and the - * block will be user wide. - * @enum - */ - enum Mode { - User = 1 << 0, - System = 1 << 1, - SecondaryNotification = 1 << 2, - ExcludeAppVersion = 1 << 3, - ExcludeAppPath = 1 << 4 - }; - Q_DECLARE_FLAGS(Options, Mode) - - /** - * @brief Intitializes a SingleApplication instance with argc command line - * arguments in argv - * @arg {int &} argc - Number of arguments in argv - * @arg {const char *[]} argv - Supplied command line arguments - * @arg {bool} allowSecondary - Whether to start the instance as secondary - * if there is already a primary instance. - * @arg {Mode} mode - Whether for the SingleApplication block to be applied - * User wide or System wide. - * @arg {int} timeout - Timeout to wait in milliseconds. - * @note argc and argv may be changed as Qt removes arguments that it - * recognizes - * @note Mode::SecondaryNotification only works if set on both the primary - * instance and the secondary instance. - * @note The timeout is just a hint for the maximum time of blocking - * operations. It does not guarantee that the SingleApplication - * initialisation will be completed in given time, though is a good hint. - * Usually 4*timeout would be the worst case (fail) scenario. - * @see See the corresponding QAPPLICATION_CLASS constructor for reference - */ - explicit SingleApplication(int &argc, char *argv[], const char *appName = "SingleApplication", bool allowSecondary = false, Options options = Mode::User, int timeout = 1000 ); - ~SingleApplication(); - - /** - * @brief Returns if the instance is the primary instance - * @returns {bool} - */ - bool isPrimary(); - - /** - * @brief Returns if the instance is a secondary instance - * @returns {bool} - */ - bool isSecondary(); - - /** - * @brief Returns a unique identifier for the current instance - * @returns {qint32} - */ - quint32 instanceId(); - - /** - * @brief Returns the process ID (PID) of the primary instance - * @returns {qint64} - */ - qint64 primaryPid(); - - /** - * @brief Sends a message to the primary instance. Returns true on success. - * @param {int} timeout - Timeout for connecting - * @returns {bool} - * @note sendMessage() will return false if invoked from the primary - * instance. - */ - bool sendMessage( QByteArray message, int timeout = 100 ); - -Q_SIGNALS: - void instanceStarted(); - void receivedMessage( quint32 instanceId, QByteArray message ); - -private: - SingleApplicationPrivate *d_ptr; - Q_DECLARE_PRIVATE(SingleApplication) -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options) - -#endif // SINGLE_APPLICATION_H diff --git a/3rd-parties/SingleApplication/singleapplication.pri b/3rd-parties/SingleApplication/singleapplication.pri deleted file mode 100644 index 26f5c9c..0000000 --- a/3rd-parties/SingleApplication/singleapplication.pri +++ /dev/null @@ -1,19 +0,0 @@ -QT += core network -CONFIG += c++11 - -HEADERS += $$PWD/singleapplication.h \ - $$PWD/singleapplication_p.h -SOURCES += $$PWD/singleapplication.cpp \ - $$PWD/singleapplication_p.cpp - -INCLUDEPATH += $$PWD - -win32 { - msvc:LIBS += Advapi32.lib - gcc:LIBS += -ladvapi32 -} - -DISTFILES += \ - $$PWD/README.md \ - $$PWD/CHANGELOG.md \ - $$PWD/Windows.md diff --git a/3rd-parties/SingleApplication/singleapplication_p.cpp b/3rd-parties/SingleApplication/singleapplication_p.cpp deleted file mode 100644 index 2b44af9..0000000 --- a/3rd-parties/SingleApplication/singleapplication_p.cpp +++ /dev/null @@ -1,407 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) Itay Grudev 2015 - 2018 -// -// 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: -// -// 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, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// -// W A R N I N G !!! -// ----------------- -// -// This file is not part of the SingleApplication API. It is used purely as an -// implementation detail. This header file may change from version to -// version without notice, or may even be removed. -// - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "singleapplication.h" -#include "singleapplication_p.h" - -#ifdef Q_OS_UNIX -#include -#include -#include -#endif - -#ifdef Q_OS_WIN -#include -#include -#endif - -SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr ) - : q_ptr( q_ptr ) -{ - server = nullptr; - socket = nullptr; - memory = nullptr; - instanceNumber = -1; -} - -SingleApplicationPrivate::~SingleApplicationPrivate() -{ - if( socket != nullptr ) { - socket->close(); - delete socket; - } - - memory->lock(); - InstancesInfo* inst = static_cast(memory->data()); - if( server != nullptr ) { - server->close(); - delete server; - inst->primary = false; - inst->primaryPid = -1; - inst->checksum = blockChecksum(); - } - memory->unlock(); - - delete memory; -} - -void SingleApplicationPrivate::genBlockServerName(const char* appName) -{ - QCryptographicHash appData( QCryptographicHash::Sha256 ); - appData.addData( appName, 17 ); - appData.addData( SingleApplication::app_t::applicationName().toUtf8() ); - appData.addData( SingleApplication::app_t::organizationName().toUtf8() ); - appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() ); - - if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ) { - appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() ); - } - - if( ! (options & SingleApplication::Mode::ExcludeAppPath) ) { -#ifdef Q_OS_WIN - appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() ); -#else - appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() ); -#endif - } - - // User level block requires a user specific data in the hash - if( options & SingleApplication::Mode::User ) { -#ifdef Q_OS_WIN - wchar_t username [ UNLEN + 1 ]; - // Specifies size of the buffer on input - DWORD usernameLength = UNLEN + 1; - if( GetUserNameW( username, &usernameLength ) ) { - appData.addData( QString::fromWCharArray(username).toUtf8() ); - } else { - appData.addData( qgetenv("USERNAME") ); - } -#endif -#ifdef Q_OS_UNIX - QByteArray username; - uid_t uid = geteuid(); - struct passwd *pw = getpwuid(uid); - if( pw ) { - username = pw->pw_name; - } - if( username.isEmpty() ) { - username = qgetenv("USER"); - } - appData.addData(username); -#endif - } - - appData.addData(qgetenv("DISPLAY")); - - // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with - // server naming requirements. - blockServerName = appData.result().toBase64().replace("/", "_"); -} - -void SingleApplicationPrivate::initializeMemoryBlock() -{ - InstancesInfo* inst = static_cast( memory->data() ); - inst->primary = false; - inst->secondary = 0; - inst->primaryPid = -1; - inst->checksum = blockChecksum(); -} - -void SingleApplicationPrivate::startPrimary() -{ - Q_Q(SingleApplication); - - // Successful creation means that no main process exists - // So we start a QLocalServer to listen for connections - QLocalServer::removeServer( blockServerName ); - server = new QLocalServer(); - - // Restrict access to the socket according to the - // SingleApplication::Mode::User flag on User level or no restrictions - if( options & SingleApplication::Mode::User ) { - server->setSocketOptions( QLocalServer::UserAccessOption ); - } else { - server->setSocketOptions( QLocalServer::WorldAccessOption ); - } - - server->listen( blockServerName ); - QObject::connect( - server, - &QLocalServer::newConnection, - this, - &SingleApplicationPrivate::slotConnectionEstablished - ); - - // Reset the number of connections - InstancesInfo* inst = static_cast ( memory->data() ); - - inst->primary = true; - inst->primaryPid = q->applicationPid(); - inst->checksum = blockChecksum(); - - instanceNumber = 0; -} - -void SingleApplicationPrivate::startSecondary() -{ -} - -void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType ) -{ - // Connect to the Local Server of the Primary Instance if not already - // connected. - if( socket == nullptr ) { - socket = new QLocalSocket(); - } - - // If already connected - we are done; - if( socket->state() == QLocalSocket::ConnectedState ) - return; - - // If not connect - if( socket->state() == QLocalSocket::UnconnectedState || - socket->state() == QLocalSocket::ClosingState ) { - socket->connectToServer( blockServerName ); - } - - // Wait for being connected - if( socket->state() == QLocalSocket::ConnectingState ) { - socket->waitForConnected( msecs ); - } - - // Initialisation message according to the SingleApplication protocol - if( socket->state() == QLocalSocket::ConnectedState ) { - // Notify the parent that a new instance had been started; - QByteArray initMsg; - QDataStream writeStream(&initMsg, QIODevice::WriteOnly); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - writeStream.setVersion(QDataStream::Qt_5_6); -#endif - - writeStream << blockServerName.toLatin1(); - writeStream << static_cast(connectionType); - writeStream << instanceNumber; - quint16 checksum = qChecksum(initMsg.constData(), static_cast(initMsg.length())); - writeStream << checksum; - - // The header indicates the message length that follows - QByteArray header; - QDataStream headerStream(&header, QIODevice::WriteOnly); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - headerStream.setVersion(QDataStream::Qt_5_6); -#endif - headerStream << static_cast ( initMsg.length() ); - - socket->write( header ); - socket->write( initMsg ); - socket->flush(); - socket->waitForBytesWritten( msecs ); - } -} - -quint16 SingleApplicationPrivate::blockChecksum() -{ - return qChecksum( - static_cast ( memory->data() ), - offsetof( InstancesInfo, checksum ) - ); -} - -qint64 SingleApplicationPrivate::primaryPid() -{ - qint64 pid; - - memory->lock(); - InstancesInfo* inst = static_cast( memory->data() ); - pid = inst->primaryPid; - memory->unlock(); - - return pid; -} - -/** - * @brief Executed when a connection has been made to the LocalServer - */ -void SingleApplicationPrivate::slotConnectionEstablished() -{ - QLocalSocket *nextConnSocket = server->nextPendingConnection(); - connectionMap.insert(nextConnSocket, ConnectionInfo()); - - QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, - [nextConnSocket, this]() { - auto &info = connectionMap[nextConnSocket]; - Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId ); - } - ); - - QObject::connect(nextConnSocket, &QLocalSocket::disconnected, - [nextConnSocket, this]() { - connectionMap.remove(nextConnSocket); - nextConnSocket->deleteLater(); - } - ); - - QObject::connect(nextConnSocket, &QLocalSocket::readyRead, - [nextConnSocket, this]() { - auto &info = connectionMap[nextConnSocket]; - switch(info.stage) { - case StageHeader: - readInitMessageHeader(nextConnSocket); - break; - case StageBody: - readInitMessageBody(nextConnSocket); - break; - case StageConnected: - Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId ); - break; - default: - break; - }; - } - ); -} - -void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock ) -{ - if (!connectionMap.contains( sock )) { - return; - } - - if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ) { - return; - } - - QDataStream headerStream( sock ); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - headerStream.setVersion( QDataStream::Qt_5_6 ); -#endif - - // Read the header to know the message length - quint64 msgLen = 0; - headerStream >> msgLen; - ConnectionInfo &info = connectionMap[sock]; - info.stage = StageBody; - info.msgLen = msgLen; - - if ( sock->bytesAvailable() >= (qint64) msgLen ) { - readInitMessageBody( sock ); - } -} - -void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock ) -{ - Q_Q(SingleApplication); - - if (!connectionMap.contains( sock )) { - return; - } - - ConnectionInfo &info = connectionMap[sock]; - if( sock->bytesAvailable() < ( qint64 )info.msgLen ) { - return; - } - - // Read the message body - QByteArray msgBytes = sock->read(info.msgLen); - QDataStream readStream(msgBytes); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - readStream.setVersion( QDataStream::Qt_5_6 ); -#endif - - // server name - QByteArray latin1Name; - readStream >> latin1Name; - - // connection type - ConnectionType connectionType = InvalidConnection; - quint8 connTypeVal = InvalidConnection; - readStream >> connTypeVal; - connectionType = static_cast ( connTypeVal ); - - // instance id - quint32 instanceId = 0; - readStream >> instanceId; - - // checksum - quint16 msgChecksum = 0; - readStream >> msgChecksum; - - const quint16 actualChecksum = qChecksum( msgBytes.constData(), static_cast( msgBytes.length() - sizeof( quint16 ) ) ); - - bool isValid = readStream.status() == QDataStream::Ok && - QLatin1String(latin1Name) == blockServerName && - msgChecksum == actualChecksum; - - if( !isValid ) { - sock->close(); - return; - } - - info.instanceId = instanceId; - info.stage = StageConnected; - - if( connectionType == NewInstance || - ( connectionType == SecondaryInstance && - options & SingleApplication::Mode::SecondaryNotification ) ) - { - Q_EMIT q->instanceStarted(); - } - - if (sock->bytesAvailable() > 0) { - Q_EMIT this->slotDataAvailable( sock, instanceId ); - } -} - -void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId ) -{ - Q_Q(SingleApplication); - Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() ); -} - -void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId ) -{ - if( closedSocket->bytesAvailable() > 0 ) - Q_EMIT slotDataAvailable( closedSocket, instanceId ); -} diff --git a/3rd-parties/SingleApplication/singleapplication_p.h b/3rd-parties/SingleApplication/singleapplication_p.h deleted file mode 100644 index 1247837..0000000 --- a/3rd-parties/SingleApplication/singleapplication_p.h +++ /dev/null @@ -1,99 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) Itay Grudev 2015 - 2016 -// -// 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: -// -// 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, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// -// W A R N I N G !!! -// ----------------- -// -// This file is not part of the SingleApplication API. It is used purely as an -// implementation detail. This header file may change from version to -// version without notice, or may even be removed. -// - -#ifndef SINGLEAPPLICATION_P_H -#define SINGLEAPPLICATION_P_H - -#include -#include -#include -#include "singleapplication.h" - -struct InstancesInfo { - bool primary; - quint32 secondary; - qint64 primaryPid; - quint16 checksum; -}; - -struct ConnectionInfo { - explicit ConnectionInfo() : - msgLen(0), instanceId(0), stage(0) {} - qint64 msgLen; - quint32 instanceId; - quint8 stage; -}; - -class SingleApplicationPrivate : public QObject { - Q_OBJECT -public: - enum ConnectionType : quint8 { - InvalidConnection = 0, - NewInstance = 1, - SecondaryInstance = 2, - Reconnect = 3 - }; - enum ConnectionStage : quint8 { - StageHeader = 0, - StageBody = 1, - StageConnected = 2, - }; - Q_DECLARE_PUBLIC(SingleApplication) - - SingleApplicationPrivate( SingleApplication *q_ptr ); - ~SingleApplicationPrivate(); - - void genBlockServerName(const char *appName); - void initializeMemoryBlock(); - void startPrimary(); - void startSecondary(); - void connectToPrimary(int msecs, ConnectionType connectionType ); - quint16 blockChecksum(); - qint64 primaryPid(); - void readInitMessageHeader(QLocalSocket *socket); - void readInitMessageBody(QLocalSocket *socket); - - SingleApplication *q_ptr; - QSharedMemory *memory; - QLocalSocket *socket; - QLocalServer *server; - quint32 instanceNumber; - QString blockServerName; - SingleApplication::Options options; - QMap connectionMap; - -public Q_SLOTS: - void slotConnectionEstablished(); - void slotDataAvailable( QLocalSocket*, quint32 ); - void slotClientConnectionClosed( QLocalSocket*, quint32 ); -}; - -#endif // SINGLEAPPLICATION_P_H diff --git a/3rd-parties/qtsingleapplication/CMakeLists.txt b/3rd-parties/qtsingleapplication/CMakeLists.txt new file mode 100644 index 0000000..4c93029 --- /dev/null +++ b/3rd-parties/qtsingleapplication/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16) +project(qtsingleapplication) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Widgets Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Widgets Network REQUIRED) + +include_directories(src) +set(SRCS src/qtsingleapplication.h src/qtsingleapplication.cpp src/qtlocalpeer.h src/qtlocalpeer.cpp) + +add_library(${PROJECT_NAME} STATIC ${SRCS}) +target_include_directories(${PROJECT_NAME} PRIVATE src) +target_link_libraries(${PROJECT_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Network) \ No newline at end of file diff --git a/3rd-parties/qtsingleapplication/INSTALL.TXT b/3rd-parties/qtsingleapplication/INSTALL.TXT new file mode 100644 index 0000000..bbb74a9 --- /dev/null +++ b/3rd-parties/qtsingleapplication/INSTALL.TXT @@ -0,0 +1,254 @@ +INSTALLATION INSTRUCTIONS + +These instructions refer to the package you are installing as +some-package.tar.gz or some-package.zip. The .zip file is intended for use +on Windows. + +The directory you choose for the installation will be referred to as +your-install-dir. + +Note to Qt Visual Studio Integration users: In the instructions below, +instead of building from command line with nmake, you can use the menu +command 'Qt->Open Solution from .pro file' on the .pro files in the +example and plugin directories, and then build from within Visual +Studio. + +Unpacking and installation +-------------------------- + +1. Unpacking the archive (if you have not done so already). + + On Unix and Mac OS X (in a terminal window): + + cd your-install-dir + gunzip some-package.tar.gz + tar xvf some-package.tar + + This creates the subdirectory some-package containing the files. + + On Windows: + + Unpack the .zip archive by right-clicking it in explorer and + choosing "Extract All...". If your version of Windows does not + have zip support, you can use the infozip tools available + from www.info-zip.org. + + If you are using the infozip tools (in a command prompt window): + cd your-install-dir + unzip some-package.zip + +2. Configuring the package. + + The configure script is called "configure" on unix/mac and + "configure.bat" on Windows. It should be run from a command line + after cd'ing to the package directory. + + You can choose whether you want to use the component by including + its source code directly into your project, or build the component + as a dynamic shared library (DLL) that is loaded into the + application at run-time. The latter may be preferable for + technical or licensing (LGPL) reasons. If you want to build a DLL, + run the configure script with the argument "-library". Also see + the note about usage below. + + (Components that are Qt plugins, e.g. styles and image formats, + are by default built as a plugin DLL.) + + The configure script will prompt you in some cases for further + information. Answer these questions and carefully read the license text + before accepting the license conditions. The package cannot be used if + you do not accept the license conditions. + +3. Building the component and examples (when required). + + If a DLL is to be built, or if you would like to build the + examples, next give the commands + + qmake + make [or nmake if your are using Microsoft Visual C++] + + The example program(s) can be found in the directory called + "examples" or "example". + + Components that are Qt plugins, e.g. styles and image formats, are + ready to be used as soon as they are built, so the rest of this + installation instruction can be skipped. + +4. Building the Qt Designer plugin (optional). + + Some of the widget components are provided with plugins for Qt + Designer. To build and install the plugin, cd into the + some-package/plugin directory and give the commands + + qmake + make [or nmake if your are using Microsoft Visual C++] + + Restart Qt Designer to make it load the new widget plugin. + + Note: If you are using the built-in Qt Designer from the Qt Visual + Studio Integration, you will need to manually copy the plugin DLL + file, i.e. copy + %QTDIR%\plugins\designer\some-component.dll + to the Qt Visual Studio Integration plugin path, typically: + C:\Program Files\Trolltech\Qt VS Integration\plugins + + Note: If you for some reason are using a Qt Designer that is built + in debug mode, you will need to build the plugin in debug mode + also. Edit the file plugin.pro in the plugin directory, changing + 'release' to 'debug' in the CONFIG line, before running qmake. + + + +Solutions components are intended to be used directly from the package +directory during development, so there is no 'make install' procedure. + + +Using a component in your project +--------------------------------- + +To use this component in your project, add the following line to the +project's .pro file (or do the equivalent in your IDE): + + include(your-install-dir/some-package/src/some-package.pri) + +This adds the package's sources and headers to the SOURCES and HEADERS +project variables respectively (or, if the component has been +configured as a DLL, it adds that library to the LIBS variable), and +updates INCLUDEPATH to contain the package's src +directory. Additionally, the .pri file may include some dependencies +needed by the package. + +To include a header file from the package in your sources, you can now +simply use: + + #include + +or alternatively, in pre-Qt 4 style: + + #include + +Refer to the documentation to see the classes and headers this +components provides. + + + +Install documentation (optional) +-------------------------------- + +The HTML documentation for the package's classes is located in the +your-install-dir/some-package/doc/html/index.html. You can open this +file and read the documentation with any web browser. + +To install the documentation into Qt Assistant (for Qt version 4.4 and +later): + +1. In Assistant, open the Edit->Preferences dialog and choose the + Documentation tab. Click the Add... button and select the file + your-install-dir/some-package/doc/html/some-package.qch + +For Qt versions prior to 4.4, do instead the following: + +1. The directory your-install-dir/some-package/doc/html contains a + file called some-package.dcf. Execute the following commands in a + shell, command prompt or terminal window: + + cd your-install-dir/some-package/doc/html/ + assistant -addContentFile some-package.dcf + +The next time you start Qt Assistant, you can access the package's +documentation. + + +Removing the documentation from assistant +----------------------------------------- + +If you have installed the documentation into Qt Assistant, and want to uninstall it, do as follows, for Qt version 4.4 and later: + +1. In Assistant, open the Edit->Preferences dialog and choose the + Documentation tab. In the list of Registered Documentation, select + the item com.nokia.qtsolutions.some-package_version, and click + the Remove button. + +For Qt versions prior to 4.4, do instead the following: + +1. The directory your-install-dir/some-package/doc/html contains a + file called some-package.dcf. Execute the following commands in a + shell, command prompt or terminal window: + + cd your-install-dir/some-package/doc/html/ + assistant -removeContentFile some-package.dcf + + + +Using the component as a DLL +---------------------------- + +1. Normal components + + The shared library (DLL) is built and placed in the + some-package/lib directory. It is intended to be used directly + from there during development. When appropriate, both debug and + release versions are built, since the run-time linker will in some + cases refuse to load a debug-built DLL into a release-built + application or vice versa. + + The following steps are taken by default to help the dynamic + linker to locate the DLL at run-time (during development): + + Unix: The some-package.pri file will add linker instructions to + add the some-package/lib directory to the rpath of the + executable. (When distributing, or if your system does not support + rpath, you can copy the shared library to another place that is + searched by the dynamic linker, e.g. the "lib" directory of your + Qt installation.) + + Mac: The full path to the library is hardcoded into the library + itself, from where it is copied into the executable at link time, + and ready by the dynamic linker at run-time. (When distributing, + you will want to edit these hardcoded paths in the same way as for + the Qt DLLs. Refer to the document "Deploying an Application on + Mac OS X" in the Qt Reference Documentation.) + + Windows: the .dll file(s) are copied into the "bin" directory of + your Qt installation. The Qt installation will already have set up + that directory to be searched by the dynamic linker. + + +2. Plugins + + For Qt Solutions plugins (e.g. image formats), both debug and + release versions of the plugin are built by default when + appropriate, since in some cases the release Qt library will not + load a debug plugin, and vice versa. The plugins are automatically + copied into the plugins directory of your Qt installation when + built, so no further setup is required. + + Plugins may also be built statically, i.e. as a library that will be + linked into your application executable, and so will not need to + be redistributed as a separate plugin DLL to end users. Static + building is required if Qt itself is built statically. To do it, + just add "static" to the CONFIG variable in the plugin/plugin.pro + file before building. Refer to the "Static Plugins" section in the + chapter "How to Create Qt Plugins" for explanation of how to use a + static plugin in your application. The source code of the example + program(s) will also typically contain the relevant instructions + as comments. + + + +Uninstalling +------------ + + The following command will remove any fils that have been + automatically placed outside the package directory itself during + installation and building + + make distclean [or nmake if your are using Microsoft Visual C++] + + If Qt Assistant documentation or Qt Designer plugins have been + installed, they can be uninstalled manually, ref. above. + + +Enjoy! :) + +- The Qt Solutions Team. diff --git a/3rd-parties/qtsingleapplication/README.TXT b/3rd-parties/qtsingleapplication/README.TXT new file mode 100644 index 0000000..06abb09 --- /dev/null +++ b/3rd-parties/qtsingleapplication/README.TXT @@ -0,0 +1,33 @@ +Qt Solutions Component: Single Application + +The QtSingleApplication component provides support for +applications that can be only started once per user. + + + +Version history: + +2.0: - Version 1.3 ported to Qt 4. + +2.1: - Fix compilation problem on Mac. + +2.2: - Really fix the Mac compilation problem. + - Mac: fix crash due to wrong object releasing. + - Mac: Fix memory leak. + +2.3: - Windows: Force creation of internal widget to make it work + with Qt 4.2. + +2.4: - Fix the system for automatic window raising on message + reception. NOTE: minor API change. + +2.5: - Mac: Fix isRunning() to work and report correctly. + +2.6: - - initialize() is now obsolete, no longer necessary to call + it + - - Fixed race condition where multiple instances migth be started + - - QtSingleCoreApplication variant provided for non-GUI (console) + usage + - Complete reimplementation. Visible changes: + - LGPL release. + diff --git a/3rd-parties/qtsingleapplication/buildlib/buildlib.pro b/3rd-parties/qtsingleapplication/buildlib/buildlib.pro new file mode 100644 index 0000000..37dddcd --- /dev/null +++ b/3rd-parties/qtsingleapplication/buildlib/buildlib.pro @@ -0,0 +1,13 @@ +TEMPLATE=lib +CONFIG += qt dll qtsingleapplication-buildlib +mac:CONFIG += absolute_library_soname +win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release build_all +include(../src/qtsingleapplication.pri) +TARGET = $$QTSINGLEAPPLICATION_LIBNAME +DESTDIR = $$QTSINGLEAPPLICATION_LIBDIR +win32 { + DLLDESTDIR = $$[QT_INSTALL_BINS] + QMAKE_DISTCLEAN += $$[QT_INSTALL_BINS]\\$${QTSINGLEAPPLICATION_LIBNAME}.dll +} +target.path = $$DESTDIR +INSTALLS += target diff --git a/3rd-parties/qtsingleapplication/common.pri b/3rd-parties/qtsingleapplication/common.pri new file mode 100644 index 0000000..924c57c --- /dev/null +++ b/3rd-parties/qtsingleapplication/common.pri @@ -0,0 +1,14 @@ +exists(config.pri):infile(config.pri, SOLUTIONS_LIBRARY, yes): CONFIG += qtsingleapplication-uselib + +TEMPLATE += fakelib +greaterThan(QT_MAJOR_VERSION, 5)|\ + if(equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 4))|\ + if(equals(QT_MAJOR_VERSION, 5):equals(QT_MINOR_VERSION, 4):greaterThan(QT_PATCH_VERSION, 1)) { + QTSINGLEAPPLICATION_LIBNAME = $$qt5LibraryTarget(QtSolutions_SingleApplication-head) +} else { + QTSINGLEAPPLICATION_LIBNAME = $$qtLibraryTarget(QtSolutions_SingleApplication-head) +} +TEMPLATE -= fakelib + +QTSINGLEAPPLICATION_LIBDIR = $$PWD/lib +unix:qtsingleapplication-uselib:!qtsingleapplication-buildlib:QMAKE_RPATHDIR += $$QTSINGLEAPPLICATION_LIBDIR diff --git a/3rd-parties/qtsingleapplication/configure b/3rd-parties/qtsingleapplication/configure new file mode 100755 index 0000000..3c4edff --- /dev/null +++ b/3rd-parties/qtsingleapplication/configure @@ -0,0 +1,25 @@ +#!/bin/sh + +if [ "x$1" != "x" -a "x$1" != "x-library" ]; then + echo "Usage: $0 [-library]" + echo + echo "-library: Build the component as a dynamic library (DLL). Default is to" + echo " include the component source code directly in the application." + echo + exit 0 +fi + +rm -f config.pri +if [ "x$1" = "x-library" ]; then + echo "Configuring to build this component as a dynamic library." + echo "SOLUTIONS_LIBRARY = yes" > config.pri +fi + +echo +echo "This component is now configured." +echo +echo "To build the component library (if requested) and example(s)," +echo "run qmake and your make command." +echo +echo "To remove or reconfigure, run make distclean." +echo diff --git a/3rd-parties/qtsingleapplication/configure.bat b/3rd-parties/qtsingleapplication/configure.bat new file mode 100644 index 0000000..2927549 --- /dev/null +++ b/3rd-parties/qtsingleapplication/configure.bat @@ -0,0 +1,43 @@ +:: Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +:: SPDX-License-Identifier: BSD-3-Clause + +@echo off + +rem +rem "Main" +rem + +if not "%1"=="" ( + if not "%1"=="-library" ( + call :PrintUsage + goto EOF + ) +) + +if exist config.pri. del config.pri +if "%1"=="-library" ( + echo Configuring to build this component as a dynamic library. + echo SOLUTIONS_LIBRARY = yes > config.pri +) + +echo . +echo This component is now configured. +echo . +echo To build the component library (if requested) and example(s), +echo run qmake and your make or nmake command. +echo . +echo To remove or reconfigure, run make (nmake) distclean. +echo . +goto EOF + +:PrintUsage +echo Usage: configure.bat [-library] +echo . +echo -library: Build the component as a dynamic library (DLL). Default is to +echo include the component source directly in the application. +echo A DLL may be preferable for technical or licensing (LGPL) reasons. +echo . +goto EOF + + +:EOF diff --git a/3rd-parties/qtsingleapplication/doc/html/classic.css b/3rd-parties/qtsingleapplication/doc/html/classic.css new file mode 100644 index 0000000..b8cae8e --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/classic.css @@ -0,0 +1,284 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Arial, Geneva, Helvetica, sans-serif; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} + +h3.fn,span.fn +{ + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 0px 6px 10px; + margin: 42px 0px 0px 0px; +} + +hr { + border: 0; + color: #a0a0a0; + background-color: #ccc; + height: 1px; + width: 100%; + text-align: left; + margin: 34px 0px 34px 0px; +} + +table.valuelist { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-color: #dddddd; + border-collapse: collapse; + background-color: #f0f0f0; +} + +table.indextable { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; + font-size: 100%; +} + +table td.largeindex { + border-width: 1px 1px 1px 1px; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; + font-size: 120%; +} + +table.valuelist th { + border-width: 1px 1px 1px 2px; + padding: 4px; + border-style: solid; + border-color: #666; + color:white; + background-color:#666; +} + +th.titleheader { + border-width: 1px 0px 1px 0px; + padding: 2px; + border-style: solid; + border-color: #666; + color:white; + background-color:#555; + background-image:url('images/gradient.png')}; + background-repeat: repeat-x; + font-size: 100%; +} + + +th.largeheader { + border-width: 1px 0px 1px 0px; + padding: 4px; + border-style: solid; + border-color: #444; + color:white; + background-color:#555555; + font-size: 120%; +} + +p { + + margin-left: 4px; + margin-top: 8px; + margin-bottom: 8px; +} + +a:link +{ + color: #0046ad; + text-decoration: none +} + +a:visited +{ + color: #672967; + text-decoration: none +} + +a.obsolete +{ + color: #661100; + text-decoration: none +} + +a.compat +{ + color: #661100; + text-decoration: none +} + +a.obsolete:visited +{ + color: #995500; + text-decoration: none +} + +a.compat:visited +{ + color: #995500; + text-decoration: none +} + +body +{ + background: #ffffff; + color: black +} + +table.generic, table.annotated +{ + border-width: 1px; + border-color:#bbb; + border-style:solid; + border-collapse:collapse; +} + +table td.memItemLeft { + width: 180px; + padding: 2px 0px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; + white-space: nowrap +} + +table td.memItemRight { + padding: 2px 8px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; +} + +table tr.odd { + background: #f0f0f0; + color: black; +} + +table tr.even { + background: #e4e4e4; + color: black; +} + +table.annotated th { + padding: 3px; + text-align: left +} + +table.annotated td { + padding: 3px; +} + +table tr pre +{ + padding-top: 0px; + padding-bottom: 0px; + padding-left: 0px; + padding-right: 0px; + border: none; + background: none +} + +tr.qt-style +{ + background: #96E066; + color: black +} + +body pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +table tr.qt-code pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +span.preprocessor, span.preprocessor a +{ + color: darkblue; +} + +span.comment +{ + color: darkred; + font-style: italic +} + +span.string,span.char +{ + color: darkgreen; +} + +.title +{ + text-align: center +} + +.subtitle +{ + font-size: 0.8em +} + +.small-subtitle +{ + font-size: 0.65em +} + +.qmlitem { + padding: 0; +} + +.qmlname { + white-space: nowrap; +} + +.qmltype { + text-align: center; + font-size: 160%; +} + +.qmlproto { + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 10px 6px 10px; + margin: 42px 0px 0px 0px; +} + +.qmlreadonly { + float: right; + color: red +} + +.qmldoc { +} + +*.qmlitem p { +} diff --git a/3rd-parties/qtsingleapplication/doc/html/images/qt-logo.png b/3rd-parties/qtsingleapplication/doc/html/images/qt-logo.png new file mode 100644 index 0000000..794162f Binary files /dev/null and b/3rd-parties/qtsingleapplication/doc/html/images/qt-logo.png differ diff --git a/3rd-parties/qtsingleapplication/doc/html/index.html b/3rd-parties/qtsingleapplication/doc/html/index.html new file mode 100644 index 0000000..af9dab1 --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/index.html @@ -0,0 +1,48 @@ + + + + + + Single Application + + + + + + + +
  Home

Single Application
+

+ +

Description

+

The QtSingleApplication component provides support for applications that can be only started once per user.

+

For some applications it is useful or even critical that they are started only once by any user. Future attempts to start the application should activate any already running instance, and possibly perform requested actions, e.g. loading a file, in that instance.

+

The QtSingleApplication class provides an interface to detect a running instance, and to send command strings to that instance. For console (non-GUI) applications, the QtSingleCoreApplication variant is provided, which avoids dependency on QtGui.

+ +

Classes

+ + +

Examples

+ + +

Tested platforms

+
    +
  • Qt 4.4, 4.5 / Windows XP / MSVC.NET 2005
  • +
  • Qt 4.4, 4.5 / Linux / gcc
  • +
  • Qt 4.4, 4.5 / MacOS X 10.5 / gcc
  • +
+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-loader.html b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-loader.html new file mode 100644 index 0000000..6b92350 --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-loader.html @@ -0,0 +1,177 @@ + + + + + + Loading Documents + + + + + + + +
  Home

Loading Documents
+

+

The application in this example loads or prints the documents passed as commandline parameters to further instances of this application.

+
 /****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the Qt Solutions component.
+ **
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ **   * Redistributions of source code must retain the above copyright
+ **     notice, this list of conditions and the following disclaimer.
+ **   * 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.
+ **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ **     the names of its contributors may be used to endorse or promote
+ **     products derived from this software without specific prior written
+ **     permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "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 COPYRIGHT
+ ** OWNER OR CONTRIBUTORS 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 <qtsingleapplication.h>
+ #include <QtCore/QFile>
+ #include <QtGui/QMainWindow>
+ #include <QtGui/QPrinter>
+ #include <QtGui/QPainter>
+ #include <QtGui/QTextEdit>
+ #include <QtGui/QMdiArea>
+ #include <QtCore/QTextStream>
+
+ class MainWindow : public QMainWindow
+ {
+     Q_OBJECT
+ public:
+     MainWindow();
+
+ public slots:
+     void handleMessage(const QString& message);
+
+ signals:
+     void needToShow();
+
+ private:
+     QMdiArea *workspace;
+ };
+

The user interface in this application is a QMainWindow subclass with a QMdiArea as the central widget. It implements a slot handleMessage() that will be connected to the messageReceived() signal of the QtSingleApplication class.

+
 MainWindow::MainWindow()
+ {
+     workspace = new QMdiArea(this);
+
+     setCentralWidget(workspace);
+ }
+

The MainWindow constructor creates a minimal user interface.

+
 void MainWindow::handleMessage(const QString& message)
+ {
+     enum Action {
+         Nothing,
+         Open,
+         Print
+     } action;
+
+     action = Nothing;
+     QString filename = message;
+     if (message.toLower().startsWith("/print ")) {
+         filename = filename.mid(7);
+         action = Print;
+     } else if (!message.isEmpty()) {
+         action = Open;
+     }
+     if (action == Nothing) {
+         emit needToShow();
+         return;
+     }
+
+     QFile file(filename);
+     QString contents;
+     if (file.open(QIODevice::ReadOnly))
+         contents = file.readAll();
+     else
+         contents = "[[Error: Could not load file " + filename + "]]";
+
+     QTextEdit *view = new QTextEdit;
+     view->setPlainText(contents);
+
+     switch(action) {
+

The handleMessage() slot interprets the message passed in as a filename that can be prepended with /print to indicate that the file should just be printed rather than loaded.

+
     case Print:
+         {
+             QPrinter printer;
+             view->print(&printer);
+             delete view;
+         }
+         break;
+
+     case Open:
+         {
+             workspace->addSubWindow(view);
+             view->setWindowTitle(message);
+             view->show();
+             emit needToShow();
+         }
+         break;
+     default:
+         break;
+     };
+ }
+

Loading the file will also activate the window.

+
 #include "main.moc"
+
+ int main(int argc, char **argv)
+ {
+     QtSingleApplication instance("File loader QtSingleApplication example", argc, argv);
+     QString message;
+     for (int a = 1; a < argc; ++a) {
+         message += argv[a];
+         if (a < argc-1)
+             message += " ";
+     }
+
+     if (instance.sendMessage(message))
+         return 0;
+

The main entry point function creates a QtSingleApplication object, and creates a message to send to a running instance of the application. If the message was sent successfully the process exits immediately.

+
     MainWindow mw;
+     mw.handleMessage(message);
+     mw.show();
+
+     QObject::connect(&instance, SIGNAL(messageReceived(const QString&)),
+                      &mw, SLOT(handleMessage(const QString&)));
+
+     instance.setActivationWindow(&mw, false);
+     QObject::connect(&mw, SIGNAL(needToShow()), &instance, SLOT(activateWindow()));
+
+     return instance.exec();
+ }
+

If the message could not be sent the application starts up. Note that false is passed to the call to setActivationWindow() to prevent automatic activation for every message received, e.g. when +the application should just print a file. Instead, the message handling function determines whether activation is requested, and signals that by emitting the needToShow() signal. This is then simply connected +directly to QtSingleApplication's activateWindow() slot.

+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-trivial.html b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-trivial.html new file mode 100644 index 0000000..5e60cfa --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-example-trivial.html @@ -0,0 +1,101 @@ + + + + + + A Trivial Example + + + + + + + +
  Home

A Trivial Example
+

+

The application in this example has a log-view that displays messages sent by further instances of the same application.

+

The example demonstrates the use of the QtSingleApplication class to detect and communicate with a running instance of the application using the sendMessage() API. The messageReceived() signal is used to display received messages in a QTextEdit log.

+
 /****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the Qt Solutions component.
+ **
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ **   * Redistributions of source code must retain the above copyright
+ **     notice, this list of conditions and the following disclaimer.
+ **   * 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.
+ **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ **     the names of its contributors may be used to endorse or promote
+ **     products derived from this software without specific prior written
+ **     permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "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 COPYRIGHT
+ ** OWNER OR CONTRIBUTORS 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 <qtsingleapplication.h>
+ #include <QtGui/QTextEdit>
+
+ class TextEdit : public QTextEdit
+ {
+     Q_OBJECT
+ public:
+     TextEdit(QWidget *parent = 0)
+         : QTextEdit(parent)
+     {}
+ public slots:
+     void append(const QString &str)
+     {
+         QTextEdit::append(str);
+     }
+ };
+
+ #include "main.moc"
+
+ int main(int argc, char **argv)
+ {
+     QtSingleApplication instance(argc, argv);
+

The example has only the main entry point function. A QtSingleApplication object is created immediately.

+
     if (instance.sendMessage("Wake up!"))
+         return 0;
+

If another instance of this application is already running, sendMessage() will succeed, and this instance just exits immediately.

+
     TextEdit logview;
+     logview.setReadOnly(true);
+     logview.show();
+

Otherwise the instance continues as normal and creates the user interface.

+
     instance.setActivationWindow(&logview);
+
+     QObject::connect(&instance, SIGNAL(messageReceived(const QString&)),
+                      &logview, SLOT(append(const QString&)));
+
+     return instance.exec();
+

The logview object is also set as the application's activation window. Every time a message is received, the window will be raised and activated automatically.

+

The messageReceived() signal is also connected to the QTextEdit's append() slot. Every message received from further instances of this application will be displayed in the log.

+

Finally the event loop is entered.

+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-members.html b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-members.html new file mode 100644 index 0000000..c995ce3 --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-members.html @@ -0,0 +1,235 @@ + + + + + + List of All Members for QtSingleApplication + + + + + + + +
  Home

List of All Members for QtSingleApplication

+

This is the complete list of members for QtSingleApplication, including inherited members.

+

+ +
+

+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-obsolete.html b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-obsolete.html new file mode 100644 index 0000000..0d07dfa --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication-obsolete.html @@ -0,0 +1,31 @@ + + + + + + Obsolete Members for QtSingleApplication + + + + + + + +
  Home

Obsolete Members for QtSingleApplication

+

The following class members are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code.

+

+

Public Functions

+ + +
void initialize ( bool dummy = true )   (obsolete)
+
+

Member Function Documentation

+

void QtSingleApplication::initialize ( bool dummy = true )

+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.dcf b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.dcf new file mode 100644 index 0000000..d81f87f --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.dcf @@ -0,0 +1,40 @@ + + +
+
+ QtSingleApplication + activateWindow + activationWindow + id + isRunning + messageReceived + sendMessage + setActivationWindow +
+
+
+
+ QtSingleCoreApplication + id + isRunning + messageReceived + sendMessage +
+
+
+
+
+ A non-GUI example +
+
+ A Trivial Example +
+
+ Loading Documents +
+
+ Single Application +
+
+
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.html b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.html new file mode 100644 index 0000000..6a30744 --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.html @@ -0,0 +1,174 @@ + + + + + + QtSingleApplication Class Reference + + + + + + + +
  Home

QtSingleApplication Class Reference

+

The QtSingleApplication class provides an API to detect and communicate with running instances of an application. More...

+
 #include <QtSingleApplication>

Inherits QApplication.

+ +
+ +

Public Functions

+ + + + + + + + + + + +
QtSingleApplication ( int & argc, char ** argv, bool GUIenabled = true )
QtSingleApplication ( const QString & appId, int & argc, char ** argv )
QtSingleApplication ( int & argc, char ** argv, Type type )
QtSingleApplication ( Display * dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )
QtSingleApplication ( Display * dpy, int & argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )
QtSingleApplication ( Display * dpy, const QString & appId, int argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )
QWidget * activationWindow () const
QString id () const
bool isRunning ()
void setActivationWindow ( QWidget * aw, bool activateOnMessage = true )
+ +
+ +

Public Slots

+ + + +
void activateWindow ()
bool sendMessage ( const QString & message, int timeout = 5000 )
+ +
+ +

Signals

+ + +
void messageReceived ( const QString & message )
+ +

Additional Inherited Members

+ + +
+

Detailed Description

+

The QtSingleApplication class provides an API to detect and communicate with running instances of an application.

+

This class allows you to create applications where only one instance should be running at a time. I.e., if the user tries to launch another instance, the already running instance will be activated +instead. Another usecase is a client-server system, where the first started instance will assume the role of server, and the later instances will act as clients of that server.

+

By default, the full path of the executable file is used to determine whether two processes are instances of the same application. You can also provide an explicit identifier string that will be compared instead.

+

The application should create the QtSingleApplication object early in the startup phase, and call isRunning() to find out if another instance of this +application is already running. If isRunning() returns false, it means that no other instance is running, and this instance has assumed the role as the +running instance. In this case, the application should continue with the initialization of the application user interface before entering the event loop with exec(), as normal.

+

The messageReceived() signal will be emitted when the running application receives messages from another instance of the same application. When +a message is received it might be helpful to the user to raise the application so that it becomes visible. To facilitate this, QtSingleApplication provides +the setActivationWindow() function and the activateWindow() slot.

+

If isRunning() returns true, another instance is already running. It may be alerted to the fact that another instance has started by using +the sendMessage() function. Also data such as startup parameters (e.g. the name of the file the user wanted this new instance to open) can +be passed to the running instance with this function. Then, the application should terminate (or enter client mode).

+

If isRunning() returns true, but sendMessage() fails, that is an indication that the running instance is frozen.

+

Here's an example that shows how to convert an existing application to use QtSingleApplication. It is very simple and does not make use of all QtSingleApplication's functionality (see the examples for that).

+
 // Original
+ int main(int argc, char **argv)
+ {
+     QApplication app(argc, argv);
+
+     MyMainWidget mmw;
+     mmw.show();
+     return app.exec();
+ }
+
+ // Single instance
+ int main(int argc, char **argv)
+ {
+     QtSingleApplication app(argc, argv);
+
+     if (app.isRunning())
+         return !app.sendMessage(someDataString);
+
+     MyMainWidget mmw;
+     app.setActivationWindow(&mmw);
+     mmw.show();
+     return app.exec();
+ }
+

Once this QtSingleApplication instance is destroyed (normally when the process exits or crashes), when the user next attempts to run the application this instance will not, of course, be encountered. +The next instance to call isRunning() or sendMessage() will assume the role as the new running instance.

+

For console (non-GUI) applications, QtSingleCoreApplication may be used instead of this class, to avoid the dependency on the QtGui library.

+

See also QtSingleCoreApplication.

+
+

Member Function Documentation

+

QtSingleApplication::QtSingleApplication ( int & argc, char ** argv, bool GUIenabled = true )

+

Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). argc, argv, and GUIenabled are passed on to the QAppliation constructor.

+

If you are creating a console application (i.e. setting GUIenabled to false), you may consider using QtSingleCoreApplication instead.

+

QtSingleApplication::QtSingleApplication ( const QString & appId, int & argc, char ** argv )

+

Creates a QtSingleApplication object with the application identifier appId. argc and argv are passed on to the QAppliation constructor.

+

QtSingleApplication::QtSingleApplication ( int & argc, char ** argv, Type type )

+

Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). argc, argv, and type are passed on to the QAppliation constructor.

+

QtSingleApplication::QtSingleApplication ( Display * dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )

+

Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will +be QCoreApplication::applicationFilePath(). dpy, visual, and cmap are passed on to +the QApplication constructor.

+

QtSingleApplication::QtSingleApplication ( Display * dpy, int & argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )

+

Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will +be QCoreApplication::applicationFilePath(). dpy, argc, argv, visual, and cmap are +passed on to the QApplication constructor.

+

QtSingleApplication::QtSingleApplication ( Display * dpy, const QString & appId, int argc, char ** argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0 )

+

Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be appId. dpy, argc, argv, visual, and cmap are passed on to the QApplication constructor.

+

void QtSingleApplication::activateWindow ()   [slot]

+

De-minimizes, raises, and activates this application's activation window. This function does nothing if no activation window has been set.

+

This is a convenience function to show the user that this application instance has been activated when he has tried to start another instance.

+

This function should typically be called in response to the messageReceived() signal. By default, that will happen automatically, if an activation window has been set.

+

See also setActivationWindow(), messageReceived(), and initialize().

+

QWidget * QtSingleApplication::activationWindow () const

+

Returns the applications activation window if one has been set by calling setActivationWindow(), otherwise returns 0.

+

See also setActivationWindow().

+

QString QtSingleApplication::id () const

+

Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application.

+

bool QtSingleApplication::isRunning ()

+

Returns true if another instance of this application is running; otherwise false.

+

This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session).

+

See also sendMessage().

+

void QtSingleApplication::messageReceived ( const QString & message )   [signal]

+

This signal is emitted when the current instance receives a message from another instance of this application.

+

See also sendMessage(), setActivationWindow(), and activateWindow().

+

bool QtSingleApplication::sendMessage ( const QString & message, int timeout = 5000 )   [slot]

+

Tries to send the text message to the currently running instance. The QtSingleApplication object in the running instance will emit the messageReceived() signal when it receives the message.

+

This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within timeout milliseconds, this function return false.

+

See also isRunning() and messageReceived().

+

void QtSingleApplication::setActivationWindow ( QWidget * aw, bool activateOnMessage = true )

+

Sets the activation window of this application to aw. The activation window is the widget that will be activated by activateWindow(). This is typically the application's main window.

+

If activateOnMessage is true (the default), the window will be activated automatically every time a message is received, just prior to the messageReceived() signal being emitted.

+

See also activationWindow(), activateWindow(), and messageReceived().

+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.index b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.index new file mode 100644 index 0000000..56052c2 --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.index @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.qhp b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.qhp new file mode 100644 index 0000000..ff42d9d --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsingleapplication.qhp @@ -0,0 +1,53 @@ + + + com.nokia.qtsolutions.qtsingleapplication_head + qdoc + + qt + solutions + qtsingleapplication + + + qt + solutions + qtsingleapplication + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + qtsingleapplication.html + index.html + qtsingleapplication-example-trivial.html + qtsinglecoreapplication.html + qtsingleapplication-example-loader.html + qtsinglecoreapplication-example-console.html + classic.css + images/qt-logo.png + + + diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication-example-console.html b/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication-example-console.html new file mode 100644 index 0000000..18a9ae8 --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication-example-console.html @@ -0,0 +1,118 @@ + + + + + + A non-GUI example + + + + + + + +
  Home

A non-GUI example
+

+

This example shows how to use the single-application functionality in a console application. It does not require the QtGui library at all.

+

The only differences from the GUI application usage demonstrated in the other examples are:

+

1) The .pro file should include qtsinglecoreapplication.pri instead of qtsingleapplication.pri

+

2) The class name is QtSingleCoreApplication instead of QtSingleApplication.

+

3) No calls are made regarding window activation, for obvious reasons.

+

console.pro:

+
 TEMPLATE   = app
+ CONFIG    += console
+ SOURCES   += main.cpp
+ include(../../src/qtsinglecoreapplication.pri)
+ QT -= gui
+

main.cpp:

+
 /****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the Qt Solutions component.
+ **
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ **   * Redistributions of source code must retain the above copyright
+ **     notice, this list of conditions and the following disclaimer.
+ **   * 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.
+ **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ **     the names of its contributors may be used to endorse or promote
+ **     products derived from this software without specific prior written
+ **     permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "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 COPYRIGHT
+ ** OWNER OR CONTRIBUTORS 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 "qtsinglecoreapplication.h"
+ #include <QtCore/QDebug>
+
+ void report(const QString& msg)
+ {
+     qDebug("[%i] %s", (int)QCoreApplication::applicationPid(), qPrintable(msg));
+ }
+
+ class MainClass : public QObject
+ {
+     Q_OBJECT
+ public:
+     MainClass()
+         : QObject()
+         {}
+
+ public slots:
+     void handleMessage(const QString& message)
+         {
+             report( "Message received: \"" + message + "\"");
+         }
+ };
+
+ int main(int argc, char **argv)
+ {
+     report("Starting up");
+
+     QtSingleCoreApplication app(argc, argv);
+
+     if (app.isRunning()) {
+         QString msg(QString("Hi master, I am %1.").arg(QCoreApplication::applicationPid()));
+         bool sentok = app.sendMessage(msg, 2000);
+         QString rep("Another instance is running, so I will exit.");
+         rep += sentok ? " Message sent ok." : " Message sending failed; the other instance may be frozen.";
+         report(rep);
+         return 0;
+     } else {
+         report("No other instance is running; so I will.");
+         MainClass mainObj;
+         QObject::connect(&app, SIGNAL(messageReceived(const QString&)),
+                          &mainObj, SLOT(handleMessage(const QString&)));
+         return app.exec();
+     }
+ }
+
+ #include "main.moc"
+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication-members.html b/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication-members.html new file mode 100644 index 0000000..69fb858 --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication-members.html @@ -0,0 +1,126 @@ + + + + + + List of All Members for QtSingleCoreApplication + + + + + + + +
  Home

List of All Members for QtSingleCoreApplication

+

This is the complete list of members for QtSingleCoreApplication, including inherited members.

+

+ +
+

+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication.html b/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication.html new file mode 100644 index 0000000..a20cf2f --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/html/qtsinglecoreapplication.html @@ -0,0 +1,98 @@ + + + + + + QtSingleCoreApplication Class Reference + + + + + + + +
  Home

QtSingleCoreApplication Class Reference

+

A variant of the QtSingleApplication class for non-GUI applications. More...

+
 #include <QtSingleCoreApplication>

Inherits QCoreApplication.

+ +
+ +

Public Functions

+ + + + + +
QtSingleCoreApplication ( int & argc, char ** argv )
QtSingleCoreApplication ( const QString & appId, int & argc, char ** argv )
QString id () const
bool isRunning ()
+ +
+ +

Public Slots

+ + +
bool sendMessage ( const QString & message, int timeout = 5000 )
+ +
+ +

Signals

+ + +
void messageReceived ( const QString & message )
+ +

Additional Inherited Members

+ + +
+

Detailed Description

+

A variant of the QtSingleApplication class for non-GUI applications.

+

This class is a variant of QtSingleApplication suited for use in console (non-GUI) applications. It is an extension of QCoreApplication (instead of QApplication). It does not require the QtGui library.

+

The API and usage is identical to QtSingleApplication, except that functions relating to the "activation window" are not present, for obvious reasons. Please refer to the QtSingleApplication documentation for explanation of the usage.

+

A QtSingleCoreApplication instance can communicate to a QtSingleApplication instance if they share the same application id. Hence, this class can be used to create a light-weight command-line tool that sends commands to a GUI application.

+

See also QtSingleApplication.

+
+

Member Function Documentation

+

QtSingleCoreApplication::QtSingleCoreApplication ( int & argc, char ** argv )

+

Creates a QtSingleCoreApplication object. The application identifier will be QCoreApplication::applicationFilePath(). argc and argv are passed on to the QCoreAppliation constructor.

+

QtSingleCoreApplication::QtSingleCoreApplication ( const QString & appId, int & argc, char ** argv )

+

Creates a QtSingleCoreApplication object with the application identifier appId. argc and argv are passed on to the QCoreAppliation constructor.

+

QString QtSingleCoreApplication::id () const

+

Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application.

+

bool QtSingleCoreApplication::isRunning ()

+

Returns true if another instance of this application is running; otherwise false.

+

This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session).

+

See also sendMessage().

+

void QtSingleCoreApplication::messageReceived ( const QString & message )   [signal]

+

This signal is emitted when the current instance receives a message from another instance of this application.

+

See also sendMessage().

+

bool QtSingleCoreApplication::sendMessage ( const QString & message, int timeout = 5000 )   [slot]

+

Tries to send the text message to the currently running instance. The QtSingleCoreApplication object in the running instance will emit the messageReceived() signal when it receives the message.

+

This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within timeout milliseconds, this function return false.

+

See also isRunning() and messageReceived().

+


+ + + + +
Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt Solutions
+ diff --git a/3rd-parties/qtsingleapplication/doc/images/qt-logo.png b/3rd-parties/qtsingleapplication/doc/images/qt-logo.png new file mode 100644 index 0000000..794162f Binary files /dev/null and b/3rd-parties/qtsingleapplication/doc/images/qt-logo.png differ diff --git a/3rd-parties/qtsingleapplication/doc/index.qdoc b/3rd-parties/qtsingleapplication/doc/index.qdoc new file mode 100644 index 0000000..796dffe --- /dev/null +++ b/3rd-parties/qtsingleapplication/doc/index.qdoc @@ -0,0 +1,50 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +/*! + \page index.html + \title Single Application + + \section1 Description + + The QtSingleApplication component provides support + for applications that can be only started once per user. + + + + For some applications it is useful or even critical that they are started + only once by any user. Future attempts to start the application should + activate any already running instance, and possibly perform requested + actions, e.g. loading a file, in that instance. + + The QtSingleApplication class provides an interface to detect a running + instance, and to send command strings to that instance. + For console (non-GUI) applications, the QtSingleCoreApplication variant is provided, which avoids dependency on QtGui. + + + + + \section1 Classes + \list + \i QtSingleApplication \i QtSingleCoreApplication\endlist + + \section1 Examples + \list + \i \link qtsingleapplication-example-trivial.html A Trivial Example \endlink \i \link qtsingleapplication-example-loader.html Loading Documents \endlink \i \link qtsinglecoreapplication-example-console.html A Non-GUI Example \endlink \endlist + + + + + + + \section1 Tested platforms + \list + \i Qt 4.4, 4.5 / Windows XP / MSVC.NET 2005 + \i Qt 4.4, 4.5 / Linux / gcc + \i Qt 4.4, 4.5 / MacOS X 10.5 / gcc + \endlist + + + + +*/ diff --git a/3rd-parties/qtsingleapplication/examples/console/console.pro b/3rd-parties/qtsingleapplication/examples/console/console.pro new file mode 100644 index 0000000..e0390e2 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/console/console.pro @@ -0,0 +1,5 @@ +TEMPLATE = app +CONFIG += console +SOURCES += main.cpp +include(../../src/qtsinglecoreapplication.pri) +QT -= gui diff --git a/3rd-parties/qtsingleapplication/examples/console/console.qdoc b/3rd-parties/qtsingleapplication/examples/console/console.qdoc new file mode 100644 index 0000000..2706e26 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/console/console.qdoc @@ -0,0 +1,28 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +/*! \page qtsinglecoreapplication-example-console.html + \title A non-GUI example + + This example shows how to use the single-application functionality + in a console application. It does not require the \c QtGui library + at all. + + The only differences from the GUI application usage demonstrated + in the other examples are: + + 1) The \c.pro file should include \c qtsinglecoreapplication.pri + instead of \c qtsingleapplication.pri + + 2) The class name is \c QtSingleCoreApplication instead of \c + QtSingleApplication. + + 3) No calls are made regarding window activation, for obvious reasons. + + console.pro: + \quotefile console/console.pro + + main.cpp: + \quotefile console/main.cpp + +*/ diff --git a/3rd-parties/qtsingleapplication/examples/console/main.cpp b/3rd-parties/qtsingleapplication/examples/console/main.cpp new file mode 100644 index 0000000..13fd00e --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/console/main.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + + +#include "qtsinglecoreapplication.h" +#include + + +void report(const QString& msg) +{ + qDebug("[%i] %s", (int)QCoreApplication::applicationPid(), qPrintable(msg)); +} + +class MainClass : public QObject +{ + Q_OBJECT +public: + MainClass() + : QObject() + {} + +public slots: + void handleMessage(const QString& message) + { + report( "Message received: \"" + message + "\""); + } +}; + +int main(int argc, char **argv) +{ + report("Starting up"); + + QtSingleCoreApplication app(argc, argv); + + if (app.isRunning()) { + QString msg(QString("Hi master, I am %1.").arg(QCoreApplication::applicationPid())); + bool sentok = app.sendMessage(msg, 2000); + QString rep("Another instance is running, so I will exit."); + rep += sentok ? " Message sent ok." : " Message sending failed; the other instance may be frozen."; + report(rep); + return 0; + } else { + report("No other instance is running; so I will."); + MainClass mainObj; + QObject::connect(&app, SIGNAL(messageReceived(const QString&)), + &mainObj, SLOT(handleMessage(const QString&))); + return app.exec(); + } +} + + +#include "main.moc" diff --git a/3rd-parties/qtsingleapplication/examples/examples.pro b/3rd-parties/qtsingleapplication/examples/examples.pro new file mode 100644 index 0000000..36b8fd3 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/examples.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = trivial \ + loader \ + console diff --git a/3rd-parties/qtsingleapplication/examples/loader/file1.qsl b/3rd-parties/qtsingleapplication/examples/loader/file1.qsl new file mode 100644 index 0000000..50fcd26 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/loader/file1.qsl @@ -0,0 +1 @@ +File 1 diff --git a/3rd-parties/qtsingleapplication/examples/loader/file2.qsl b/3rd-parties/qtsingleapplication/examples/loader/file2.qsl new file mode 100644 index 0000000..4475433 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/loader/file2.qsl @@ -0,0 +1 @@ +File 2 diff --git a/3rd-parties/qtsingleapplication/examples/loader/loader.pro b/3rd-parties/qtsingleapplication/examples/loader/loader.pro new file mode 100644 index 0000000..3e52586 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/loader/loader.pro @@ -0,0 +1,6 @@ +greaterThan(QT_MAJOR_VERSION, 4): QT += printsupport +TEMPLATE = app + +include(../../src/qtsingleapplication.pri) + +SOURCES += main.cpp diff --git a/3rd-parties/qtsingleapplication/examples/loader/loader.qdoc b/3rd-parties/qtsingleapplication/examples/loader/loader.qdoc new file mode 100644 index 0000000..1f55026 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/loader/loader.qdoc @@ -0,0 +1,44 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +/*! \page qtsingleapplication-example-loader.html + \title Loading Documents + + The application in this example loads or prints the documents + passed as commandline parameters to further instances of this + application. + + \quotefromfile loader/main.cpp + \printuntil }; + The user interface in this application is a QMainWindow subclass + with a QMdiArea as the central widget. It implements a slot + \c handleMessage() that will be connected to the messageReceived() + signal of the QtSingleApplication class. + + \printuntil } + The MainWindow constructor creates a minimal user interface. + + \printto case Print: + The handleMessage() slot interprets the message passed in as a + filename that can be prepended with \e /print to indicate that + the file should just be printed rather than loaded. + + \printto #include + Loading the file will also activate the window. + + \printto mw + The \c main entry point function creates a QtSingleApplication + object, and creates a message to send to a running instance + of the application. If the message was sent successfully the + process exits immediately. + + \printuntil } + If the message could not be sent the application starts up. Note + that \c false is passed to the call to setActivationWindow() to + prevent automatic activation for every message received, e.g. when + the application should just print a file. Instead, the message + handling function determines whether activation is requested, and + signals that by emitting the needToShow() signal. This is then + simply connected directly to QtSingleApplication's + activateWindow() slot. +*/ diff --git a/3rd-parties/qtsingleapplication/examples/loader/main.cpp b/3rd-parties/qtsingleapplication/examples/loader/main.cpp new file mode 100644 index 0000000..5078490 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/loader/main.cpp @@ -0,0 +1,115 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include +#include +#include +#include +#include + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + MainWindow(); + +public slots: + void handleMessage(const QString& message); + +signals: + void needToShow(); + +private: + QMdiArea *workspace; +}; + +MainWindow::MainWindow() +{ + workspace = new QMdiArea(this); + + setCentralWidget(workspace); +} + +void MainWindow::handleMessage(const QString& message) +{ + enum Action { + Nothing, + Open, + Print + } action; + + action = Nothing; + QString filename = message; + if (message.toLower().startsWith("/print ")) { + filename = filename.mid(7); + action = Print; + } else if (!message.isEmpty()) { + action = Open; + } + if (action == Nothing) { + emit needToShow(); + return; + } + + QFile file(filename); + QString contents; + if (file.open(QIODevice::ReadOnly)) + contents = file.readAll(); + else + contents = "[[Error: Could not load file " + filename + "]]"; + + QTextEdit *view = new QTextEdit; + view->setPlainText(contents); + + switch(action) { + case Print: + { + QPrinter printer; + view->print(&printer); + delete view; + } + break; + + case Open: + { + workspace->addSubWindow(view); + view->setWindowTitle(message); + view->show(); + emit needToShow(); + } + break; + default: + break; + }; +} + +#include "main.moc" + +int main(int argc, char **argv) +{ + QtSingleApplication instance("File loader QtSingleApplication example", argc, argv); + QString message; + for (int a = 1; a < argc; ++a) { + message += argv[a]; + if (a < argc-1) + message += " "; + } + + if (instance.sendMessage(message)) + return 0; + + MainWindow mw; + mw.handleMessage(message); + mw.show(); + + QObject::connect(&instance, SIGNAL(messageReceived(const QString&)), + &mw, SLOT(handleMessage(const QString&))); + + instance.setActivationWindow(&mw, false); + QObject::connect(&mw, SIGNAL(needToShow()), &instance, SLOT(activateWindow())); + + return instance.exec(); +} diff --git a/3rd-parties/qtsingleapplication/examples/trivial/main.cpp b/3rd-parties/qtsingleapplication/examples/trivial/main.cpp new file mode 100644 index 0000000..d243cc5 --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/trivial/main.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include + +class TextEdit : public QTextEdit +{ + Q_OBJECT +public: + TextEdit(QWidget *parent = 0) + : QTextEdit(parent) + {} +public slots: + void append(const QString &str) + { + QTextEdit::append(str); + } +}; + +#include "main.moc" + + + +int main(int argc, char **argv) +{ + QtSingleApplication instance(argc, argv); + if (instance.sendMessage("Wake up!")) + return 0; + + TextEdit logview; + logview.setReadOnly(true); + logview.show(); + + instance.setActivationWindow(&logview); + + QObject::connect(&instance, SIGNAL(messageReceived(const QString&)), + &logview, SLOT(append(const QString&))); + + return instance.exec(); +} diff --git a/3rd-parties/qtsingleapplication/examples/trivial/trivial.pro b/3rd-parties/qtsingleapplication/examples/trivial/trivial.pro new file mode 100644 index 0000000..673497a --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/trivial/trivial.pro @@ -0,0 +1,5 @@ +TEMPLATE = app + +include(../../src/qtsingleapplication.pri) + +SOURCES += main.cpp diff --git a/3rd-parties/qtsingleapplication/examples/trivial/trivial.qdoc b/3rd-parties/qtsingleapplication/examples/trivial/trivial.qdoc new file mode 100644 index 0000000..4a8640e --- /dev/null +++ b/3rd-parties/qtsingleapplication/examples/trivial/trivial.qdoc @@ -0,0 +1,39 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +/*! \page qtsingleapplication-example-trivial.html + \title A Trivial Example + + The application in this example has a log-view that displays + messages sent by further instances of the same application. + + The example demonstrates the use of the QtSingleApplication + class to detect and communicate with a running instance of + the application using the sendMessage() API. The messageReceived() + signal is used to display received messages in a QTextEdit log. + + \quotefromfile trivial/main.cpp + \printuntil instance + The example has only the \c main entry point function. + A QtSingleApplication object is created immediately. + + \printuntil return + If another instance of this application is already running, + sendMessage() will succeed, and this instance just exits + immediately. + + \printuntil show() + Otherwise the instance continues as normal and creates the + user interface. + + \printuntil return instance.exec(); + The \c logview object is also set as the application's activation + window. Every time a message is received, the window will be raised + and activated automatically. + + The messageReceived() signal is also connected to the QTextEdit's + append() slot. Every message received from further instances of + this application will be displayed in the log. + + Finally the event loop is entered. +*/ diff --git a/3rd-parties/qtsingleapplication/qtlocalpeer.h b/3rd-parties/qtsingleapplication/qtlocalpeer.h deleted file mode 100644 index 1b533b1..0000000 --- a/3rd-parties/qtsingleapplication/qtlocalpeer.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTLOCALPEER_H -#define QTLOCALPEER_H - -#include -#include -#include - -#include "qtlockedfile.h" - -class QtLocalPeer : public QObject -{ - Q_OBJECT - -public: - QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); - bool isClient(); - bool sendMessage(const QString &message, int timeout); - QString applicationId() const - { return id; } - -Q_SIGNALS: - void messageReceived(const QString &message); - -protected Q_SLOTS: - void receiveConnection(); - -protected: - QString id; - QString socketName; - QLocalServer* server; - QtLP_Private::QtLockedFile lockFile; - -private: - static const char* ack; -}; - -#endif // QTLOCALPEER_H diff --git a/3rd-parties/qtsingleapplication/qtlockedfile.h b/3rd-parties/qtsingleapplication/qtlockedfile.h deleted file mode 100644 index 84c18e5..0000000 --- a/3rd-parties/qtsingleapplication/qtlockedfile.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTLOCKEDFILE_H -#define QTLOCKEDFILE_H - -#include -#ifdef Q_OS_WIN -#include -#endif - -#if defined(Q_OS_WIN) -# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) -# define QT_QTLOCKEDFILE_EXPORT -# elif defined(QT_QTLOCKEDFILE_IMPORT) -# if defined(QT_QTLOCKEDFILE_EXPORT) -# undef QT_QTLOCKEDFILE_EXPORT -# endif -# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) -# elif defined(QT_QTLOCKEDFILE_EXPORT) -# undef QT_QTLOCKEDFILE_EXPORT -# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) -# endif -#else -# define QT_QTLOCKEDFILE_EXPORT -#endif - -namespace QtLP_Private { - -class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile -{ -public: - enum LockMode { NoLock = 0, ReadLock, WriteLock }; - - QtLockedFile(); - QtLockedFile(const QString &name); - ~QtLockedFile(); - - bool open(OpenMode mode); - - bool lock(LockMode mode, bool block = true); - bool unlock(); - bool isLocked() const; - LockMode lockMode() const; - -private: -#ifdef Q_OS_WIN - Qt::HANDLE wmutex; - Qt::HANDLE rmutex; - QVector rmutexes; - QString mutexname; - - Qt::HANDLE getMutexHandle(int idx, bool doCreate); - bool waitMutex(Qt::HANDLE mutex, bool doBlock); - -#endif - LockMode m_lock_mode; -}; -} -#endif diff --git a/3rd-parties/qtsingleapplication/qtlockedfile_unix.cpp b/3rd-parties/qtsingleapplication/qtlockedfile_unix.cpp deleted file mode 100644 index 976c1b9..0000000 --- a/3rd-parties/qtsingleapplication/qtlockedfile_unix.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include - -#include "qtlockedfile.h" - -bool QtLockedFile::lock(LockMode mode, bool block) -{ - if (!isOpen()) { - qWarning("QtLockedFile::lock(): file is not opened"); - return false; - } - - if (mode == NoLock) - return unlock(); - - if (mode == m_lock_mode) - return true; - - if (m_lock_mode != NoLock) - unlock(); - - struct flock fl; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; - int cmd = block ? F_SETLKW : F_SETLK; - int ret = fcntl(handle(), cmd, &fl); - - if (ret == -1) { - if (errno != EINTR && errno != EAGAIN) - qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); - return false; - } - - - m_lock_mode = mode; - return true; -} - - -bool QtLockedFile::unlock() -{ - if (!isOpen()) { - qWarning("QtLockedFile::unlock(): file is not opened"); - return false; - } - - if (!isLocked()) - return true; - - struct flock fl; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - fl.l_type = F_UNLCK; - int ret = fcntl(handle(), F_SETLKW, &fl); - - if (ret == -1) { - qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); - return false; - } - - m_lock_mode = NoLock; - return true; -} - -QtLockedFile::~QtLockedFile() -{ - if (isOpen()) - unlock(); -} - diff --git a/3rd-parties/qtsingleapplication/qtsingleapplication.pro b/3rd-parties/qtsingleapplication/qtsingleapplication.pro new file mode 100644 index 0000000..07257c5 --- /dev/null +++ b/3rd-parties/qtsingleapplication/qtsingleapplication.pro @@ -0,0 +1,5 @@ +TEMPLATE=subdirs +CONFIG += ordered +include(common.pri) +qtsingleapplication-uselib:SUBDIRS=buildlib +SUBDIRS+=examples diff --git a/3rd-parties/qtsingleapplication/qtsinglecoreapplication.h b/3rd-parties/qtsingleapplication/qtsinglecoreapplication.h deleted file mode 100644 index b87fffe..0000000 --- a/3rd-parties/qtsingleapplication/qtsinglecoreapplication.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTSINGLECOREAPPLICATION_H -#define QTSINGLECOREAPPLICATION_H - -#include - -class QtLocalPeer; - -class QtSingleCoreApplication : public QCoreApplication -{ - Q_OBJECT - -public: - QtSingleCoreApplication(int &argc, char **argv); - QtSingleCoreApplication(const QString &id, int &argc, char **argv); - - bool isRunning(); - QString id() const; - -public Q_SLOTS: - bool sendMessage(const QString &message, int timeout = 5000); - - -Q_SIGNALS: - void messageReceived(const QString &message); - - -private: - QtLocalPeer* peer; -}; - -#endif // QTSINGLECOREAPPLICATION_H diff --git a/3rd-parties/qtsingleapplication/QtLockedFile b/3rd-parties/qtsingleapplication/src/QtLockedFile similarity index 100% rename from 3rd-parties/qtsingleapplication/QtLockedFile rename to 3rd-parties/qtsingleapplication/src/QtLockedFile diff --git a/3rd-parties/qtsingleapplication/QtSingleApplication b/3rd-parties/qtsingleapplication/src/QtSingleApplication similarity index 100% rename from 3rd-parties/qtsingleapplication/QtSingleApplication rename to 3rd-parties/qtsingleapplication/src/QtSingleApplication diff --git a/3rd-parties/qtsingleapplication/qtlocalpeer.cpp b/3rd-parties/qtsingleapplication/src/qtlocalpeer.cpp similarity index 68% rename from 3rd-parties/qtsingleapplication/qtlocalpeer.cpp rename to 3rd-parties/qtsingleapplication/src/qtlocalpeer.cpp index a7dd166..7e99171 100644 --- a/3rd-parties/qtsingleapplication/qtlocalpeer.cpp +++ b/3rd-parties/qtsingleapplication/src/qtlocalpeer.cpp @@ -1,47 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause #include "qtlocalpeer.h" #include #include +#include #include #if defined(Q_OS_WIN) @@ -78,7 +42,7 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) #endif prefix = id.section(QLatin1Char('/'), -1); } - prefix.remove(QRegExp("[^a-zA-Z]")); + prefix.remove(QRegularExpression("[^a-zA-Z]")); prefix.truncate(6); QByteArray idc = id.toUtf8(); @@ -180,7 +144,6 @@ void QtLocalPeer::receiveConnection() if (socket->state() == QLocalSocket::UnconnectedState) { qWarning("QtLocalPeer: Peer disconnected"); delete socket; - socket = nullptr; return; } if (socket->bytesAvailable() >= qint64(sizeof(quint32))) @@ -203,7 +166,6 @@ void QtLocalPeer::receiveConnection() if (got < 0) { qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); delete socket; - socket = nullptr; return; } QString message(QString::fromUtf8(uMsg)); @@ -211,6 +173,5 @@ void QtLocalPeer::receiveConnection() socket->waitForBytesWritten(1000); socket->waitForDisconnected(1000); // make sure client reads ack delete socket; - socket = nullptr; - Q_EMIT messageReceived(message); //### (might take a long time to return) + emit messageReceived(message); //### (might take a long time to return) } diff --git a/3rd-parties/qtsingleapplication/src/qtlocalpeer.h b/3rd-parties/qtsingleapplication/src/qtlocalpeer.h new file mode 100644 index 0000000..5e6db56 --- /dev/null +++ b/3rd-parties/qtsingleapplication/src/qtlocalpeer.h @@ -0,0 +1,40 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef QTLOCALPEER_H +#define QTLOCALPEER_H + +#include +#include +#include + +#include "qtlockedfile.h" + +class QtLocalPeer : public QObject +{ + Q_OBJECT + +public: + QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); + bool isClient(); + bool sendMessage(const QString &message, int timeout); + QString applicationId() const + { return id; } + +Q_SIGNALS: + void messageReceived(const QString &message); + +protected Q_SLOTS: + void receiveConnection(); + +protected: + QString id; + QString socketName; + QLocalServer* server; + QtLP_Private::QtLockedFile lockFile; + +private: + static const char* ack; +}; + +#endif // QTLOCALPEER_H diff --git a/3rd-parties/qtsingleapplication/qtlockedfile.cpp b/3rd-parties/qtsingleapplication/src/qtlockedfile.cpp similarity index 67% rename from 3rd-parties/qtsingleapplication/qtlockedfile.cpp rename to 3rd-parties/qtsingleapplication/src/qtlockedfile.cpp index c142a86..78f20bc 100644 --- a/3rd-parties/qtsingleapplication/qtlockedfile.cpp +++ b/3rd-parties/qtsingleapplication/src/qtlockedfile.cpp @@ -1,42 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause #include "qtlockedfile.h" diff --git a/3rd-parties/qtsingleapplication/src/qtlockedfile.h b/3rd-parties/qtsingleapplication/src/qtlockedfile.h new file mode 100644 index 0000000..c729bf2 --- /dev/null +++ b/3rd-parties/qtsingleapplication/src/qtlockedfile.h @@ -0,0 +1,60 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef QTLOCKEDFILE_H +#define QTLOCKEDFILE_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#if defined(Q_OS_WIN) +# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) +# define QT_QTLOCKEDFILE_EXPORT +# elif defined(QT_QTLOCKEDFILE_IMPORT) +# if defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# endif +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) +# elif defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTLOCKEDFILE_EXPORT +#endif + +namespace QtLP_Private { + +class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile +{ +public: + enum LockMode { NoLock = 0, ReadLock, WriteLock }; + + QtLockedFile(); + QtLockedFile(const QString &name); + ~QtLockedFile(); + + bool open(OpenMode mode); + + bool lock(LockMode mode, bool block = true); + bool unlock(); + bool isLocked() const; + LockMode lockMode() const; + +private: +#ifdef Q_OS_WIN + Qt::HANDLE wmutex; + Qt::HANDLE rmutex; + QVector rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; +} +#endif diff --git a/3rd-parties/qtsingleapplication/src/qtlockedfile_unix.cpp b/3rd-parties/qtsingleapplication/src/qtlockedfile_unix.cpp new file mode 100644 index 0000000..8385d8b --- /dev/null +++ b/3rd-parties/qtsingleapplication/src/qtlockedfile_unix.cpp @@ -0,0 +1,78 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +#include +#include +#include +#include + +#include "qtlockedfile.h" + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; + int cmd = block ? F_SETLKW : F_SETLK; + int ret = fcntl(handle(), cmd, &fl); + + if (ret == -1) { + if (errno != EINTR && errno != EAGAIN) + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + + m_lock_mode = mode; + return true; +} + + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_UNLCK; + int ret = fcntl(handle(), F_SETLKW, &fl); + + if (ret == -1) { + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + m_lock_mode = NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); +} + diff --git a/3rd-parties/qtsingleapplication/qtlockedfile_win.cpp b/3rd-parties/qtsingleapplication/src/qtlockedfile_win.cpp similarity index 69% rename from 3rd-parties/qtsingleapplication/qtlockedfile_win.cpp rename to 3rd-parties/qtsingleapplication/src/qtlockedfile_win.cpp index 5e21262..28cf072 100644 --- a/3rd-parties/qtsingleapplication/qtlockedfile_win.cpp +++ b/3rd-parties/qtsingleapplication/src/qtlockedfile_win.cpp @@ -1,42 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause #include "qtlockedfile.h" #include diff --git a/3rd-parties/qtsingleapplication/qtsingleapplication.cpp b/3rd-parties/qtsingleapplication/src/qtsingleapplication.cpp similarity index 82% rename from 3rd-parties/qtsingleapplication/qtsingleapplication.cpp rename to 3rd-parties/qtsingleapplication/src/qtsingleapplication.cpp index 5878a82..a6f4516 100644 --- a/3rd-parties/qtsingleapplication/qtsingleapplication.cpp +++ b/3rd-parties/qtsingleapplication/src/qtsingleapplication.cpp @@ -1,42 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause #include "qtsingleapplication.h" @@ -323,7 +286,7 @@ QWidget* QtSingleApplication::activationWindow() const void QtSingleApplication::activateWindow() { if (actWin) { - //actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); + actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); actWin->raise(); actWin->activateWindow(); } diff --git a/3rd-parties/qtsingleapplication/qtsingleapplication.h b/3rd-parties/qtsingleapplication/src/qtsingleapplication.h similarity index 50% rename from 3rd-parties/qtsingleapplication/qtsingleapplication.h rename to 3rd-parties/qtsingleapplication/src/qtsingleapplication.h index 049406f..f8f6e88 100644 --- a/3rd-parties/qtsingleapplication/qtsingleapplication.h +++ b/3rd-parties/qtsingleapplication/src/qtsingleapplication.h @@ -1,42 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause #ifndef QTSINGLEAPPLICATION_H #define QTSINGLEAPPLICATION_H diff --git a/3rd-parties/qtsingleapplication/qtsingleapplication.pri b/3rd-parties/qtsingleapplication/src/qtsingleapplication.pri similarity index 96% rename from 3rd-parties/qtsingleapplication/qtsingleapplication.pri rename to 3rd-parties/qtsingleapplication/src/qtsingleapplication.pri index 1d85285..6f2bced 100644 --- a/3rd-parties/qtsingleapplication/qtsingleapplication.pri +++ b/3rd-parties/qtsingleapplication/src/qtsingleapplication.pri @@ -1,3 +1,4 @@ +include(../common.pri) INCLUDEPATH += $$PWD DEPENDPATH += $$PWD QT *= network diff --git a/3rd-parties/qtsingleapplication/qtsinglecoreapplication.cpp b/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.cpp similarity index 62% rename from 3rd-parties/qtsingleapplication/qtsinglecoreapplication.cpp rename to 3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.cpp index 5634537..a3e2b3a 100644 --- a/3rd-parties/qtsingleapplication/qtsinglecoreapplication.cpp +++ b/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.cpp @@ -1,42 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Solutions component. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * 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. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "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 COPYRIGHT -** OWNER OR CONTRIBUTORS 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." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause #include "qtsinglecoreapplication.h" diff --git a/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.h b/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.h new file mode 100644 index 0000000..1272589 --- /dev/null +++ b/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.h @@ -0,0 +1,34 @@ +// Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef QTSINGLECOREAPPLICATION_H +#define QTSINGLECOREAPPLICATION_H + +#include + +class QtLocalPeer; + +class QtSingleCoreApplication : public QCoreApplication +{ + Q_OBJECT + +public: + QtSingleCoreApplication(int &argc, char **argv); + QtSingleCoreApplication(const QString &id, int &argc, char **argv); + + bool isRunning(); + QString id() const; + +public Q_SLOTS: + bool sendMessage(const QString &message, int timeout = 5000); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + QtLocalPeer* peer; +}; + +#endif // QTSINGLECOREAPPLICATION_H diff --git a/3rd-parties/qtsingleapplication/qtsinglecoreapplication.pri b/3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.pri similarity index 100% rename from 3rd-parties/qtsingleapplication/qtsinglecoreapplication.pri rename to 3rd-parties/qtsingleapplication/src/qtsinglecoreapplication.pri diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7887722 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.14) +project(ukui-search LANGUAGES C CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +include(GNUInstallDirs) + +add_subdirectory(libchinese-segmentation) +add_subdirectory(libsearch) +add_subdirectory(frontend) +add_subdirectory(ukuisearch-systemdbus) +add_subdirectory(search-ukcc-plugin) +add_subdirectory(ukui-search-service) +add_subdirectory(ukui-search-app-data-service) +add_subdirectory(ukui-search-service-dir-manager) + +if (BUILD_TEST) + add_subdirectory(tests) +endif () \ No newline at end of file diff --git a/README.md b/README.md index 2c2749e..fe77389 100644 --- a/README.md +++ b/README.md @@ -3,23 +3,26 @@ [dWIP] UKUI Search is a user-wide desktop search feature of UKUI desktop environment. ## 简介 -狭义上的ukui-search指ukui桌面环境中的全局搜索应用,目前最新版本为3.22.x.x。全局搜索应用提供了本地文件、文本内容、应用、设置项、便签等聚合搜索功能,基于其文件索引功能,可以为用户提供快速准确的搜索体验。 +狭义上的ukui-search指ukui桌面环境中的全局搜索应用,目前最新版本为4.0.x.x。全局搜索应用提供了本地文件、文本内容、应用、设置项、便签等聚合搜索功能,基于其文件索引功能,可以为用户提供快速准确的搜索体验。 广义的ukui-search除了包括全局搜索应用,还包括在ukui桌面环境中的本地搜索服务以及其开发接口。基于文建索引服务,应用搜索数据服务等基础数据源服务,可以提供基于C++接口的搜索功能,应用开发者可以通过引用动态库的形式直接使用其搜索功能。除此之外,ukui桌面环境搜索服务还提供了一组基于Qt插件框架的插件接口,用户可以通过继承接口以实现搜索功能的扩展。 以下提到的ukui-search如无说明均指后者。 -ukui-search 目前被打包成6个包(openkylin): +ukui-search 目前被打包成9个包(openkylin): + ukui-search_xxxxxx.deb ++ ukui-search-service_xxxx.deb + libukui-search-dev_xxxxx.deb + libukui-search2_xxxxx.deb ++ libukui-search-common_xxxxx.deb + libchinese-segmentation1_xxxx.deb + libchinese-segmentation-dev_xxxx.deb ++ libchinese-segmentation-common_xxxx.deb + ukui-search-systemdbus_xxxxx.deb -xxx代表版本号。其中,ukui-search 为全局搜索应用本体,libukui-search包提供了搜索服务基本功能以及扩展接口,libukui-search-dev为其开发包。libchinese-segmentation包为搜索服务提供了NLP能力,如中文分词等。ukui-search-systemdbus包提供了一些systemdbus提权操作。 +xxx代表版本号。其中,ukui-search 为全局搜索应用本体,ukui-search-service为搜索数据服务相关进程,libukui-search包提供了搜索服务基本功能以及扩展接口,libukui-search-dev为其开发包。libchinese-segmentation包为搜索服务提供了NLP能力,如中文分词等。ukui-search-systemdbus包提供了一些systemdbus提权操作。 ## 运行 -搜索服务相关的进程共有5个,包括ukui-search(全局搜索GUI界面),ukui-search-service(文件搜索服务),ukui-search-service-dir-manager(文件搜索目录管理), ukui-search-app-data-service(应用数据服务),ukuisearch-systemdbus(systembus)。 +搜索服务相关的进程共有5个,包括ukui-search(全局搜索GUI界面),ukui-search-service(文件搜索服务),ukui-search-service-dir-manager(文件搜索目录管理模块), ukui-search-app-data-service(应用数据服务),ukuisearch-systemdbus(systembus)。 所有进程默认开机自启。 @@ -70,9 +73,16 @@ interface: com.ukui.search.service 搜索的功能有一部分依赖于其他桌面环境组件: -设置项搜索:依赖ukui-control-center提供的配置文件,安装路径为: +设置项搜索:依赖ukui-control-center提供的dbus接口: -> /usr/share/ukui-control-center/shell/res/search.xml +``` +service:org.ukui.ukcc.session +path:/ +interface:org.ukui.ukcc.session.interface +method:getSearchItems () ↦ (Dict of {String, Variant} arg_0) +signal:searchItemsAdd(Dict of{String, Variant}) + searchItemsDelete(Dict of{String, Variant}) +``` 跳转到搜索结果对应的控制面板页面使用了ukui-control-center的命令行: @@ -91,7 +101,7 @@ Options: service: com.kylin.softwarecenter.getsearchresults path: /com/kylin/softwarecenter/getsearchresults interface: com.kylin.getsearchresults - get_search_result (String keyword) ↦ (Boolean arg_1) +method:get_search_result (String keyword) ↦ (Boolean arg_1) ``` 跳转到软件商店安装页面的使用了以下dbus接口: @@ -129,7 +139,7 @@ interface: org.freedesktop.FileManager1 ## 原理与功能特点 -全局搜索支持控制面板设置项搜索,应用搜索,文件搜索,便签本搜索。支持名称,拼音,或拼音首字母搜索(文本内容搜索和便签本搜索不支持拼音搜索)。其中,设置项搜索通过读取控制面板提供的配置文件实现,打开对应的控制面板页面也依赖与控制面板提供的命令行;应用搜索分为本地已安装应用(包括安卓兼容应用)和软件商店已上架的在线应用,在线应用的搜索和跳转安装通过软件商店提供的接口实现。所以,当怀疑搜索的设置搜索或应用搜索有问题时,可以直接测试控制面板或软件商店对应的接口。 +全局搜索支持控制面板设置项搜索,应用搜索,文件搜索,便签本搜索。支持名称,拼音,或拼音首字母搜索(文本内容搜索和便签本搜索不支持拼音搜索)。其中,设置项搜索通过控制面板提供dbus接口获取数据,打开对应的控制面板页面也依赖与控制面板提供的命令行;应用搜索分为本地已安装应用(包括安卓兼容应用)和软件商店已上架的在线应用,在线应用的搜索和跳转安装通过软件商店提供的接口实现。所以,当怀疑搜索的设置搜索或应用搜索有问题时,可以直接测试控制面板或软件商店对应的接口。 文件搜索分为文件名(文件夹名)搜索和文本内容搜索。文件搜索有两种模式:`直接搜索`和`建立索引搜索`。 @@ -138,6 +148,7 @@ interface: org.freedesktop.FileManager1 + 索引搜索:搜索通过遍历文件系统建立数据库(需要消耗一定的时间和资源),搜索时直接对数据库进行搜索,可以实现毫秒级的搜索响应,建立索引的过程中,搜索结果可能不全或者搜不出结果。 首次打开索引时,ukui-search-service进程会新建两个数据库分别存储基础索引信息(用于文件名搜索)和文本内容索引信息(用于文本内容搜索),完成首次索引后,索引服务会依赖inotify机制进行实时监听更新。索引关闭再打开或重启服务时,索引服务会对遍历文件并对数据库进行校验以增量更新。 索引数据库会基于文件系统监听进行实时更新。但是由于解析文本需要时间,所以大文件的索引新可能会有短暂的延迟。由于各种意外原因,比如索引更新过程中掉电关机,可能会导致索引损坏,此时搜索在下次开机时会重新建立索引来保证正常的文件搜索功能。基于机器配置和本地文件的数量,大小以及种类,索引重建的时间可以从几秒到数分钟不等。 +搜索目录可以在控制面板中手动配置,目前索引已经支持外接设备。 索引搜索支持文本内容搜索,基本原理可以参考 [倒排索引与优麒麟的文件搜索](https://docs.qq.com/doc/DU0p0S1lRelp2aW1y) 。建立索引时,搜索会对常用的文本文件进行解析,提取关键词存入数据库。搜索时,用户输入的文本也会被提取关键词,和数据库中的关键词进行匹配, 所以文本索引并不能保证你搜索一个文本文件里的任意内容都能搜出这个文件,这也不是普遍的应用场景。搜索输入的文本中必须要包含【关键词】才可以。比如你搜索一个‘的’,由于‘的’并不是任何文件的关键词,所以并不会有搜索到任何文件。事实上,我们有一个停用词词库,专门用来排除‘我’‘的’于是‘等等基本上在每个文档都会出现的一些无用词。目前,搜索支持解析的文件格式有:docx,pptx, xlsx, txt(大部分编码格式), doc, dot, wps, ppt, pps, dps, et, xls, pdf,uof,uot,uos,uop,ofd以上格式均不支持加密文件的解析,此外,文件索引支持图片ocr提取文字,所以你也可以通过图片中的文字搜索到图片(就像文档一样),支持的图片格式:png,bmp,gif,tif,tiff,webp,jpe,jpg,jpeg。 > 注意:应用的.desktop文件并不是应用本身或者“快捷方式”,对于搜索来说它只是一个文件,所以搜索desktop文件的名字并不能搜出这个应用,除非它恰好和应用重名。另外,在文件搜索中显示的dekstop文件并不会以应用的形式显示,而是显示它本来的样子——一个文件。 @@ -150,11 +161,13 @@ ukui-search应用和ukui-search-service、ukui-search-app-data-service的配置 文件说明: -+ ukui-search.conf ------------------------------------全局搜索GUI配置文件。 -+ ukui-search-block-dirs.conf ---------------------文件搜索黑名单,在控制面板中设置 -+ ukui-search-index-status.conf ------------------文件索引服务状态记录 -+ index_data ---------------------------------------------文件索引数据库 -+ content_index_data ---------------------------------文本内容数据库 ++ ukui-search.conf -------------------------------------全局搜索GUI配置文件。 ++ ukui-search-plugin-order.conf -------------------搜索插件显示顺序 ++ ukui-search-block-dirs.conf ----------------------文件搜索黑名单,在控制面板中设置 ++ ukui-search-index-status.conf -------------------文件索引服务状态记录 ++ ukui-search-current-indexable-dir.conf -------搜索目录配置文件 ++ index_data --------------------------------------------文件索引数据库 ++ content_index_data --------------------------------文本内容数据库 ## 编译 @@ -181,11 +194,11 @@ mkdir build;cd build;qmake ..;make ## 调试 -ukui-search目前并未采用ukui-log4qt模块的日志功能。如需调试,可在以下目录新建`ukui-search.log`、`ukui-search-service.log`以及`ukui-search-app-data-service.log`文件,分别对应全局搜索GUI应用,全局搜索文件索引服务和应用数据服务。新建日志文件后,日志会自动打印到对应额文件中,但目前日志没有自动备份或删除机制。 +ukui-search目前并未采用ukui-log4qt模块的日志功能。如需调试,可在~/.config/org.ukui/目录新建`ukui-search.log`、`ukui-search-service.log`以及`ukui-search-app-data-service.log`文件,分别对应全局搜索GUI应用,全局搜索文件索引服务和应用数据服务。新建日志文件后,日志会自动打印到对应文件中,但目前日志没有自动备份或删除机制。 ## 开发接口 -### 搜索服务接口(此接口目前处于快速更新总,请以代码为准) +### 搜索服务接口(此接口目前快速更新,请以代码为准) #### Use with CMake: @@ -210,20 +223,33 @@ PKGCONFIG += ukui-search ...... //初始化一个搜索实例 UkuiSearch::UkuiSearchTask ukst; +//初始化需要用到的搜索插件 +ukst.initSearchPlugin(UkuiSearch::SearchProperty::SearchType::File); //初始化队列 UkuiSearch::DataQueue *queue = ukst.init(); -//加载想要使用的搜索插件 -ukst.initSearchPlugin(UkuiSearch::SearchType::File); +//设置最大结果数量(默认为100) +ukst.setMaxResultNum(999999); +//添加搜索文件夹 +QString path = "/home/usr/下载"; +ukst.addSearchDir("path"); +//设置需要的信息,将被储存在 UkuiSearch::ResultItem中 +ukst.setResultProperties(UkuiSearch::SearchProperty::SearchType::File, + UkuiSearch::SearchResultProperties{UkuiSearch::SearchProperty::FilePath, + UkuiSearch::SearchProperty::FileIconName}); +//添加关键词,支持添加多个关键词,用 ‘与’的关系搜索,注意,当需要重新添加关键词时需要调用‘clearKeyWords清空关键词’ +ukst.addKeyword(searchText); //添加搜索条件 ukst.setOnlySearchFile(true); -ukst.addKeyword(m_keyword); - //启动搜索(异步) -ukst.startSearch(UkuiSearch::SearchType::File); +//执行搜索,参数表示执行搜索的搜索插件,注意每次搜索之前可以调用‘’ +ukst.startSearch(UkuiSearch::SearchProperty::SearchType::File); //接收结果(示例) - while(true) { - if(!queue->isEmpty()) { - qDebug() << queue->dequeue().getItemKey(); - } +while(!queue->isEmpty()) { + auto result = queue->dequeue(); + //通过属性取值 + qDebug() << result.getValue(UkuiSearch::SearchProperty::FilePath); + //直接获取所有值 + UkuiSearch::SearchResultPropertyMap map = result.getAllValue(); + qDebug() << map; } ``` @@ -267,24 +293,30 @@ Q_DECLARE_INTERFACE(UkuiSearch::SearchTaskPluginIface, SearchTaskPluginIface_iid 表示加载用户插件 ```c++ -ukst.initSearchPlugin(UkuiSearch::SearchType::Custom); +ukst.initSearchPlugin(UkuiSearch::SearchType::Custom, "<用户自定义的名称>"); ``` 启动搜索 ```c++ -ukst.startSearch(UkuiSearch::SearchType::<用户自定义的名称>); +ukst.startSearch(UkuiSearch::SearchType::Custom, "<用户自定义的名称>"; ``` ### 搜索应用插件接口 -搜索应用本身也提供了一个插件接口,可以通过加载用户实现的插件以实现额外搜索功能: +搜索应用本身也提供了一个插件接口,可以通过加载用户实现的插件以实现额外搜索以及详情页定制功能: ```c++ -namespace UkuiSearch { class SearchPluginIface : public PluginInterface { public: + enum InvokableAction + { + None = 1u << 0, + HideUI = 1u << 1 + }; + Q_DECLARE_FLAGS(InvokableActions, InvokableAction) + struct DescriptionInfo { QString key; @@ -305,6 +337,15 @@ public: QVector description; QString actionKey; int type; + ResultInfo(const QIcon &iconToSet = QIcon(), const QString &nameToSet = QString(), + const QVector &descriptionToSet = QVector(), + const QString &actionKeyToSet = QString(), const int &typeToSet = 0) { + icon = iconToSet; + name = nameToSet; + description = descriptionToSet; + actionKey = actionKeyToSet; + type = typeToSet; + } }; virtual ~SearchPluginIface() {} @@ -313,9 +354,12 @@ public: virtual void stopSearch() = 0; virtual QList getActioninfo(int type) = 0; virtual void openAction(int actionkey, QString key, int type) = 0; +// virtual bool isPreviewEnable(QString key, int type) = 0; +// virtual QWidget *previewPage(QString key, int type, QWidget *parent = nullptr) = 0; virtual QWidget *detailPage(const ResultInfo &ri) = 0; + + void invokeActions(InvokableActions actions); }; -} ``` > 接口使用注意事项: diff --git a/data/org.ukui.search.data.gschema.xml b/data/org.ukui.search.data.gschema.xml index 014f622..e5633a2 100644 --- a/data/org.ukui.search.data.gschema.xml +++ b/data/org.ukui.search.data.gschema.xml @@ -1,19 +1,29 @@ - - - false - file index switch - Enable or disable file index service. - - - "baidu" - web engine - Web engine to search keyword online. - - - false - content fuzzy search - Enable or disable fuzzy search for file content. - - + + + "0.0" + version of this config + Version of the config of ukui-search. + + + false + file index switch + Enable or disable file index service. + + + false + file content index switch + Enable or disable file content index service. + + + "baidu" + web engine + Web engine to search keyword online. + + + false + content fuzzy search + Enable or disable fuzzy search for file content. + + diff --git a/data/ukui-search-menu.desktop b/data/ukui-search-menu.desktop index 27b0ec2..05aa767 100644 --- a/data/ukui-search-menu.desktop +++ b/data/ukui-search-menu.desktop @@ -2,12 +2,15 @@ Name=Search Name[zh_CN]=搜索 Name[bo_CN]=བཤེར་འཚོལ། +Name[mn]=ᠪᠦᠬᠦ ᠲᠠᠯ᠎ᠠ ᠪᠠᠷ ᠬᠠᠢᠬᠤ GenericName=UKUI Global Search GenericName[zh_CN]=全局搜索 GenericName[bo_CN]=བཤེར་འཚོལ། +GenericName[mn]=ᠪᠦᠬᠦ ᠲᠠᠯ᠎ᠠ ᠪᠠᠷ ᠡᠷᠢᠨ᠎ᠡ Comment=ukui-search Comment[zh_CN]=全局搜索 Comment[bo_CN]=ཁྱོན་ཡོངས་བཤེར་འཚོལ། +Comment[mn]=ᠪᠦᠬᠦ ᠲᠠᠯ᠎ᠠ ᠪᠠᠷ ᠬᠠᠢᠬᠤ Exec=/usr/bin/ukui-search -s Type=Application Icon=kylin-search diff --git a/debian/changelog b/debian/changelog index e98bdc3..6adb351 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -ukui-search (3.22.4.2) unstable; urgency=medium +ukui-search (4.0.6.1-1) unstable; urgency=medium - * Initial + * Initial release. (Closes: #1234567) - -- MouseZhang Fri, 10 Feb 2023 11:26:15 +0800 + -- xibowen Sun, 23 Jul 2023 22:52:54 -0400 diff --git a/debian/control b/debian/control index e0842aa..2a3d386 100644 --- a/debian/control +++ b/debian/control @@ -1,96 +1,108 @@ Source: ukui-search Section: utils Priority: optional -Maintainer: Kylin Team -Uploaders: MouseZhang -Build-Depends: debhelper-compat (=13), - pkgconf, - libgsettings-qt-dev, - qtbase5-dev, - qt5-qmake, - qtchooser, - qtscript5-dev, - qttools5-dev-tools, - libxapian-dev, - libquazip5-dev(>=0.7.6-6build1), +Maintainer: zhangpengfei +Uploaders: xibowen , Mouse Zhang +Build-Depends: cmake, + debhelper-compat (=13), libglib2.0-dev, + libgsettings-qt-dev, libkf5windowsystem-dev, - libqt5x11extras5-dev, - libuchardet-dev, + libkysdk-applications-dev, + libleptonica-dev, libpoppler-qt5-dev, - libukui-log4qt-dev, + libqt5x11extras5-dev, libqt5xdg-dev, - libukcc-dev, - libopencv-dev, + libquazip5-dev(>=0.7.6-6build1), libtesseract-dev, - libkysdk-waylandhelper-dev, - libkysdk-qtwidgets-dev, + libuchardet-dev, + libukcc-dev, libukui-appwidget-manager-dev, libukui-appwidget-provider-dev, libukui-appwidget-qmlplugin0, - qml-module-org-ukui-stylehelper, - qtdeclarative5-dev + libukui-log4qt-dev, + libxapian-dev, + pkgconf, + qt5-qmake, + qtbase5-dev, + qtchooser, + qtdeclarative5-dev, + qtscript5-dev, + qttools5-dev Standards-Version: 4.6.1.0 Rules-Requires-Root: no -Homepage: https://www.ukui.org/ +Homepage: https://gitee.com/openkylin/ukui-search Vcs-Git: https://gitee.com/openkylin/ukui-search.git Vcs-Browser: https://gitee.com/openkylin/ukui-search Package: ukui-search Architecture: any -Depends: ${misc:Depends}, - ${shlibs:Depends}, - libukui-search2 (= ${binary:Version}), -Description: User-wide desktop search feature of UKUI desktop environment - Gui application that provides file search, - application search,settings search functions, - and so on. +Depends: libukui-search2 (= ${binary:Version}), + ukui-search-service (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Description: User-wide desktop search of ukui + feature of UKUI desktop environment. + +Package: ukui-search-service +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Data service for search function in UKUI desktop environment. Package: libchinese-segmentation1 Section: libs Architecture: any -Depends: ${misc:Depends}, +Depends: libchinese-segmentation-common (= ${source:Version}), + ${misc:Depends}, ${shlibs:Depends} Description: Libraries for chinese-segmentation - This package contains a few runtime libraries needed by - libsearch. + . + This package contains a runtime library needed by + ukui-search's file index function. + +Package: libchinese-segmentation-common +Architecture: all +Depends: ${misc:Depends} +Description: Extra files for chinese-segmentation + . + This package contains dicts used by chinese-segmentation. Package: libchinese-segmentation-dev Section: libdevel Architecture: any -Depends: ${misc:Depends}, - ${shlibs:Depends}, - libchinese-segmentation1 (= ${binary:Version}), -Description: Libraries for chinese-segmentation(development files) - This package contains NLP functions used by ukui-search. +Depends: libchinese-segmentation1 (= ${binary:Version}), ${misc:Depends} +Description: Libraries for chinese-segmentation(development files). Package: libukui-search2 Section: libs Architecture: any -Depends: ${misc:Depends}, - ${shlibs:Depends}, - libchinese-segmentation1 (= ${binary:Version}), - ukui-search-systemdbus (= ${binary:Version}) -Provides: libukui-search, -Description: Libraries for ukui-search - This package provides libraries for ukui-search, - and contains some binarys for search function implement, - Which are ukui-search-service,ukui-search-app-data-service - and ukui-search-service-dir-manager. +Depends: libchinese-segmentation1 (= ${binary:Version}), + libukui-search-common (= ${source:Version}), + ukui-search-systemdbus (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Provides: libukui-search +Description: Libraries for ukui-search. + . + This package contains a runtime library needed by + ukui-search and it's extensions. + +Package: libukui-search-common +Architecture: all +Depends: ${misc:Depends} +Description: Extra files for libukui-search + . + This package contains some extra files for libukui-search, + for now, translation files only. Package: libukui-search-dev Section: libdevel Architecture: any -Depends: ${misc:Depends}, - ${shlibs:Depends}, - libukui-search2 (= ${binary:Version}), -Description: Libraries for ukui-search(development files) - This package can be used to implement a gui application. +Depends: libukui-search2 (= ${binary:Version}), ${misc:Depends} +Description: Libraries for ukui-search(development files). Package: ukui-search-systemdbus Architecture: any -Depends: ${shlibs:Depends}, - ${misc:Depends}, -Description: Systembus interface to modify max_user_watches nums permanent - This package contains functions used when ukui-search want to - modify some system settings. +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Systembus interface to modify max_user_watches nums + permanent. diff --git a/debian/copyright b/debian/copyright index 729692c..22f9c96 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,237 +1,42 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ukui-search +Upstream-Contact: zhangpengfei +Source: Files: * -Copyright: 2020, KylinSoft Co., Ltd. +Copyright: 2020-2023, KylinSoft Co., Ltd. License: GPL-3+ Files: 3rd-parties/* -Copyright: 2020, KylinSoft Co., Ltd. - 2015-2018, Itay Grudev -License: Expat - -Files: 3rd-parties/SingleApplication/CHANGELOG.md - 3rd-parties/SingleApplication/Windows.md -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: 3rd-parties/SingleApplication/README.md -Copyright: 2020, KylinSoft Co., Ltd. -License: Expat - -Files: 3rd-parties/SingleApplication/singleapplication.cpp - 3rd-parties/SingleApplication/singleapplication.h - 3rd-parties/SingleApplication/singleapplication_p.cpp - 3rd-parties/SingleApplication/singleapplication_p.h -Copyright: 2015-2018, Itay Grudev -License: Expat - -Files: 3rd-parties/qtsingleapplication/* Copyright: 2013, Digia Plc and/or its subsidiary(-ies). -License: BSD-3-clause - -Files: 3rd-parties/qtsingleapplication/QtLockedFile - 3rd-parties/qtsingleapplication/QtSingleApplication -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: frontend/* -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ +License: UNKNOWN + Please fill license UNKNOWN from header of 3rd-parties/* Files: frontend/control/flow-layout/* Copyright: 2019, Tianjin KYLIN Information Technology Co., Ltd. License: GPL-2+ -Files: frontend/model/best-list-model.h - frontend/model/web-search-model.h -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: frontend/ukui-search-dbus-service.cpp - frontend/ukui-search-dbus-service.h - frontend/ukui-search-gui.cpp - frontend/ukui-search-gui.h -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: frontend/view/* -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: frontend/view/result-view-delegate.h - frontend/view/web-search-view.cpp -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/* -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/chinese-segmentation-private.h - libchinese-segmentation/common-struct.h -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/cppjieba/* -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/cppjieba/idf-trie/* -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/cppjieba/limonp/Md5.hpp +Files: libchinese-segmentation/cppjieba/limonp/* Copyright: 1991, 1992, RSA Data Security, Inc. Created 1991 License: NTP - -Files: libchinese-segmentation/cppjieba/segment-trie/* -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/development-files/* -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/dict/* -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ + Please fill license NTP from header of libchinese-segmentation/cppjieba/limonp/* Files: libchinese-segmentation/storage-base/cedar/* Copyright: 2009-2015, Naoki Yoshinaga -License: GPL-3+ - -Files: libchinese-segmentation/storage-base/darts-clone/* -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libchinese-segmentation/test/* -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libsearch/appsearch/app-match.cpp - libsearch/appsearch/app-match.h -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libsearch/file-utils.cpp - libsearch/file-utils.h - libsearch/global-settings.cpp - libsearch/global-settings.h - libsearch/gobject-template.cpp - libsearch/gobject-template.h - libsearch/libsearch.cpp - libsearch/libsearch.h - libsearch/libsearch_global.h -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libsearch/filesystemwatcher/* -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libsearch/index/* -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libsearch/index/compatible-define.h - libsearch/index/data-queue.cpp - libsearch/index/data-queue.h - libsearch/index/database.cpp - libsearch/index/database.h - libsearch/index/ocrobject.cpp - libsearch/index/ocrobject.h -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: libsearch/plugininterface/action-label.cpp - libsearch/plugininterface/action-label.h -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ +License: UNKNOWN + Please fill license UNKNOWN from header of libchinese-segmentation/storage-base/cedar/* Files: ukui-search-app-data-service/convert-winid-to-desktop.cpp ukui-search-app-data-service/convert-winid-to-desktop.h Copyright: 2019, Tianjin KYLIN Information Technology Co., Ltd. License: GPL-3+ -Files: ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.cpp - ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.h -Copyright: 2020, The Qt Company Ltd. -License: GPL-3+ - -Files: ukui-search-service-dir-manager/main.cpp -Copyright: 2019, Tianjin KYLIN Information Technology Co., Ltd. -License: GPL-2+ - -Files: ukui-search-service/* -Copyright: 2020-2022, KylinSoft Co., Ltd. -License: GPL-3+ - -Files: ukui-search-service/ukui-search-service.h -Copyright: 2020, KylinSoft Co., Ltd. -License: GPL-3+ - Files: ukuisearch-systemdbus/* Copyright: 2019, Tianjin KYLIN Information Technology Co., Ltd. License: GPL-2+ -License: BSD-3-clause - This software is Copyright (c) 2021 by foo. - This is free software, licensed under: - The (three-clause) BSD License - The BSD License - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of foo nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR - CONTRIBUTORS 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. - -License: Expat - The MIT License - . - 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: - . - 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, FITNESS FOR A PARTICULAR - PURPOSE AND NONINFRINGEMENT. IN NO EVENT - SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - License: GPL-2+ - This software is Copyright (c) 2021 by foo. + This software is Copyright (c) 2024 by foo. This is free software, licensed under: The GNU General Public License, Version 2, June 1991 This program is free software; you can redistribute it and/or modify @@ -242,7 +47,7 @@ License: GPL-2+ Public License can be found in '/usr/share/common-licenses/GPL-2'. License: GPL-3+ - This software is Copyright (c) 2021 by foo. + This software is Copyright (c) 2024 by foo. This is free software, licensed under: The GNU General Public License, Version 3, June 2007 This program is free software; you can redistribute it and/or modify @@ -251,17 +56,3 @@ License: GPL-3+ your option) any later version. On Debian systems, the complete text of version 3 of the GNU General Public License can be found in '/usr/share/common-licenses/GPL-3'. - -License: NTP - Copyright (c) (CopyrightHoldersName) (From 4-digit-year)-(To 4-digit-year) - Permission to use, copy, modify, and distribute this software and - its documentation for any purpose with or without fee is hereby - granted, provided that the above copyright notice appears in all - copies and that both the copyright notice and this permission - notice appear in supporting documentation, and that the name - (TrademarkedName) not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. (TrademarkedName) makes no - representations about the suitability this software for any - purpose. It is provided “as is” without express or implied - warranty. diff --git a/debian/libchinese-segmentation-common.install b/debian/libchinese-segmentation-common.install new file mode 100644 index 0000000..8c45bdc --- /dev/null +++ b/debian/libchinese-segmentation-common.install @@ -0,0 +1,2 @@ +/usr/share/chinese-segmentation/res/dict/*.txt +/usr/share/chinese-segmentation/res/dict/*.utf8 diff --git a/debian/libchinese-segmentation-dev.install b/debian/libchinese-segmentation-dev.install index 4cf98f4..dc0fb11 100644 --- a/debian/libchinese-segmentation-dev.install +++ b/debian/libchinese-segmentation-dev.install @@ -1,3 +1,4 @@ -usr/include/chinese-seg/* -usr/lib/*/pkgconfig/chinese-segmentation.pc +/usr/share/cmake/chinese-segmentation/*.cmake +usr/include/chinese-segmentation/* usr/lib/*/libchinese-segmentation.so +usr/lib/*/pkgconfig/chinese-segmentation.pc diff --git a/debian/libchinese-segmentation1.install b/debian/libchinese-segmentation1.install index 0ff1414..ace82bf 100644 --- a/debian/libchinese-segmentation1.install +++ b/debian/libchinese-segmentation1.install @@ -1,3 +1 @@ usr/lib/*/libchinese-segmentation.so.* -/usr/share/ukui-search/res/dict/*.utf8 -/usr/share/ukui-search/res/dict/*.txt diff --git a/debian/libukui-search-common.install b/debian/libukui-search-common.install new file mode 100644 index 0000000..b98a50e --- /dev/null +++ b/debian/libukui-search-common.install @@ -0,0 +1 @@ +usr/share/ukui-search/translations/libukui-search diff --git a/debian/libukui-search-dev.install b/debian/libukui-search-dev.install index c693652..26c5b0a 100644 --- a/debian/libukui-search-dev.install +++ b/debian/libukui-search-dev.install @@ -1,3 +1,4 @@ usr/include/ukui-search/* -usr/lib/*/pkgconfig/ukui-search.pc usr/lib/*/libukui-search.so +usr/lib/*/pkgconfig/ukui-search.pc +usr/share/cmake/ukui-search/*.cmake diff --git a/debian/libukui-search2.install b/debian/libukui-search2.install index c8dd09e..c6bfa96 100644 --- a/debian/libukui-search2.install +++ b/debian/libukui-search2.install @@ -1,11 +1 @@ usr/lib/*/libukui-search.so.* -usr/bin/ukui-search-service -usr/bin/ukui-search-app-data-service -usr/bin/ukui-search-service-dir-manager -etc/xdg/autostart/ukui-search-service-dir-manager.desktop -etc/xdg/autostart/ukui-search-app-data-service.desktop -etc/xdg/autostart/ukui-search-service.desktop -usr/share/dbus-1/services/com.ukui.search.appdb.service -usr/share/dbus-1/services/com.ukui.search.fileindex.service -usr/share/glib-2.0/schemas/org.ukui.search.data.gschema.xml -libsearch/.qm/*.qm usr/share/ukui-search/translations diff --git a/debian/rules b/debian/rules index 548260b..7330eb0 100755 --- a/debian/rules +++ b/debian/rules @@ -1,5 +1,6 @@ #!/usr/bin/make -f +export QT_SELECT=5 export DEB_BUILD_MAINT_OPTIONS = hardening=+all %: - dh $@ + dh $@ diff --git a/debian/source/format b/debian/source/format index 89ae9db..163aaf8 100644 --- a/debian/source/format +++ b/debian/source/format @@ -1 +1 @@ -3.0 (native) +3.0 (quilt) diff --git a/debian/ukui-search-service.install b/debian/ukui-search-service.install new file mode 100644 index 0000000..df33415 --- /dev/null +++ b/debian/ukui-search-service.install @@ -0,0 +1,9 @@ +etc/xdg/autostart/ukui-search-app-data-service.desktop +etc/xdg/autostart/ukui-search-service-dir-manager.desktop +etc/xdg/autostart/ukui-search-service.desktop +usr/bin/ukui-search-app-data-service +usr/bin/ukui-search-service +usr/bin/ukui-search-service-dir-manager +usr/share/dbus-1/services/com.ukui.search.appdb.service +usr/share/dbus-1/services/com.ukui.search.fileindex.service +usr/share/glib-2.0/schemas/org.ukui.search.data.gschema.xml diff --git a/debian/ukui-search-systemdbus.install b/debian/ukui-search-systemdbus.install index fe69413..bf5101b 100644 --- a/debian/ukui-search-systemdbus.install +++ b/debian/ukui-search-systemdbus.install @@ -1,3 +1,3 @@ +/usr/bin/ukui-search-systemdbus /usr/share/dbus-1/system-services/com.ukui.search.qt.systemdbus.service /usr/share/dbus-1/system.d/com.ukui.search.qt.systemdbus.conf -/usr/bin/ukui-search-systemdbus diff --git a/debian/ukui-search.install b/debian/ukui-search.install index 61ddc04..7ca92d2 100644 --- a/debian/ukui-search.install +++ b/debian/ukui-search.install @@ -1,12 +1,10 @@ -usr/bin/ukui-search etc/xdg/autostart/ukui-search.desktop -usr/share/applications/ukui-search-menu.desktop -frontend/.qm/*.qm usr/share/ukui-search/translations -usr/share/glib-2.0/schemas/org.ukui.log4qt.ukui-search.gschema.xml +usr/bin/ukui-search usr/lib/*/ukui-control-center/* -usr/share/ukui-search/search-ukcc-plugin/translations/* -search-ukcc-plugin/.qm/*.qm usr/share/ukui-search/search-ukcc-plugin/translations -usr/share/ukui-search/search-ukcc-plugin/image/* - +usr/share/applications/ukui-search-menu.desktop +usr/share/appwidget/* usr/share/dbus-1/services/org.ukui.appwidget.provider.search.service -/usr/share/appwidget/* +usr/share/glib-2.0/schemas/org.ukui.log4qt.ukui-search.gschema.xml +usr/share/ukui-search/search-ukcc-plugin/image/* +usr/share/ukui-search/search-ukcc-plugin/translations/* +usr/share/ukui-search/translations/ukui-search diff --git a/frontend/CMakeLists.txt b/frontend/CMakeLists.txt new file mode 100644 index 0000000..75773a4 --- /dev/null +++ b/frontend/CMakeLists.txt @@ -0,0 +1,132 @@ +cmake_minimum_required(VERSION 3.14) +project(ukui-search VERSION 1.0 LANGUAGES C CXX) + +set(VERSION_MAJOR 2) +set(VERSION_MINOR 2) +set(VERSION_MICRO 3) +set(UKUI_SEARCH_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus Widgets Xml Concurrent Sql LinguistTools X11Extras REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus Widgets Xml Concurrent Sql LinguistTools X11Extras REQUIRED) +find_package(PkgConfig REQUIRED) +find_package(KF5WindowSystem) + +set(UKUI_SEARCH_EXTERNAL_LIBS "") +set(UKUI_SEARCH_PC_PKGS gio-2.0 glib-2.0 gio-unix-2.0 kysdk-waylandhelper xapian-core gsettings-qt) + +foreach(PC_LIB IN ITEMS ${UKUI_SEARCH_PC_PKGS}) + pkg_check_modules(${PC_LIB} REQUIRED IMPORTED_TARGET ${PC_LIB}) + if(${${PC_LIB}_FOUND}) + include_directories(${${PC_LIB}_INCLUDE_DIRS}) + link_directories(${${PC_LIB}_LIBRARY_DIRS}) + list(APPEND UKUI_NOTIFICATION_EXTERNAL_LIBS PkgConfig::${PC_LIB}) + endif() +endforeach() + +add_subdirectory(../3rd-parties/qtsingleapplication ${CMAKE_CURRENT_SOURCE_DIR}) + +set(UKUI_SEARCH_SRC + control/create-index-ask-dialog.cpp control/create-index-ask-dialog.h + control/list-labels/show-more-label.cpp control/list-labels/show-more-label.h + control/list-labels/title-label.cpp control/list-labels/title-label.h + control/search-line-edit.cpp control/search-line-edit.h + control/stack-pages/search-page-section.cpp control/stack-pages/search-page-section.h + control/stack-pages/search-result-page.cpp control/stack-pages/search-result-page.h + main.cpp + mainwindow.cpp mainwindow.h + model/best-list-model.cpp model/best-list-model.h + model/search-result-manager.cpp model/search-result-manager.h + model/search-result-model.cpp model/search-result-model.h + search-app-widget-plugin/search.cpp search-app-widget-plugin/search.h + ukui-search-dbus-service.cpp ukui-search-dbus-service.h + ukui-search-gui.cpp ukui-search-gui.h + view/best-list-view.cpp view/best-list-view.h + view/result-view.cpp view/result-view.h + view/result-view-delegate.cpp view/result-view-delegate.h + ) +if(COMMAND qt_add_dbus_adaptor) + qt_add_dbus_adaptor(UKUI_SEARCH_SRC org.ukui.search.service.xml ukui-search-dbus-service.h UkuiSearch::UkuiSearchDbusServices) + qt_add_dbus_interface(UKUI_SEARCH_SRC org.ukui.search.service.xml service_interface) +else() + qt5_add_dbus_adaptor(UKUI_SEARCH_SRC org.ukui.search.service.xml ukui-search-dbus-service.h UkuiSearch::UkuiSearchDbusServices) + qt5_add_dbus_interface(UKUI_SEARCH_SRC org.ukui.search.service.xml service_interface) +endif() + +set(QRC_FILES resource.qrc) + +file(GLOB UKUI_SEARCH_TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../translations/ukui-search/*.ts) +set_source_files_properties(${UKUI_SEARCH_TS_FILES} PROPERTIES OUTPUT_LOCATION ${CMAKE_BINARY_DIR}/frontend/.qm) +qt5_create_translation(UKUI_SEARCH_QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${UKUI_SEARCH_TS_FILES}) + +file(GLOB UKUI_SEARCH_APP_WIDGET_TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../translations/ukui-search/appwidget/*.ts) +set_source_files_properties(${UKUI_SEARCH_APP_WIDGET_TS_FILES} PROPERTIES OUTPUT_LOCATION ${CMAKE_BINARY_DIR}/frontend/.qm) +qt5_create_translation(UKUI_SEARCH_APP_WIDGET_QM_FILES ${PROJECT_SOURCE_DIR} ${UKUI_SEARCH_APP_WIDGET_TS_FILES}) +add_executable(ukui-search + ${UKUI_SEARCH_SRC} + ${QRC_FILES} + ${UKUI_SEARCH_QM_FILES} + ${UKUI_SEARCH_APP_WIDGET_QM_FILES}) +set(UKUI_SEARCH_QM_INSTALL_PATH /usr/share/ukui-search/translations/ukui-search) +target_compile_definitions(ukui-search PRIVATE + VERSION="${UKUI_SEARCH_VERSION}" + UKUI_SEARCH_QM_INSTALL_PATH="${UKUI_SEARCH_QM_INSTALL_PATH}" + ) + +target_link_libraries(ukui-search PRIVATE + KF5::WindowSystem + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::X11Extras + gsettings-qt + ukui-appwidget-manager + ukui-appwidget-provider + libukui-search + chinese-segmentation + kysdk-waylandhelper + qtsingleapplication + ) + +target_include_directories(ukui-search PRIVATE + ../3rd-parties/qtsingleapplication/src + ../libchinese-segmentation + ../libsearch + ../libsearch/pluginmanage + ../libsearch/plugininterface + ../libsearch/searchinterface + control + control/list-labels + control/stack-pages + model + search-app-widget-plugin + view + xatom + ) + +set(APP_WIDGET_FILES_PRE + search-app-widget-plugin/provider +) +#小插件相关 +install(FILES ${APP_WIDGET_FILES_PRE}/data/search.conf DESTINATION /usr/share/appwidget/config/) +install(FILES ${APP_WIDGET_FILES_PRE}/org.ukui.appwidget.provider.search.service DESTINATION /usr/share/dbus-1/services/) +install(FILES + ${APP_WIDGET_FILES_PRE}/data/search.png + ${APP_WIDGET_FILES_PRE}/data/ukui-search.svg + DESTINATION /usr/share/appwidget/search/) +install(FILES ${APP_WIDGET_FILES_PRE}/data/search.qml DESTINATION /usr/share/appwidget/qml/) +install(FILES ${UKUI_SEARCH_APP_WIDGET_QM_FILES} DESTINATION /usr/share/appwidget/translations/) +#二进制 +install(TARGETS ukui-search RUNTIME DESTINATION /usr/bin) +#翻译 +install(FILES ${UKUI_SEARCH_QM_FILES} DESTINATION ${UKUI_SEARCH_QM_INSTALL_PATH}) +#desktop文件 +install(FILES ../data/ukui-search-menu.desktop DESTINATION /usr/share/applications) +install(FILES ../data/ukui-search.desktop DESTINATION /etc/xdg/autostart) +#gsettings +install(FILES ../data/org.ukui.log4qt.ukui-search.gschema.xml DESTINATION /usr/share/glib-2.0/schemas/) \ No newline at end of file diff --git a/frontend/control/README.md b/frontend/control/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/control/control.pri b/frontend/control/control.pri deleted file mode 100644 index 9fc1074..0000000 --- a/frontend/control/control.pri +++ /dev/null @@ -1,14 +0,0 @@ -include(stack-pages/stack-pages.pri) -include(list-labels/list-labels.pri) - -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/search-line-edit.h \ -# $$PWD/settings-widget.h \ - $$PWD/create-index-ask-dialog.h \ - -SOURCES += \ - $$PWD/search-line-edit.cpp \ -# $$PWD/settings-widget.cpp \ - $$PWD/create-index-ask-dialog.cpp \ diff --git a/frontend/control/create-index-ask-dialog.cpp b/frontend/control/create-index-ask-dialog.cpp index f0f4e58..50aae0e 100644 --- a/frontend/control/create-index-ask-dialog.cpp +++ b/frontend/control/create-index-ask-dialog.cpp @@ -22,6 +22,7 @@ #include "create-index-ask-dialog.h" #include #include +#include "icon-loader.h" #define MAIN_SIZE QSize(380, 202) #define MAIN_SPACING 0 @@ -61,19 +62,20 @@ void CreateIndexAskDialog::initUi() { m_titleFrame->setLayout(m_titleLyt); m_iconLabel = new QLabel(m_titleFrame); m_iconLabel->setFixedSize(ICON_SIZE); - m_iconLabel->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24))); + m_iconLabel->setPixmap(IconLoader::loadIconQt("kylin-search").pixmap(QSize(24, 24))); //主题改变时,更新自定义标题栏的图标 connect(qApp, &QApplication::paletteChanged, this, [ = ]() { - m_iconLabel->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24))); + m_iconLabel->setPixmap(IconLoader::loadIconQt("kylin-search").pixmap(QSize(24, 24))); }); m_titleLabel = new QLabel(m_titleFrame); m_titleLabel->setText(tr("Search")); m_closeBtn = new QPushButton(m_titleFrame); m_closeBtn->setFixedSize(CLOSE_BTN_SIZE); - m_closeBtn->setIcon(QIcon::fromTheme("window-close-symbolic")); + m_closeBtn->setIcon(IconLoader::loadIconQt("window-close-symbolic")); m_closeBtn->setProperty("isWindowButton", 0x02); m_closeBtn->setProperty("useIconHighlightEffect", 0x08); m_closeBtn->setFlat(true); + m_closeBtn->setToolTip(tr("close")); connect(m_closeBtn, &QPushButton::clicked, this, [ = ]() { this->hide(); }); @@ -91,7 +93,7 @@ void CreateIndexAskDialog::initUi() { m_contentLyt->setContentsMargins(CONTENT_MARGINS); m_tipLabel = new QLabel(m_contentFrame); - m_tipLabel->setText(tr("Creating index can help you getting results quickly, whether to create or not?")); + m_tipLabel->setText(tr("Creating index can help you get results more quickly. Would you like to create one?")); m_tipLabel->setWordWrap(true); m_tipLabel->setAlignment(Qt::AlignVCenter); m_tipLabel->setMinimumHeight(TIP_LABEL_HEIGHT); diff --git a/frontend/control/flow-layout/flow-layout.pri b/frontend/control/flow-layout/flow-layout.pri deleted file mode 100644 index d0e147a..0000000 --- a/frontend/control/flow-layout/flow-layout.pri +++ /dev/null @@ -1,5 +0,0 @@ -SOURCES += \ - $$PWD/flow-layout.cpp \ - -HEADERS += \ - $$PWD/flow-layout.h \ diff --git a/frontend/control/list-labels/list-labels.pri b/frontend/control/list-labels/list-labels.pri deleted file mode 100644 index 4049a43..0000000 --- a/frontend/control/list-labels/list-labels.pri +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/show-more-label.h \ - $$PWD/title-label.h - -SOURCES += \ - $$PWD/show-more-label.cpp \ - $$PWD/title-label.cpp diff --git a/frontend/control/list-labels/show-more-label.cpp b/frontend/control/list-labels/show-more-label.cpp index d2b3908..41fb861 100644 --- a/frontend/control/list-labels/show-more-label.cpp +++ b/frontend/control/list-labels/show-more-label.cpp @@ -19,6 +19,7 @@ * */ #include "show-more-label.h" +#include "icon-loader.h" #include #include #include @@ -30,13 +31,13 @@ ShowMoreLabel::ShowMoreLabel(QWidget *parent) : QWidget(parent) { void ShowMoreLabel::resetLabel() { m_isOpen = false; - m_iconLabel->setPixmap(QIcon::fromTheme("ukui-down-symbolic", QIcon(":/res/icons/ukui-down-symbolic.svg")).pixmap(QSize(16, 16))); + m_iconLabel->setPixmap(IconLoader::loadIconQt("ukui-down-symbolic", QIcon(":/res/icons/ukui-down-symbolic.svg")).pixmap(QSize(16, 16))); } void ShowMoreLabel::setLabel() { m_isOpen = true; - m_iconLabel->setPixmap(QIcon::fromTheme("ukui-up-symbolic", QIcon(":/res/icons/ukui-up-symbolic.svg")).pixmap(QSize(16, 16))); + m_iconLabel->setPixmap(IconLoader::loadIconQt("ukui-up-symbolic", QIcon(":/res/icons/ukui-up-symbolic.svg")).pixmap(QSize(16, 16))); } /** @@ -53,7 +54,7 @@ void ShowMoreLabel::initUi() { m_layout = new QHBoxLayout(this); m_layout->setContentsMargins(0, 0, 0, 6); m_iconLabel = new QLabel(this); - m_iconLabel->setPixmap(QIcon::fromTheme("ukui-down-symbolic", QIcon(":/res/icons/ukui-down-symbolic.svg")).pixmap(QSize(16, 16))); + m_iconLabel->setPixmap(IconLoader::loadIconQt("ukui-down-symbolic", QIcon(":/res/icons/ukui-down-symbolic.svg")).pixmap(QSize(16, 16))); m_iconLabel->setCursor(QCursor(Qt::PointingHandCursor)); m_iconLabel->installEventFilter(this); // m_loadingIconLabel = new QLabel(this); //使用图片显示加载状态时,取消此label的注释 @@ -63,7 +64,7 @@ void ShowMoreLabel::initUi() { m_layout->addWidget(m_iconLabel); m_iconLabel->setPalette(pal); m_iconLabel->setCursor(QCursor(Qt::PointingHandCursor)); - m_iconLabel->setProperty("useIconHighlightEffect", 0x08); + m_iconLabel->setProperty("useIconHighlightEffect", 0x02); m_iconLabel->setProperty("iconHighlightEffectMode", 1); // m_layout->addWidget(m_loadingIconLabel); } @@ -73,11 +74,11 @@ bool ShowMoreLabel::eventFilter(QObject *watched, QEvent *event) { if(event->type() == QEvent::MouseButtonPress) { if(! m_timer->isActive()) { if(!m_isOpen) { - m_iconLabel->setPixmap(QIcon::fromTheme("ukui-up-symbolic", QIcon(":/res/icons/ukui-up-symbolic.svg")).pixmap(QSize(16, 16))); + m_iconLabel->setPixmap(IconLoader::loadIconQt("ukui-up-symbolic", QIcon(":/res/icons/ukui-up-symbolic.svg")).pixmap(QSize(16, 16))); m_isOpen = true; Q_EMIT this->showMoreClicked(); } else { - m_iconLabel->setPixmap(QIcon::fromTheme("ukui-down-symbolic", QIcon(":/res/icons/ukui-down-symbolic.svg")).pixmap(QSize(16, 16))); + m_iconLabel->setPixmap(IconLoader::loadIconQt("ukui-down-symbolic", QIcon(":/res/icons/ukui-down-symbolic.svg")).pixmap(QSize(16, 16))); m_isOpen = false; Q_EMIT this->retractClicked(); } diff --git a/frontend/control/search-line-edit.cpp b/frontend/control/search-line-edit.cpp index eb2b9e2..54a4628 100644 --- a/frontend/control/search-line-edit.cpp +++ b/frontend/control/search-line-edit.cpp @@ -19,7 +19,9 @@ * */ #include "search-line-edit.h" +#include "icon-loader.h" #include +#include #include QT_BEGIN_NAMESPACE @@ -38,13 +40,8 @@ SearchLineEdit::SearchLineEdit(QWidget *parent) : QLineEdit(parent) { this->setDragEnabled(true); m_queryIcon = new QLabel; - QPixmap pixmap; - if (!QIcon::fromTheme("system-search-symbolic").isNull()) { - pixmap = QPixmap(QIcon::fromTheme("system-search-symbolic").pixmap(QSize(18, 18))); - } else { - pixmap = QPixmap(QIcon(":/res/icons/system-search.symbolic.png").pixmap(QSize(18, 18))); - } - m_queryIcon->setProperty("useIconHighlightEffect", 0x10); + QPixmap pixmap = QPixmap(IconLoader::loadIconQt("system-search-symbolic", QIcon(":/res/icons/system-search.symbolic.png")).pixmap(QSize(18, 18))); + m_queryIcon->setProperty("useIconHighlightEffect", 0x02); m_queryIcon->setFixedSize(pixmap.size() / pixmap.devicePixelRatio()); m_queryIcon->setPixmap(pixmap); @@ -91,7 +88,7 @@ void SearchLineEdit::paintEvent(QPaintEvent *e) QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; p.setBrush(palette().base()); - p.setOpacity(GlobalSettings::getInstance()->getValue(TRANSPARENCY_KEY).toDouble()); + p.setOpacity(GlobalSettings::getInstance().getValue(TRANSPARENCY_KEY).toDouble()); p.setPen(Qt::NoPen); p.drawRoundedRect(this->rect(), 12, 12); return QLineEdit::paintEvent(e); @@ -99,6 +96,7 @@ void SearchLineEdit::paintEvent(QPaintEvent *e) void SearchLineEdit::focusOutEvent(QFocusEvent *e) { + Q_UNUSED(e) this->setFocus(); } diff --git a/frontend/control/settings-widget.cpp b/frontend/control/settings-widget.cpp deleted file mode 100644 index 39abded..0000000 --- a/frontend/control/settings-widget.cpp +++ /dev/null @@ -1,594 +0,0 @@ -/* - * - * Copyright (C) 2020, KylinSoft Co., Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Authors: zhangjiaping - * - */ -#include "settings-widget.h" -#include -#include -#include -#include -#include -#include -#include "global-settings.h" -#include "file-utils.h" - -using namespace UkuiSearch; -extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); -SettingsWidget::SettingsWidget(QWidget *parent) : QWidget(parent) { -// this->setWindowIcon(QIcon::fromTheme("kylin-search")); - this->setWindowTitle(tr("ukui-search-settings")); -// this->setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint); -// this->setAttribute(Qt::WA_TranslucentBackground); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) - m_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - m_hints.functions = MWM_FUNC_ALL; - m_hints.decorations = MWM_DECOR_BORDER; - XAtomHelper::getInstance()->setWindowMotifHint(winId(), m_hints); -#endif - - initUi(); - refreshIndexState(); - setupBlackList(GlobalSettings::getInstance()->getBlockDirs()); - resetWebEngine(); -} - -SettingsWidget::~SettingsWidget() { -} - -/** - * @brief SettingsWidget::initUi 初始化界面UI - */ -void SettingsWidget::initUi() { - QPalette pal = palette(); - pal.setColor(QPalette::Window, QColor(0, 0, 0, 0)); -// this->setFixedWidth(528); -// this->setMinimumHeight(460); -// this->setMaximumHeight(680); - m_mainLyt = new QVBoxLayout(this); - m_mainLyt->setContentsMargins(16, 8, 16, 24); - this->setLayout(m_mainLyt); - - //标题栏 - m_titleFrame = new QFrame(this); - m_titleFrame->setFixedHeight(40); - m_titleLyt = new QHBoxLayout(m_titleFrame); - m_titleLyt->setContentsMargins(0, 0, 0, 0); - m_titleFrame->setLayout(m_titleLyt); - m_titleIcon = new QLabel(m_titleFrame); - m_titleIcon->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24))); - //主题改变时,更新自定义标题栏的图标 - connect(qApp, &QApplication::paletteChanged, this, [ = ]() { - m_titleIcon->setPixmap(QIcon::fromTheme("kylin-search").pixmap(QSize(24, 24))); - }); - m_titleLabel = new QLabel(m_titleFrame); - m_titleLabel->setText(tr("Search")); - m_closeBtn = new QPushButton(m_titleFrame); - m_closeBtn->setFixedSize(24, 24); -// m_closeBtn->setIcon(QIcon(":/res/icons/close.svg")); - m_closeBtn->setIcon(QIcon::fromTheme("window-close-symbolic")); - m_closeBtn->setProperty("isWindowButton", 0x02); - m_closeBtn->setProperty("useIconHighlightEffect", 0x08); - m_closeBtn->setFlat(true); - connect(m_closeBtn, &QPushButton::clicked, this, [ = ]() { - Q_EMIT this->settingWidgetClosed(); - m_timer->stop(); - this->close(); - }); - m_titleLyt->addWidget(m_titleIcon); - m_titleLyt->addWidget(m_titleLabel); - m_titleLyt->addStretch(); - m_titleLyt->addWidget(m_closeBtn); - m_mainLyt->addWidget(m_titleFrame); - - m_contentFrame = new QFrame(this); - m_contentLyt = new QVBoxLayout(m_contentFrame); - m_contentFrame->setLayout(m_contentLyt); - m_contentLyt->setContentsMargins(8, 0, 8, 0); - m_mainLyt->addWidget(m_contentFrame); - - //设置 - m_settingLabel = new QLabel(m_contentFrame); - m_settingLabel->setText(tr("

Settings

")); - m_contentLyt->addWidget(m_settingLabel); - - //文件索引 - m_indexTitleLabel = new QLabel(m_contentFrame); - m_indexTitleLabel->setText(tr("

Index State

")); - m_indexStateLabel = new QLabel(m_contentFrame); - m_indexStateLabel->setText(tr("...")); - m_indexNumLabel = new QLabel(m_contentFrame); - m_indexNumLabel->setText(tr("...")); - m_contentLyt->addWidget(m_indexTitleLabel); - m_contentLyt->addWidget(m_indexStateLabel); -// m_mainLyt->addWidget(m_indexNumLabel); - m_indexNumLabel->hide(); - - //文件索引设置(黑名单) - m_indexSettingLabel = new QLabel(m_contentFrame); - m_indexSettingLabel->setText(tr("

File Index Settings

")); - m_indexDescLabel = new QLabel(m_contentFrame); - m_indexDescLabel->setText(tr("Following folders will not be searched. You can set it by adding and removing folders.")); - m_indexDescLabel->setWordWrap(true); - m_indexBtnFrame = new QFrame(m_contentFrame); - m_indexBtnLyt = new QHBoxLayout(m_indexBtnFrame); - m_indexBtnLyt->setContentsMargins(0, 0, 0, 0); - m_indexBtnFrame->setLayout(m_indexBtnLyt); - m_addDirBtn = new QPushButton(m_indexBtnFrame); - m_addDirBtn->setFixedHeight(32); - m_addDirBtn->setMinimumWidth(164); - m_addDirBtn->setText(tr("Add ignored folders")); - connect(m_addDirBtn, &QPushButton::clicked, this, &SettingsWidget::onBtnAddClicked); - m_indexBtnLyt->addWidget(m_addDirBtn); - m_indexBtnLyt->addStretch(); - m_dirListArea = new QScrollArea(m_contentFrame); - m_dirListArea->setPalette(pal); - m_dirListArea->setFrameShape(QFrame::Shape::NoFrame); - m_dirListWidget = new QWidget(m_contentFrame); - m_dirListLyt = new QVBoxLayout(m_dirListWidget); - m_dirListLyt->setContentsMargins(0, 0, 0, 0); - m_dirListLyt->setSpacing(0); - m_dirListWidget->setLayout(m_dirListLyt); - m_dirListArea->setWidget(m_dirListWidget); - m_dirListArea->setWidgetResizable(m_contentFrame); - m_contentLyt->addWidget(m_indexSettingLabel); - m_contentLyt->addWidget(m_indexDescLabel); - m_contentLyt->addWidget(m_indexBtnFrame); - m_contentLyt->addWidget(m_dirListArea); - - //搜索引擎设置 - m_searchEngineLabel = new QLabel(m_contentFrame); - m_searchEngineLabel->setText(tr("

Search Engine Settings

")); - m_engineDescLabel = new QLabel(m_contentFrame); - m_engineDescLabel->setText(tr("Please select search engine you preferred.")); - m_engineDescLabel->setWordWrap(true); - m_engineBtnGroup = new QButtonGroup(m_contentFrame); - m_baiduBtn = new QRadioButton(m_contentFrame); - m_sougouBtn = new QRadioButton(m_contentFrame); - m_360Btn = new QRadioButton(m_contentFrame); - m_baiduBtn->setFixedSize(16, 16); - m_sougouBtn->setFixedSize(16, 16); - m_360Btn->setFixedSize(16, 16); - m_radioBtnFrame = new QFrame(m_contentFrame); - m_radioBtnLyt = new QHBoxLayout(m_radioBtnFrame); - m_radioBtnFrame->setLayout(m_radioBtnLyt); - m_baiduLabel = new QLabel(); - m_baiduLabel->setText(tr("baidu")); - m_sougouLabel = new QLabel(); - m_sougouLabel->setText(tr("sougou")); - m_360Label = new QLabel(); - m_360Label->setText(tr("360")); - m_radioBtnLyt->setContentsMargins(0, 0, 0, 0); - m_radioBtnLyt->addWidget(m_baiduBtn); - m_radioBtnLyt->addWidget(m_baiduLabel); - m_radioBtnLyt->addWidget(m_sougouBtn); - m_radioBtnLyt->addWidget(m_sougouLabel); - m_radioBtnLyt->addWidget(m_360Btn); - m_radioBtnLyt->addWidget(m_360Label); - m_radioBtnLyt->addStretch(); - m_engineBtnGroup->setExclusive(true); - m_engineBtnGroup->addButton(m_baiduBtn); - m_engineBtnGroup->addButton(m_sougouBtn); - m_engineBtnGroup->addButton(m_360Btn); -// m_engineBtnGroup->setId(m_baiduBtn, WebEngine::Baidu); -// m_engineBtnGroup->setId(m_sougouBtn, WebEngine::Sougou); -// m_engineBtnGroup->setId(m_360Btn, WebEngine::_360); -// connect(m_engineBtnGroup, QOverload::of(&QButtonGroup::buttonClicked), [ = ] (int id) { -// setWebEngine(id); -// }); - connect(m_baiduBtn, &QRadioButton::clicked, [ = ](bool checked) { - if(checked) setWebEngine("baidu"); - }); - connect(m_sougouBtn, &QRadioButton::clicked, [ = ](bool checked) { - if(checked) setWebEngine("sougou"); - }); - connect(m_360Btn, &QRadioButton::clicked, [ = ](bool checked) { - if(checked) setWebEngine("360"); - }); - - m_contentLyt->addWidget(m_searchEngineLabel); - m_contentLyt->addWidget(m_engineDescLabel); - m_contentLyt->addWidget(m_radioBtnFrame); - - //取消与确认按钮 (隐藏) -// m_bottomBtnFrame = new QFrame(this); -// m_bottomBtnLyt = new QHBoxLayout(m_bottomBtnFrame); -// m_bottomBtnFrame->setLayout(m_bottomBtnLyt); -// m_bottomBtnLyt->setSpacing(20); -// m_cancelBtn = new QPushButton(m_bottomBtnFrame); -// m_cancelBtn->setText(tr("Cancel")); -// m_cancelBtn->setFixedSize(80, 32); -// connect(m_cancelBtn, &QPushButton::clicked, this, &SettingsWidget::onBtnCancelClicked); -// m_confirmBtn = new QPushButton(m_bottomBtnFrame); -// m_confirmBtn->setText(tr("Confirm")); -// m_confirmBtn->setFixedSize(80, 32); -// connect(m_confirmBtn, &QPushButton::clicked, this, &SettingsWidget::onBtnConfirmClicked); -// m_bottomBtnLyt->addStretch(); -// m_bottomBtnLyt->addWidget(m_cancelBtn); -// m_bottomBtnLyt->addWidget(m_confirmBtn); -// m_mainLyt->addWidget(m_bottomBtnFrame); - - m_contentLyt->addStretch(); - -#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0)) - this->m_titleFrame->hide(); - setAttribute(Qt::WA_DeleteOnClose); -#endif -} - -/** - * @brief SettingsWidget::setupBlackList 创建黑名单列表 - * @param list 文件夹路径列表 - */ -void SettingsWidget::setupBlackList(const QStringList& list) { - clearLayout(m_dirListLyt); - m_blockdirs = 0; - Q_FOREACH(QString path, list) { - FolderListItem * item = new FolderListItem(m_dirListWidget, path); - m_dirListLyt->addWidget(item); - item->setMaximumWidth(this->width() - 52); - connect(item, &FolderListItem::onDelBtnClicked, this, &SettingsWidget::onBtnDelClicked); - m_blockdirs ++; - } - this->resize(); - m_dirListWidget->setFixedWidth(this->width() - 68); -// m_dirListLyt->addStretch(); -} - -/** - * @brief SettingsWidget::clearLayout 清空某个布局 - * @param layout 需要清空的布局 - */ -void SettingsWidget::clearLayout(QLayout * layout) { - if(! layout) return; - QLayoutItem * child; - while((child = layout->takeAt(0)) != 0) { - if(child->widget()) { - child->widget()->setParent(NULL); - } - delete child; - } - child = NULL; -} - -/** - * @brief SettingsWidget::refreshIndexState 定时刷新索引项 - */ -void SettingsWidget::refreshIndexState() { -// qDebug()<<"FileUtils::indexStatus: "<setIndexState(true); - } else { - this->setIndexState(false); - } - m_indexNumLabel->setText(QString("%1/%2").arg(QString::number(SearchManager::getCurrentIndexCount())).arg(QString::number(FileUtils::maxIndexCount))); - m_timer = new QTimer; - connect(m_timer, &QTimer::timeout, this, [ = ]() { - qDebug() << "FileUtils::indexStatus: " << FileUtils::indexStatus; - if(FileUtils::indexStatus != 0) { - this->setIndexState(true); - } else { - this->setIndexState(false); - } - m_indexNumLabel->setText(QString("%1/%2").arg(QString::number(SearchManager::getCurrentIndexCount())).arg(QString::number(FileUtils::maxIndexCount))); - }); - m_timer->start(0.5 * 1000); -} - -/** - * @brief SettingsWidget::onBtnDelClicked 删除黑名单中的目录 - * @param path 文件夹路径 - */ -void SettingsWidget::onBtnDelClicked(const QString& path) { - QMessageBox message(QMessageBox::Question, tr("Search"), tr("Whether to delete this directory?")); - QPushButton * buttonYes = message.addButton(tr("Yes"), QMessageBox::YesRole); - message.addButton(tr("No"), QMessageBox::NoRole); - message.exec(); - if(message.clickedButton() != buttonYes) { - return; - } - - int returnCode = 0; - if(GlobalSettings::getInstance()->setBlockDirs(path, returnCode, true)) { - qDebug() << "Remove block dir in onBtnDelClicked() successed."; - Q_FOREACH(FolderListItem * item, m_dirListWidget->findChildren()) { - if(item->getPath() == path) { - item->deleteLater(); - item = NULL; - m_blockdirs --; - this->resize(); - return; - } - } - } else { - showWarningDialog(returnCode); - } -} - -/** - * @brief SettingsWidget::resetWebEngine 获取当前的搜索引擎并反映在UI控件上 - */ -void SettingsWidget::resetWebEngine() { - QString engine = GlobalSettings::getInstance()->getValue(WEB_ENGINE).toString(); - m_engineBtnGroup->blockSignals(true); - if(!engine.isEmpty()) { - if(engine == "360") { - m_360Btn->setChecked(true); - } else if(engine == "sougou") { - m_sougouBtn->setChecked(true); - } else { - m_baiduBtn->setChecked(true); - } - } else { - m_baiduBtn->setChecked(true); - } - m_engineBtnGroup->blockSignals(false); -} - -/** - * @brief SettingsWidget::setWebEngine - * @param engine 选择的搜索引擎 - */ -void SettingsWidget::setWebEngine(const QString& engine) { -// GlobalSettings::getInstance()->setValue(WEB_ENGINE, engine); - Q_EMIT this->webEngineChanged(engine); -} - -/** - * @brief setIndexState 设置当前索引状态 - * @param isCreatingIndex 是否正在创建索引 - */ -void SettingsWidget::setIndexState(bool isCreatingIndex) { - if(isCreatingIndex) { - m_indexStateLabel->setText(tr("Creating ...")); - return; - } - m_indexStateLabel->setText(tr("Done")); -} - -/** - * @brief SettingsWidget::setIndexNum 设置当前索引项数量 - * @param num 索引项数量 - */ -void SettingsWidget::setIndexNum(int num) { - m_indexNumLabel->setText(QString(tr("Index Entry: %1")).arg(QString::number(num))); -} - -/** - * @brief SettingsWidget::showWidget 显示此窗口 - */ -void SettingsWidget::showWidget() { - Qt::WindowFlags flags = this->windowFlags(); - flags |= Qt::WindowStaysOnTopHint; - this->setWindowFlags(flags); - flags &= ~Qt::WindowStaysOnTopHint; - this->setWindowFlags(flags); - m_timer->start(); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) - XAtomHelper::getInstance()->setWindowMotifHint(winId(), m_hints); -#endif - this->show(); -} - -///** -// * @brief SettingsWidget::onBtnConfirmClicked 点击确认按钮的槽函数 -// */ -//void SettingsWidget::onBtnConfirmClicked() { -// Q_EMIT this->settingWidgetClosed(); -// m_timer->stop(); -// this->close(); -//} - -///** -// * @brief SettingsWidget::onBtnCancelClicked 点击取消按钮的槽函数 -// */ -//void SettingsWidget::onBtnCancelClicked() { -// Q_EMIT this->settingWidgetClosed(); -// m_timer->stop(); -// this->close(); -//} - -/** - * @brief SettingsWidget::onBtnAddClicked 点击添加黑名单按钮的槽函数 - */ -void SettingsWidget::onBtnAddClicked() { - QFileDialog * fileDialog = new QFileDialog(this); -// fileDialog->setFileMode(QFileDialog::Directory); //允许查看文件和文件夹,但只允许选择文件夹 - fileDialog->setFileMode(QFileDialog::DirectoryOnly); //只允许查看文件夹 -// fileDialog->setViewMode(QFileDialog::Detail); - fileDialog->setDirectory(QDir::homePath()); - fileDialog->setNameFilter(tr("Directories")); - fileDialog->setWindowTitle(tr("select blocked folder")); - fileDialog->setLabelText(QFileDialog::Accept, tr("Select")); - fileDialog->setLabelText(QFileDialog::LookIn, tr("Position: ")); - fileDialog->setLabelText(QFileDialog::FileName, tr("FileName: ")); - fileDialog->setLabelText(QFileDialog::FileType, tr("FileType: ")); - fileDialog->setLabelText(QFileDialog::Reject, tr("Cancel")); - if(fileDialog->exec() != QDialog::Accepted) { - fileDialog->deleteLater(); - return; - } - QString selectedDir = 0; - int returnCode; - selectedDir = fileDialog->selectedFiles().first(); - qDebug() << "Selected a folder in onBtnAddClicked(): " << selectedDir << ". ->settings-widget.cpp #238"; - if(GlobalSettings::getInstance()->setBlockDirs(selectedDir, returnCode)) { - setupBlackList(GlobalSettings::getInstance()->getBlockDirs()); - qDebug() << "Add block dir in onBtnAddClicked() successed. ->settings-widget.cpp #238"; - } else { - showWarningDialog(returnCode); - } -} - -/** - * @brief SettingsWidget::paintEvent 绘制弹窗阴影 - * @param event - */ -void SettingsWidget::paintEvent(QPaintEvent *event) { - Q_UNUSED(event) - - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - QPainterPath rectPath; - rectPath.addRect(this->rect()); - - // 绘制一个背景 - p.save(); - p.fillPath(rectPath, palette().color(QPalette::Base)); - p.restore(); -} - -/** - * @brief SettingsWidget::resize 重新计算窗口应有大小 - */ -void SettingsWidget::resize() { -// if (m_blockdirs <= 1) { -// this->setFixedSize(528, 455); -// } else if (m_blockdirs <= 3) { -// this->setFixedSize(528, 425 + 30 * m_blockdirs); -// } else { -// this->setFixedSize(528, 515); -// } - if(m_blockdirs <= 4) { - m_dirListArea->setFixedHeight(32 * m_blockdirs + 4); - m_dirListWidget->setFixedHeight(32 * m_blockdirs); - } else { - m_dirListWidget->setFixedHeight(32 * m_blockdirs); - m_dirListArea->setFixedHeight(32 * 4 + 4); - } - this->setFixedSize(528, 410 + m_dirListArea->height()); -} - -/** - * @brief SettingsWidget::showWarningDialog 显示警告弹窗 - * @param errorCode 错误码 - */ -void SettingsWidget::showWarningDialog(const int & errorCode) { - qWarning() << "Add block dir in onBtnAddClicked() failed. Code: " << errorCode << " ->settings-widget.cpp #238"; - QString errorMessage; - switch(errorCode) { - case 1: { - errorMessage = tr("Choosen path is Empty!"); - break; - } - case 2: { - errorMessage = tr("Choosen path is not in \"home\"!"); - break; - } - case 3: { - errorMessage = tr("Its' parent folder has been blocked!"); - break; - } - default: { - errorMessage = tr("Set blocked folder failed!"); - break; - } - } - QMessageBox message(QMessageBox::Warning, tr("Search"), errorMessage); - message.addButton(tr("OK"), QMessageBox::AcceptRole); - message.exec(); -} - - -FolderListItem::FolderListItem(QWidget *parent, const QString &path) : QWidget(parent) { - m_path = path; - initUi(); -} - -FolderListItem::~FolderListItem() { - -} - -/** - * @brief FolderListItem::initUi 构建ui - */ -void FolderListItem::initUi() { - m_layout = new QVBoxLayout(this); - m_layout->setSpacing(0); - m_layout->setContentsMargins(0, 0, 0, 0); - m_widget = new QWidget(this); - m_widget->setObjectName("mWidget"); - this->setFixedHeight(32); - m_layout->addWidget(m_widget); - m_widgetlayout = new QHBoxLayout(m_widget); - m_widgetlayout->setContentsMargins(8, 4, 8, 4); - m_widget->setLayout(m_widgetlayout); - - m_iconLabel = new QLabel(m_widget); - m_pathLabel = new QLabel(m_widget); - m_delLabel = new QLabel(m_widget); - m_iconLabel->setPixmap(QIcon::fromTheme("inode-directory").pixmap(QSize(16, 16))); - m_pathLabel->setText(m_path); - m_delLabel->setText(tr("Delete the folder out of blacklist")); - QPalette pal = palette(); - pal.setColor(QPalette::WindowText, QColor(55, 144, 250, 255)); - m_delLabel->setPalette(pal); - m_delLabel->setCursor(QCursor(Qt::PointingHandCursor)); - m_delLabel->installEventFilter(this); - m_delLabel->hide(); - m_widgetlayout->addWidget(m_iconLabel); - m_widgetlayout->addWidget(m_pathLabel); - m_widgetlayout->addStretch(); - m_widgetlayout->addWidget(m_delLabel); -} - -/** - * @brief FolderListItem::getPath 获取当前文件夹路径 - * @return - */ -QString FolderListItem::getPath() { - return m_path; -} - -/** - * @brief FolderListItem::enterEvent 鼠标移入事件 - * @param event - */ -void FolderListItem::enterEvent(QEvent *event) { - m_delLabel->show(); - m_widget->setStyleSheet("QWidget#mWidget{background: rgba(0,0,0,0.1);}"); - QWidget::enterEvent(event); -} - -/** - * @brief FolderListItem::leaveEvent 鼠标移出事件 - * @param event - */ -void FolderListItem::leaveEvent(QEvent *event) { - m_delLabel->hide(); - m_widget->setStyleSheet("QWidget#mWidget{background: transparent;}"); - QWidget::leaveEvent(event); -} - - -/** - * @brief FolderListItem::eventFilter 处理删除按钮点击事件 - * @param watched - * @param event - * @return - */ -bool FolderListItem::eventFilter(QObject *watched, QEvent *event) { - if(watched == m_delLabel) { - if(event->type() == QEvent::MouseButtonPress) { -// qDebug()<<"pressed!"; - Q_EMIT this->onDelBtnClicked(m_path); - } - } - return QObject::eventFilter(watched, event); -} diff --git a/frontend/control/settings-widget.h b/frontend/control/settings-widget.h deleted file mode 100644 index 185a8c1..0000000 --- a/frontend/control/settings-widget.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * - * Copyright (C) 2020, KylinSoft Co., Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Authors: zhangjiaping - * - */ -#ifndef SETTINGSWIDGET_H -#define SETTINGSWIDGET_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "libsearch.h" -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) -#include "xatom-helper.h" -#endif - -namespace UkuiSearch { -class FolderListItem : public QWidget { - Q_OBJECT -public: - explicit FolderListItem(QWidget *parent = nullptr, const QString &path = 0); - ~FolderListItem(); - QString getPath(); - -protected: - virtual void enterEvent(QEvent *); - virtual void leaveEvent(QEvent *); - bool eventFilter(QObject *, QEvent *); - -private: - void initUi(); - - QString m_path; - - QVBoxLayout * m_layout = nullptr; - QWidget * m_widget = nullptr; - QHBoxLayout * m_widgetlayout = nullptr; - QLabel * m_iconLabel = nullptr; - QLabel * m_pathLabel = nullptr; - QLabel * m_delLabel = nullptr; -Q_SIGNALS: - void onDelBtnClicked(const QString&); -}; - -class SettingsWidget : public QWidget { - Q_OBJECT -public: - explicit SettingsWidget(QWidget *parent = nullptr); - ~SettingsWidget(); - - void setIndexState(bool); - void setIndexNum(int); - void showWidget(); - void resetWebEngine(); - -private: - void initUi(); - void setupBlackList(const QStringList &); - void clearLayout(QLayout *); - void refreshIndexState(); - void paintEvent(QPaintEvent *); - void resize(); - void showWarningDialog(const int&); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) - MotifWmHints m_hints; -#endif - - //标题栏 - QVBoxLayout * m_mainLyt = nullptr; - QFrame * m_contentFrame = nullptr; - QVBoxLayout * m_contentLyt = nullptr; - QFrame * m_titleFrame = nullptr; - QHBoxLayout * m_titleLyt = nullptr; - QLabel * m_titleIcon = nullptr; - QLabel * m_titleLabel = nullptr; - QPushButton * m_closeBtn = nullptr; - - //设置 - QLabel * m_settingLabel = nullptr; - //文件索引 - QLabel * m_indexTitleLabel = nullptr; - QLabel * m_indexStateLabel = nullptr; - QLabel * m_indexNumLabel = nullptr; - //文件索引设置(黑名单) - QLabel * m_indexSettingLabel = nullptr; - QLabel * m_indexDescLabel = nullptr; - QFrame * m_indexBtnFrame = nullptr; - QHBoxLayout * m_indexBtnLyt = nullptr; - QPushButton * m_addDirBtn = nullptr; - QScrollArea * m_dirListArea = nullptr; - QWidget * m_dirListWidget = nullptr; - QVBoxLayout * m_dirListLyt = nullptr; - - //搜索引擎设置 - QLabel * m_searchEngineLabel = nullptr; - QLabel * m_engineDescLabel = nullptr; - QButtonGroup * m_engineBtnGroup = nullptr; - QFrame * m_radioBtnFrame = nullptr; - QHBoxLayout * m_radioBtnLyt = nullptr; - QRadioButton * m_baiduBtn = nullptr; - QLabel * m_baiduLabel = nullptr; - QRadioButton * m_sougouBtn = nullptr; - QLabel * m_sougouLabel = nullptr; - QRadioButton * m_360Btn = nullptr; - QLabel * m_360Label = nullptr; - - //取消与确认按钮 - QFrame * m_bottomBtnFrame = nullptr; - QHBoxLayout * m_bottomBtnLyt = nullptr; - QPushButton * m_cancelBtn = nullptr; - QPushButton * m_confirmBtn = nullptr; - - QTimer * m_timer; - - int m_blockdirs = 0; //黑名单文件夹数量 - -Q_SIGNALS: - void settingWidgetClosed(); - void webEngineChanged(const QString&); - -private Q_SLOTS: -// void onBtnConfirmClicked(); -// void onBtnCancelClicked(); - void onBtnAddClicked(); - void onBtnDelClicked(const QString&); - void setWebEngine(const QString&); -}; -} - -#endif // SETTINGSWIDGET_H diff --git a/frontend/control/stack-pages/search-page-section.cpp b/frontend/control/stack-pages/search-page-section.cpp index f363655..0c7bd8c 100644 --- a/frontend/control/stack-pages/search-page-section.cpp +++ b/frontend/control/stack-pages/search-page-section.cpp @@ -630,49 +630,6 @@ QString escapeHtml(const QString & str) { return temp; } -void DetailWidget::setWidgetInfo(const QString &plugin_name, const SearchPluginIface::ResultInfo &info) -{ -// clearLayout(m_descFrameLyt); -// clearLayout(m_previewFrameLyt); -// if(SearchPluginManager::getInstance()->getPlugin(plugin_name)->isPreviewEnable(info.actionKey,info.type)) { -// m_iconLabel->hide(); -// m_previewFrameLyt->addWidget(SearchPluginManager::getInstance()->getPlugin(plugin_name)->previewPage(info.actionKey,info.type, m_previewFrame), 0 , Qt::AlignHCenter); -// m_previewFrameLyt->setContentsMargins(0,0,0,0); -// m_previewFrame->show(); -// } else { -// m_previewFrame->hide(); -// m_iconLabel->setPixmap(info.icon.pixmap(info.icon.actualSize(ICON_SIZE))); -// m_iconLabel->show(); -// } -// QFontMetrics fontMetrics = m_nameLabel->fontMetrics(); -// QString name = fontMetrics.elidedText(info.name, Qt::ElideRight, NAME_LABEL_WIDTH - 8); -// m_nameLabel->setText(QString("

%1

").arg(escapeHtml(name))); -// m_nameLabel->setToolTip(info.name); -// m_pluginLabel->setText(plugin_name); -// m_nameFrame->show(); -// m_line_1->show(); - -// if (info.description.length() > 0) { -// //NEW_TODO 样式待优化 -// clearLayout(m_descFrameLyt); -// Q_FOREACH (SearchPluginIface::DescriptionInfo desc, info.description) { -// QLabel * descLabel = new QLabel(m_descFrame); -// descLabel->setTextFormat(Qt::PlainText); -// descLabel->setWordWrap(true); -// QString show_desc = desc.key + " " + desc.value; -// descLabel->setText(show_desc); -// m_descFrameLyt->addWidget(descLabel); -// } -// m_descFrame->show(); -// m_line_2->show(); -// } -// clearLayout(m_actionFrameLyt); -// Q_FOREACH (SearchPluginIface::Actioninfo actioninfo, SearchPluginManager::getInstance()->getPlugin(plugin_name)->getActioninfo(info.type)) { -// ActionLabel * actionLabel = new ActionLabel(actioninfo.displayName, info.actionKey, actioninfo.actionkey, plugin_name, info.type, m_actionFrame); -// m_actionFrameLyt->addWidget(actionLabel); -// } -// m_actionFrame->show(); -} void DetailWidget::updateDetailPage(const QString &plugin_name, const SearchPluginIface::ResultInfo &info) { @@ -697,71 +654,6 @@ void DetailWidget::updateDetailPage(const QString &plugin_name, const SearchPlug m_currentPluginId = plugin_name; } -void DetailWidget::clear() -{ -// m_iconLabel->hide(); -// m_nameFrame->hide(); -// m_line_1->hide(); -// m_descFrame->hide(); -// m_line_2->hide(); -// m_actionFrame->hide(); -} - -void DetailWidget::initUi() -{ -// this->setFixedSize(368, 516); -// m_mainLyt = new QVBoxLayout(this); -// this->setLayout(m_mainLyt); -// m_mainLyt->setContentsMargins(DETAIL_WIDGET_MARGINS); -// m_mainLyt->setAlignment(Qt::AlignHCenter); - -// m_iconLabel = new QLabel(this); -// m_iconLabel->setFixedHeight(DETAIL_ICON_HEIGHT); -// m_iconLabel->setAlignment(Qt::AlignCenter); -// m_previewFrame = new QFrame(this); -// m_previewFrameLyt = new QHBoxLayout(m_previewFrame); - -// m_nameFrame = new QFrame(this); -// m_nameFrameLyt = new QHBoxLayout(m_nameFrame); -// m_nameFrame->setLayout(m_nameFrameLyt); -// m_nameFrameLyt->setContentsMargins(DETAIL_FRAME_MARGINS); -// m_nameLabel = new QLabel(m_nameFrame); -// m_nameLabel->setMaximumWidth(NAME_LABEL_WIDTH); -// m_pluginLabel = new QLabel(m_nameFrame); -// m_pluginLabel->setEnabled(false); -// m_nameFrameLyt->addWidget(m_nameLabel); -// m_nameFrameLyt->addStretch(); -// m_nameFrameLyt->addWidget(m_pluginLabel); - -// m_line_1 = new QFrame(this); -// m_line_1->setFixedHeight(1); -// m_line_1->setLineWidth(0); -// m_line_1->setStyleSheet(LINE_STYLE); -// m_line_2 = new QFrame(this); -// m_line_2->setFixedHeight(1); -// m_line_2->setLineWidth(0); -// m_line_2->setStyleSheet(LINE_STYLE); - -// m_descFrame = new QFrame(this); -// m_descFrameLyt = new QVBoxLayout(m_descFrame); -// m_descFrame->setLayout(m_descFrameLyt); -// m_descFrameLyt->setContentsMargins(DETAIL_FRAME_MARGINS); - -// m_actionFrame = new QFrame(this); -// m_actionFrameLyt = new QVBoxLayout(m_actionFrame); -// m_actionFrame->setLayout(m_actionFrameLyt); -// m_actionFrameLyt->setContentsMargins(DETAIL_FRAME_MARGINS); - -// m_mainLyt->addWidget(m_iconLabel); -// m_mainLyt->addWidget(m_previewFrame, 0, Qt::AlignHCenter); -// m_mainLyt->addWidget(m_nameFrame); -// m_mainLyt->addWidget(m_line_1); -// m_mainLyt->addWidget(m_descFrame); -// m_mainLyt->addWidget(m_line_2); -// m_mainLyt->addWidget(m_actionFrame); -// m_mainLyt->addStretch(); -} - void DetailWidget::paintEvent(QPaintEvent *event) { QStyleOption opt; @@ -791,53 +683,6 @@ void DetailWidget::clearLayout(QLayout *layout) child = NULL; } -//ActionLabel::ActionLabel(const QString &action, const QString &key, const int &ActionKey, const QString &pluginId, const int type, QWidget *parent) : QLabel(parent) -//{ -// m_action = action; -// m_key = key; -// m_actionKey = ActionKey; -// m_type = type; -// m_pluginId = pluginId; -// this->initUi(); -// this->installEventFilter(this); -//} - -//void ActionLabel::initUi() -//{ -// this->setText(m_action); -// QPalette pal = palette(); -// pal.setColor(QPalette::WindowText, ACTION_NORMAL_COLOR); -// pal.setColor(QPalette::Light, ACTION_HOVER_COLOR); -// pal.setColor(QPalette::Dark, ACTION_PRESS_COLOR); -// this->setPalette(pal); -// this->setForegroundRole(QPalette::WindowText); -// this->setCursor(QCursor(Qt::PointingHandCursor)); -//} - -//bool ActionLabel::eventFilter(QObject *watched, QEvent *event) -//{ -// if (watched == this) { -// if(event->type() == QEvent::MouseButtonPress) { -// this->setForegroundRole(QPalette::Dark); -// return true; -// } else if(event->type() == QEvent::MouseButtonRelease) { -// SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_pluginId); -// if (plugin) -// plugin->openAction(m_actionKey, m_key, m_type); -// else -// qWarning()<<"Get plugin failed!"; -// this->setForegroundRole(QPalette::Light); -// return true; -// } else if(event->type() == QEvent::Enter) { -// this->setForegroundRole(QPalette::Light); -// return true; -// } else if(event->type() == QEvent::Leave) { -// this->setForegroundRole(QPalette::WindowText); -// return true; -// } -// } -//} - ResultScrollBar::ResultScrollBar(QWidget *parent) : QScrollBar(parent) { diff --git a/frontend/control/stack-pages/search-page-section.h b/frontend/control/stack-pages/search-page-section.h index 2559d13..7773040 100644 --- a/frontend/control/stack-pages/search-page-section.h +++ b/frontend/control/stack-pages/search-page-section.h @@ -28,7 +28,6 @@ #include "result-view.h" #include "search-plugin-iface.h" #include "best-list-view.h" -#include "web-search-view.h" namespace UkuiSearch { class ResultScrollBar : public QScrollBar @@ -115,32 +114,16 @@ class DetailWidget : public QWidget public: DetailWidget(QWidget *parent = nullptr); ~DetailWidget() = default; - void clear(); public Q_SLOTS: - void setWidgetInfo(const QString &plugin_name, const SearchPluginIface::ResultInfo &info); void updateDetailPage(const QString &plugin_name, const SearchPluginIface::ResultInfo &info); protected: void paintEvent(QPaintEvent *event); private: - void initUi(); void clearLayout(QLayout *); QVBoxLayout * m_mainLyt = nullptr; QString m_currentPluginId; QWidget *m_detailPage = nullptr; -// QLabel * m_iconLabel = nullptr; -// QFrame *m_previewFrame = nullptr; -// QHBoxLayout *m_previewFrameLyt = nullptr; -// QFrame * m_nameFrame = nullptr; -// QHBoxLayout * m_nameFrameLyt = nullptr; -// QLabel * m_nameLabel = nullptr; -// QLabel * m_pluginLabel = nullptr; -// QFrame * m_line_1 = nullptr; -// QFrame * m_descFrame = nullptr; -// QVBoxLayout * m_descFrameLyt = nullptr; -// QFrame * m_line_2 = nullptr; -// QFrame * m_actionFrame = nullptr; -// QVBoxLayout * m_actionFrameLyt = nullptr; }; class DetailArea : public QScrollArea @@ -156,24 +139,6 @@ private: Q_SIGNALS: void setWidgetInfo(const QString&, const SearchPluginIface::ResultInfo&); }; - -//class ActionLabel : public QLabel -//{ -// Q_OBJECT -//public: -// ActionLabel(const QString &action, const QString &key, const int &ActionKey, const QString &pluginId, const int type = 0, QWidget *parent = nullptr); -// ~ActionLabel() = default; -//private: -// void initUi(); -// QString m_action; -// QString m_key; -// int m_actionKey; -// int m_type = 0; -// QString m_pluginId; - -//protected: -// bool eventFilter(QObject *, QEvent *); -//}; } #endif // SEARCHPAGESECTION_H diff --git a/frontend/control/stack-pages/search-result-page.cpp b/frontend/control/stack-pages/search-result-page.cpp index e83c52c..6c7fe1f 100644 --- a/frontend/control/stack-pages/search-result-page.cpp +++ b/frontend/control/stack-pages/search-result-page.cpp @@ -19,6 +19,7 @@ * */ #include "search-result-page.h" +#include "global-settings.h" #include QT_BEGIN_NAMESPACE extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); @@ -35,11 +36,6 @@ SearchResultPage::SearchResultPage(QWidget *parent) : QWidget(parent) setInternalPlugins(); } -void SearchResultPage::setSize(const int&width, const int&height) -{ -// m_splitter->setFixedSize(width, height); -} - void SearchResultPage::setInternalPlugins() { QList infoList = SearchPluginManager::getInstance()->getPluginIds(); @@ -129,10 +125,11 @@ void SearchResultPage::setWidth(int width) void SearchResultPage::paintEvent(QPaintEvent *event) { + Q_UNUSED(event) QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setBrush(palette().base()); - p.setOpacity(GlobalSettings::getInstance()->getValue(TRANSPARENCY_KEY).toDouble()); + p.setOpacity(GlobalSettings::getInstance().getValue(TRANSPARENCY_KEY).toDouble()); p.setPen(Qt::NoPen); p.drawRoundedRect(this->rect().adjusted(10,10,-10,-10), 12, 12); @@ -210,10 +207,18 @@ void SearchResultPage::initConnections() setWidth(672); }); connect(m_resultArea, &ResultArea::scrollBarAppeared, this, [ & ]{ - setWidth(672); + if (m_detailArea->isHidden()) { + setWidth(672); + } else { + setWidth(296); + } }); connect(m_resultArea, &ResultArea::scrollBarIsHideen, this, [ & ]{ - setWidth(672); + if (m_detailArea->isHidden()) { + setWidth(672); + } else { + setWidth(296); + } }); connect(m_resultArea, &ResultArea::keyPressChanged, m_detailArea, &DetailArea::setWidgetInfo); connect(m_resultArea, &ResultArea::keyPressChanged, this, [=] () { diff --git a/frontend/control/stack-pages/search-result-page.h b/frontend/control/stack-pages/search-result-page.h index f501620..ad42cc5 100644 --- a/frontend/control/stack-pages/search-result-page.h +++ b/frontend/control/stack-pages/search-result-page.h @@ -31,7 +31,6 @@ class SearchResultPage : public QWidget public: explicit SearchResultPage(QWidget *parent = nullptr); ~SearchResultPage() = default; - void setSize(const int&, const int&); void setInternalPlugins(); void appendPlugin(const QString &plugin_id); void movePlugin(const QString &plugin_id, int index); diff --git a/frontend/control/stack-pages/stack-pages.pri b/frontend/control/stack-pages/stack-pages.pri deleted file mode 100644 index d61da71..0000000 --- a/frontend/control/stack-pages/stack-pages.pri +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/search-page-section.h \ - $$PWD/search-result-page.h - -SOURCES += \ - $$PWD/search-page-section.cpp \ - $$PWD/search-result-page.cpp diff --git a/frontend/frontend.pro b/frontend/frontend.pro deleted file mode 100644 index ece5567..0000000 --- a/frontend/frontend.pro +++ /dev/null @@ -1,79 +0,0 @@ -QT += core gui dbus KWindowSystem xml x11extras sql - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -VERSION = 2.2.3 -DEFINES += VERSION='\\"$${VERSION}\\"' -TARGET = ukui-search -TEMPLATE = app - -PKGCONFIG += gio-2.0 glib-2.0 gio-unix-2.0 kysdk-waylandhelper -CONFIG += c++11 link_pkgconfig no_keywords lrelease -LIBS += -lxapian -lgsettings-qt -lquazip5 -lX11 -#LIBS += -lukui-log4qt -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 -include(../libsearch/libukui-search-headers.pri) -include(control/control.pri) -include(model/model.pri) -include(xatom/xatom.pri) -include(../3rd-parties/qtsingleapplication/qtsingleapplication.pri) -include(view/view.pri) - - -SOURCES += \ - main.cpp \ - mainwindow.cpp \ - ukui-search-dbus-service.cpp \ - ukui-search-gui.cpp - - -HEADERS += \ - mainwindow.h \ - ukui-search-dbus-service.h \ - ukui-search-gui.h - -# Default rules for deployment. - -target.path = /usr/bin -!isEmpty(target.path): INSTALLS += target - -data-menu.path = /usr/share/applications -data-menu.files += ../data/ukui-search-menu.desktop -data.path = /etc/xdg/autostart -data.files += ../data/ukui-search.desktop - -INSTALLS += data data-menu - -RESOURCES += \ - resource.qrc - -TRANSLATIONS += \ - ../translations/ukui-search/zh_CN.ts \ - ../translations/ukui-search/tr.ts \ - ../translations/ukui-search/bo_CN.ts - -qm_files.path = /usr/share/ukui-search/translations/ -qm_files.files = $$OUT_PWD/.qm/*.qm - -schemes.path = /usr/share/glib-2.0/schemas/ -schemes.files += ../data/org.ukui.log4qt.ukui-search.gschema.xml - -INSTALLS += qm_files schemes - -LIBS += -L$$OUT_PWD/../libchinese-segmentation -lchinese-segmentation \ - -L$$OUT_PWD/../libsearch -lukui-search - -INCLUDEPATH += $$PWD/../libchinese-segmentation -DEPENDPATH += $$PWD/../libchinese-segmentation - -DISTFILES += \ - ../data/org.ukui.log4qt.ukui-search.gschema.xml \ diff --git a/frontend/main.cpp b/frontend/main.cpp index 24cf0d7..88508f9 100644 --- a/frontend/main.cpp +++ b/frontend/main.cpp @@ -21,76 +21,17 @@ * */ - -#include -#include -#include +#include #include -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) -#include -#endif -#include -#include -#include +#include #include "ukui-search-gui.h" +#include "log-utils.h" using namespace UkuiSearch; -void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) -{ - QByteArray localMsg = msg.toLocal8Bit(); - QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit(); - - bool showDebug = true; -// QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/ukui-search.log"; -// QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search/ukui-search.log"; - QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search.log"; - if (!QFile::exists(logFilePath)) { - showDebug = false; - } - FILE *log_file = nullptr; - - if (showDebug) { - log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+"); - } - - const char *file = context.file ? context.file : ""; - const char *function = context.function ? context.function : ""; - switch (type) { - case QtDebugMsg: - if (!log_file) { - break; - } - fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtInfoMsg: - fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtWarningMsg: - fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtCriticalMsg: - fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtFatalMsg: - fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - } - - if (log_file) - fclose(log_file); -} - int main(int argc, char *argv[]) { -//v101日志模块 -//#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) -// //Init log module -// initUkuiLog4qt("ukui-search"); -//#endif - // Determine whether the home directory has been created, and if not, keep waiting. char *p_home = NULL; - unsigned int i = 0; while(p_home == NULL) { ::sleep(1); @@ -111,14 +52,8 @@ int main(int argc, char *argv[]) { } // Output log to file - qInstallMessageHandler(messageOutput); -//若使用v101日志模块,可以解放如下判断条件 -//#if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0)) -// // Output log to file -// qInstallMessageHandler(messageOutput); -//#endif - - // Register meta type + LogUtils::initLogFile("ukui-search"); + qInstallMessageHandler(LogUtils::messageOutput); qDebug() << "ukui-search main start"; // If qt version bigger than 5.12, enable high dpi scaling and use high dpi pixmaps? #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) @@ -128,7 +63,18 @@ int main(int argc, char *argv[]) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif - UkuiSearchGui app(argc, argv, QString("ukui-search-gui-%1").arg(QX11Info::appScreen())); + QString display; + QString sessionType; + if(QString(getenv("XDG_SESSION_TYPE")) == "wayland") { + sessionType = "wayland"; + display = getenv("WAYLAND_DISPLAY"); + } else { + sessionType = "x11"; + display = getenv("DISPLAY"); + } + qDebug() << "Current DISPLAY: " << display; + UkuiSearchGui app(argc, argv, display, sessionType); + if (app.isRunning()) return 0; diff --git a/frontend/mainwindow.cpp b/frontend/mainwindow.cpp index 6bcb226..83e2826 100644 --- a/frontend/mainwindow.cpp +++ b/frontend/mainwindow.cpp @@ -36,6 +36,7 @@ #include "windowmanager/windowmanager.h" #include "global-settings.h" #include "action-transmiter.h" +#include "icon-loader.h" #define MAIN_MARGINS 0, 0, 0, 0 #define TITLE_MARGINS 0,0,0,0 @@ -50,7 +51,7 @@ #define MAIN_SETTINGS QDir::homePath() + "/.config/org.ukui/ukui-search/ukui-search.conf" #define ENABLE_CREATE_INDEX_ASK_DIALOG "enable_create_index_ask_dialog" - +const static QString FILE_INDEX_ENABLE_KEY = "fileIndexEnable"; using namespace UkuiSearch; extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); @@ -75,13 +76,12 @@ MainWindow::MainWindow(QWidget *parent) : initTimer(); m_sys_tray_icon = new QSystemTrayIcon(this); - m_sys_tray_icon->setIcon(QIcon::fromTheme("system-search-symbolic", QIcon(":/res/icons/edit-find-symbolic.svg"))); + m_sys_tray_icon->setIcon(IconLoader::loadIconQt("system-search-symbolic", QIcon(":/res/icons/edit-find-symbolic.svg"))); m_sys_tray_icon->setToolTip(tr("Global Search")); m_sys_tray_icon->show(); installEventFilter(this); initConnections(); - // connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this,[&](WId activeWindowId){ // qDebug() << "activeWindowChanged!!!" << activeWindowId; // if (activeWindowId != this->winId()) { @@ -91,9 +91,12 @@ MainWindow::MainWindow(QWidget *parent) : m_appWidgetPlugin = new AppWidgetPlugin; - connect(m_appWidgetPlugin, &AppWidgetPlugin::startSearch, this, [ & ] (QString keyword){ +// connect(m_appWidgetPlugin, &AppWidgetPlugin::startSearch, this, [ & ] (QString keyword){ +// this->bootOptionsFilter("-s"); +// this->setText(keyword); +// }); + connect(m_appWidgetPlugin, &AppWidgetPlugin::start, this, [&] { this->bootOptionsFilter("-s"); - this->setText(keyword); }); connect(ActionTransmiter::getInstance(), &ActionTransmiter::hideUIAction, this, &MainWindow::tryHideMainwindow); } @@ -103,10 +106,10 @@ MainWindow::~MainWindow() { delete m_askDialog; m_askDialog = NULL; } - if(m_askTimer) { - delete m_askTimer; - m_askTimer = NULL; - } +// if(m_askTimer) { +// delete m_askTimer; +// m_askTimer = NULL; +// } if(m_searchGsettings) { delete m_searchGsettings; m_searchGsettings = NULL; @@ -134,8 +137,7 @@ void MainWindow::initUi() { void MainWindow::initConnections() { connect(m_sys_tray_icon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivatedSlot); - connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &MainWindow::monitorResolutionChange); - connect(qApp, &QApplication::primaryScreenChanged, this, &MainWindow::primaryScreenChangedSlot); + connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &MainWindow::ScreenGeometryChanged); connect(m_askDialog, &CreateIndexAskDialog::closed, this, [ = ]() { m_isAskDialogVisible = false; }); @@ -163,8 +165,8 @@ void MainWindow::bootOptionsFilter(QString opt) { clearSearchResult(); centerToScreen(this); this->m_searchBarWidget->setFocus(); - this->activateWindow(); } + this->activateWindow(); } } @@ -235,7 +237,7 @@ void MainWindow::searchKeywordSlot(const QString &keyword) //允许弹窗且当前次搜索(为关闭主界面,算一次搜索过程)未询问且当前为暴力搜索 if(m_settings->value(ENABLE_CREATE_INDEX_ASK_DIALOG).toBool() && !m_currentSearchAsked - && GlobalSettings::getInstance()->getValue(FILE_INDEX_ENABLE_KEY).toBool() == false) { + && !m_isIndexSearch) { m_askTimer->start(); } Q_EMIT m_searchResultPage->startSearch(keyword); @@ -258,73 +260,10 @@ void MainWindow::tryHide() this->tryHideMainwindow(); } -/** - * @brief monitorResolutionChange 监听屏幕改变 - * @param rect - */ -void MainWindow::monitorResolutionChange(QRect rect) { +void MainWindow::ScreenGeometryChanged(QRect rect) { Q_UNUSED(rect); -} - -/** - * @brief primaryScreenChangedSlot 监听分辨率改变 - * @param screen - */ -void MainWindow::primaryScreenChangedSlot(QScreen *screen) { - Q_UNUSED(screen); - -} - -/** - * @brief MainWindow::moveToPanel 将主界面移动到任务栏旁边(跟随任务栏位置) - */ -void MainWindow::moveToPanel() { - QRect availableGeometry = qApp->primaryScreen()->availableGeometry(); - QRect screenGeometry = qApp->primaryScreen()->geometry(); - - QDBusInterface primaryScreenInterface("org.ukui.SettingsDaemon", - "/org/ukui/SettingsDaemon/wayland", - "org.ukui.SettingsDaemon.wayland", - QDBusConnection::sessionBus()); - if(QDBusReply(primaryScreenInterface.call("x")).isValid()) { - QDBusReply x = primaryScreenInterface.call("x"); - QDBusReply y = primaryScreenInterface.call("y"); - QDBusReply width = primaryScreenInterface.call("width"); - QDBusReply height = primaryScreenInterface.call("height"); - screenGeometry.setX(x); - screenGeometry.setY(y); - screenGeometry.setWidth(width); - screenGeometry.setHeight(height); - availableGeometry.setX(x); - availableGeometry.setY(y); - availableGeometry.setWidth(width); - availableGeometry.setHeight(height); - } - - QDesktopWidget * desktopWidget = QApplication::desktop(); - QRect screenMainRect = desktopWidget->screenGeometry(0);//获取设备屏幕大小 - - QDBusInterface interface("com.ukui.panel.desktop", - "/", - "com.ukui.panel.desktop", - QDBusConnection::sessionBus()); - - int position = QDBusReply(interface.call("GetPanelPosition", "position")); - int height = QDBusReply(interface.call("GetPanelSize", "height")); - int d = 8; //窗口边沿到任务栏距离 - - if(position == 0) { - //任务栏在下侧 - this->move(availableGeometry.x() + availableGeometry.width() - this->width() - d, screenGeometry.y() + screenGeometry.height() - this->height() - height - d); - } else if(position == 1) { - //任务栏在上侧 - this->move(availableGeometry.x() + availableGeometry.width() - this->width() - d, screenGeometry.y() + height + d); - } else if(position == 2) { - //任务栏在左侧 - this->move(screenGeometry.x() + height + d, screenGeometry.y() + screenGeometry.height() - this->height() - d); - } else if(position == 3) { - //任务栏在右侧 - this->move(screenGeometry.x() + screenGeometry.width() - this->width() - height - d, screenGeometry.y() + screenGeometry.height() - this->height() - d); + if(this->isVisible()) { + centerToScreen(this); } } @@ -336,15 +275,13 @@ void MainWindow::centerToScreen(QWidget* widget) { if(!widget) return; KWindowSystem::setState(this->winId(),NET::SkipTaskbar | NET::SkipPager); - QDesktopWidget* m = QApplication::desktop(); - QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos())); + QRect desk_rect = qApp->screenAt(QCursor::pos())->geometry(); int desk_x = desk_rect.width(); int desk_y = desk_rect.height(); int x = widget->width(); - int y = widget->height(); widget->show(); kdk::WindowManager::setGeometry(this->windowHandle(),QRect(desk_x / 2 - x / 2 + desk_rect.left(), - desk_y / 3 + desk_rect.top(), + desk_y / 6 + desk_rect.top(), this->width(), this->height())); //设置跳过多任务视图 @@ -358,10 +295,13 @@ void MainWindow::initSettings() { const QByteArray id(UKUI_SEARCH_SCHEMAS); if(QGSettings::isSchemaInstalled(id)) { m_searchGsettings = new QGSettings(id); + if (m_searchGsettings->keys().contains(FILE_INDEX_ENABLE_KEY)) { + m_isIndexSearch = m_searchGsettings->get(FILE_INDEX_ENABLE_KEY).toBool(); + } connect(m_searchGsettings, &QGSettings::changed, this, [ = ](const QString & key) { if(key == FILE_INDEX_ENABLE_KEY) { - bool isIndexSearch = m_searchGsettings->get(FILE_INDEX_ENABLE_KEY).toBool(); - if(m_researchTimer->isActive() && !isIndexSearch) { + m_isIndexSearch = m_searchGsettings->get(FILE_INDEX_ENABLE_KEY).toBool(); + if(m_researchTimer->isActive() && !m_isIndexSearch) { m_researchTimer->stop(); } } @@ -372,14 +312,24 @@ void MainWindow::initSettings() { //使用GSetting获取当前窗口应该使用的透明度 double MainWindow::getTransparentData() { - return GlobalSettings::getInstance()->getValue(TRANSPARENCY_KEY).toDouble(); + return GlobalSettings::getInstance().getValue(TRANSPARENCY_KEY).toDouble(); } void MainWindow::initTimer() { - m_askTimer = new QTimer; + m_askTimer = new QTimer(this); m_askTimer->setInterval(ASK_INDEX_TIME); connect(m_askTimer, &QTimer::timeout, this, [ = ]() { - if(this->isVisible()) { + QWindow *modal = QGuiApplication::modalWindow(); + if(modal) { + m_askTimer->stop(); + connect(modal, &QWindow::visibleChanged, this, [ & ](bool visible){ + if(!visible) { + m_askTimer->start(); + } + }, Qt::UniqueConnection); + return; + } + if(this->isVisible() && !m_isIndexSearch) { m_isAskDialogVisible = true; kdk::UkuiStyleHelper::self()->removeHeader(m_askDialog); m_askDialog->show(); @@ -404,8 +354,9 @@ void MainWindow::initTimer() { m_askTimer->stop(); } else { //允许弹窗且当前次搜索(为关闭主界面,算一次搜索过程)未询问且当前为暴力搜索 - if(m_settings->value(ENABLE_CREATE_INDEX_ASK_DIALOG, true).toBool() && !m_currentSearchAsked && GlobalSettings::getInstance()->getValue(FILE_INDEX_ENABLE_KEY).toBool() == false) + if(m_settings->value(ENABLE_CREATE_INDEX_ASK_DIALOG, true).toBool() && !m_currentSearchAsked && !m_isIndexSearch) { m_askTimer->start(); + } } }); } @@ -418,10 +369,11 @@ bool MainWindow::tryHideMainwindow() if (!m_isAskDialogVisible && QApplication::activeModalWidget() == nullptr) { qDebug()<<"Mainwindow will be hidden"; m_currentSearchAsked = false; - this->hide(); m_askTimer->stop(); m_researchTimer->stop(); Q_EMIT m_searchResultPage->stopSearch(); + this->clearSearchResult(); + this->hide(); return true; } else { //有上层弹窗未关闭,不允许隐藏主界面 @@ -468,8 +420,9 @@ void MainWindow::keyPressEvent(QKeyEvent *event) return QWidget::keyPressEvent(event); } -void MainWindow::paintEvent(QPaintEvent *event) { - +void MainWindow::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) QPainterPath path; path.addRoundedRect(m_searchBarWidget->x()+10, m_searchBarWidget->y()+10, m_searchBarWidget->width()-20, m_searchBarWidget->height()-20, 12, 12); diff --git a/frontend/mainwindow.h b/frontend/mainwindow.h index 7c03cfd..01189e6 100644 --- a/frontend/mainwindow.h +++ b/frontend/mainwindow.h @@ -67,11 +67,6 @@ class MainWindow : public QMainWindow { public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); - /** - * @brief Load the main window - * The position which mainwindow shows follow the ukui-panel. - */ - void moveToPanel(); // The position which mainwindow shows in the center of screen where the cursor in. void centerToScreen(QWidget* widget); @@ -87,16 +82,8 @@ public: bool eventFilter(QObject *watched, QEvent *event) override; public Q_SLOTS: - /** - * @brief Monitor screen resolution - * @param rect: Screen resolution - */ - void monitorResolutionChange(QRect rect); - /** - * @brief Monitor primary screen changes - * @param screen: Primary screen - */ - void primaryScreenChangedSlot(QScreen *screen); + + void ScreenGeometryChanged(QRect rect); void bootOptionsFilter(QString opt); // 过滤终端命令 void clearSearchResult(); //清空搜索结果 void trayIconActivatedSlot(QSystemTrayIcon::ActivationReason reason); @@ -127,7 +114,7 @@ private: QGSettings *m_searchGsettings = nullptr; QSettings *m_settings = nullptr; AppWidgetPlugin *m_appWidgetPlugin = nullptr; - + bool m_isIndexSearch = false; }; } diff --git a/frontend/model/README.md b/frontend/model/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/model/best-list-model.cpp b/frontend/model/best-list-model.cpp index 97f5159..66ba7e3 100644 --- a/frontend/model/best-list-model.cpp +++ b/frontend/model/best-list-model.cpp @@ -25,25 +25,26 @@ using namespace UkuiSearch; BestListModel::BestListModel(QObject *parent) : QAbstractItemModel(parent) { - m_item = new SearchResultItem; initConnections(); } QModelIndex BestListModel::index(int row, int column, const QModelIndex &parent) const { - if(row < 0 || row > m_item->m_result_info_list.length() - 1) + Q_UNUSED(parent) + if(row < 0 || row > m_items.length() - 1) return QModelIndex(); - return createIndex(row, column, m_item); + return createIndex(row, column, nullptr); } QModelIndex BestListModel::parent(const QModelIndex &index) const { + Q_UNUSED(index) return QModelIndex(); } int BestListModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : (m_isExpanded ? m_item->m_result_info_list.length() : NUM_LIMIT_SHOWN_DEFAULT); + return parent.isValid() ? 0 : (m_isExpanded ? m_items.length() : NUM_LIMIT_SHOWN_DEFAULT); } int BestListModel::columnCount(const QModelIndex &parent) const @@ -55,13 +56,13 @@ QVariant BestListModel::data(const QModelIndex &index, int role) const { switch(role) { case Qt::DecorationRole: { - return m_item->m_result_info_list.at(index.row()).icon; + return m_items.at(index.row()).icon; } case Qt::DisplayRole: { - return m_item->m_result_info_list.at(index.row()).name; + return m_items.at(index.row()).name; } case Qt::ToolTipRole: { - return m_item->m_result_info_list.at(index.row()).name; + return m_items.at(index.row()).name; } default: return QVariant(); @@ -71,7 +72,7 @@ QVariant BestListModel::data(const QModelIndex &index, int role) const const SearchPluginIface::ResultInfo &BestListModel::getInfo(const QModelIndex &index) { - return m_item->m_result_info_list.at(index.row()); + return m_items.at(index.row()); } const QString &BestListModel::getPluginInfo(const QModelIndex &index) @@ -84,7 +85,7 @@ void BestListModel::setExpanded(const bool &is_expanded) this->beginResetModel(); m_isExpanded = is_expanded; this->endResetModel(); - Q_EMIT this->itemListChanged(m_item->m_result_info_list.length()); + Q_EMIT this->itemListChanged(m_items.length()); } const bool &BestListModel::isExpanded() @@ -96,13 +97,14 @@ QStringList BestListModel::getActions(const QModelIndex &index) { // if (m_item->m_result_info_list.length() > index.row() && index.row() >= 0) // return m_item->m_result_info_list.at(index.row()).actionList; + Q_UNUSED(index) return QStringList(); } QString BestListModel::getKey(const QModelIndex &index) { - if (m_item->m_result_info_list.length() > index.row() && index.row() >= 0) - return m_item->m_result_info_list.at(index.row()).actionKey; + if (m_items.length() > index.row() && index.row() >= 0) + return m_items.at(index.row()).actionKey; return NULL; } @@ -115,19 +117,19 @@ void BestListModel::appendInfo(const QString &pluginId, const SearchPluginIface: m_plugin_action_key_list.append(info.actionKey); } if (m_plugin_id_list.contains(pluginId)) { - if (info.name == m_item->m_result_info_list.at(m_plugin_id_list.lastIndexOf(pluginId)).name) { + if (info.name == m_items.at(m_plugin_id_list.lastIndexOf(pluginId)).name) { return; } // qDebug()<<"plugin ID:"< using namespace UkuiSearch; SearchResultManager::SearchResultManager(const QString& plugin_id, QObject *parent) : QObject(parent) @@ -47,10 +48,11 @@ void SearchResultManager::stopSearch() { if(m_getResultThread->isRunning()) { m_getResultThread->stop(); - SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_pluginId); - plugin->stopSearch(); - qDebug() << m_pluginId << "stopped"; } + SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_pluginId); + plugin->stopSearch(); + qDebug() << m_pluginId << "stopped"; + m_resultQueue->clear(); } void SearchResultManager::initConnections() @@ -71,24 +73,19 @@ void ReceiveResultThread::stop() void ReceiveResultThread::run() { - QTimer *timer = new QTimer; - timer->setInterval(3000); - + QDeadlineTimer deadline(25000); while(!isInterruptionRequested()) { SearchPluginIface::ResultInfo oneResult = m_resultQueue->tryDequeue(); if(oneResult.name.isEmpty()) { - if(!timer->isActive()) { - timer->start(); + if(deadline.remainingTime()) { + msleep(100); + } else { + this->requestInterruption(); } - msleep(100); } else { - timer->stop(); + deadline.setRemainingTime(25000); Q_EMIT gotResultInfo(oneResult); } - - if(timer->isActive() && timer->remainingTime() < 0.01 && m_resultQueue->isEmpty()) { - this->requestInterruption(); - } } - delete m_timer; + m_resultQueue->clear(); } diff --git a/frontend/model/search-result-model.cpp b/frontend/model/search-result-model.cpp index 51a3484..50f3540 100644 --- a/frontend/model/search-result-model.cpp +++ b/frontend/model/search-result-model.cpp @@ -23,7 +23,6 @@ using namespace UkuiSearch; SearchResultModel::SearchResultModel(const QString &plugin_id) { - m_item = new SearchResultItem; m_plugin_id = plugin_id; m_search_manager = new SearchResultManager(plugin_id); m_timer = new QTimer(this); @@ -33,20 +32,23 @@ SearchResultModel::SearchResultModel(const QString &plugin_id) QModelIndex SearchResultModel::index(int row, int column, const QModelIndex &parent) const { - if(row < 0 || row > m_item->m_result_info_list.length() - 1) + Q_UNUSED(parent) + if(row < 0 || row > m_items.length() - 1) return QModelIndex(); // QVector * m_info = &m_result_info_list; - return createIndex(row, column, m_item); + return createIndex(row, column, nullptr); + } QModelIndex SearchResultModel::parent(const QModelIndex &child) const { + Q_UNUSED(child) return QModelIndex(); } int SearchResultModel::rowCount(const QModelIndex &index) const { - return index.isValid() ? 0 : (m_isExpanded ? m_item->m_result_info_list.length() : NUM_LIMIT_SHOWN_DEFAULT); + return index.isValid() ? 0 : (m_isExpanded ? m_items.length() : NUM_LIMIT_SHOWN_DEFAULT); } int SearchResultModel::columnCount(const QModelIndex &index) const @@ -56,15 +58,18 @@ int SearchResultModel::columnCount(const QModelIndex &index) const QVariant SearchResultModel::data(const QModelIndex &index, int role) const { + if (!index.isValid() || index.row() >= m_items.count()) { + return {}; + } switch(role) { case Qt::DecorationRole: { - return m_item->m_result_info_list.at(index.row()).icon; + return m_items.at(index.row()).icon; } case Qt::DisplayRole: { - return m_item->m_result_info_list.at(index.row()).name; + return m_items.at(index.row()).name; } case Qt::ToolTipRole: { - return m_item->m_result_info_list.at(index.row()).name; + return m_items.at(index.row()).name; } default: return QVariant(); @@ -74,35 +79,37 @@ QVariant SearchResultModel::data(const QModelIndex &index, int role) const void SearchResultModel::appendInfo(const SearchPluginIface::ResultInfo &info)//TODO 代码逻辑可尝试梳理优化 { - if (m_item->m_result_info_list.length() > 5 //搜索结果大于5个并且搜索结果处于收起状态时只存储数据无需刷新UI + if (m_items.length() > 5 //搜索结果大于5个并且搜索结果处于收起状态时只存储数据无需刷新UI and !m_isExpanded) { - m_item->m_result_info_list.append(info); + m_items.append(info); return; } - if (m_item->m_result_info_list.length() > 50 + if (m_items.length() > 50 and m_isExpanded) {//搜索结果大于50个并且搜索结果处于展开状态时只存储数据并启动定时,500ms刷新一次UI - m_item->m_result_info_list.append(info); + m_items.append(info); if (!m_timer->isActive()) { m_timer->start(); } return; } - this->beginResetModel(); - m_item->m_result_info_list.append(info); - this->endResetModel(); - Q_EMIT this->itemListChanged(m_item->m_result_info_list.length()); +// this->beginResetModel(); + beginInsertRows(QModelIndex(), m_items.length(), m_items.length()); + m_items.append(info); +// this->endResetModel(); + endInsertRows(); + Q_EMIT this->itemListChanged(m_items.length()); if (m_plugin_id != "Web Page") { - Q_EMIT this->sendBestListData(m_plugin_id, m_item->m_result_info_list.at(0)); + Q_EMIT this->sendBestListData(m_plugin_id, m_items.at(0)); } } void SearchResultModel::startSearch(const QString &keyword) { - if (!m_item->m_result_info_list.isEmpty()) { + if (!m_items.isEmpty()) { this->beginResetModel(); - m_item->m_result_info_list.clear(); + m_items.clear(); this->endResetModel(); - Q_EMIT this->itemListChanged(m_item->m_result_info_list.length()); + Q_EMIT this->itemListChanged(m_items.length()); } m_search_manager->startSearch(keyword); } @@ -112,14 +119,14 @@ void SearchResultModel::initConnections() connect(this, &SearchResultModel::stopSearch, m_search_manager, &SearchResultManager::stopSearch); connect(m_search_manager, &SearchResultManager::gotResultInfo, this, &SearchResultModel::appendInfo); connect(m_timer, &QTimer::timeout, [ = ] () {//500ms刷新一次UI,防止搜索结果数据量过大导致的UI卡顿 - Q_EMIT this->itemListChanged(m_item->m_result_info_list.length()); + Q_EMIT this->itemListChanged(m_items.length()); m_timer->stop(); }); } const SearchPluginIface::ResultInfo &SearchResultModel::getInfo(const QModelIndex &index) { - return m_item->m_result_info_list.at(index.row()); + return m_items.at(index.row()); } void SearchResultModel::setExpanded(const bool &is_expanded) @@ -127,7 +134,7 @@ void SearchResultModel::setExpanded(const bool &is_expanded) this->beginResetModel(); m_isExpanded = is_expanded; this->endResetModel(); - Q_EMIT this->itemListChanged(m_item->m_result_info_list.length()); + Q_EMIT this->itemListChanged(m_items.length()); } const bool &SearchResultModel::isExpanded() @@ -135,32 +142,23 @@ const bool &SearchResultModel::isExpanded() return m_isExpanded; } -/** - * @brief SearchResultModel::getActions 获取操作列表 - * @param index - * @return - */ -QStringList SearchResultModel::getActions(const QModelIndex &index) -{ - if (m_item->m_result_info_list.length() > index.row() && index.row() >= 0) -// return m_item->m_result_info_list.at(index.row()).actionList; - return QStringList(); -} - -QString SearchResultModel::getKey(const QModelIndex &index) -{ - if (m_item->m_result_info_list.length() > index.row() && index.row() >= 0) -// return m_item->m_result_info_list.at(index.row()).key; - return NULL; -} - void SearchResultModel::refresh() { this->beginResetModel(); this->endResetModel(); } -SearchResultItem::SearchResultItem(QObject *parent) : QObject(parent) +void SearchResultModel::stopSearchSlot() { - + beginResetModel(); + m_items.clear(); + m_items.squeeze(); + endResetModel(); + Q_EMIT stopSearch(); +} + +SearchResultModel::~SearchResultModel() +{ + m_items.clear(); + m_items.squeeze(); } diff --git a/frontend/model/search-result-model.h b/frontend/model/search-result-model.h index e8cc153..c9e92cd 100644 --- a/frontend/model/search-result-model.h +++ b/frontend/model/search-result-model.h @@ -27,24 +27,12 @@ namespace UkuiSearch { -class SearchResultItem : public QObject { - friend class SearchResultModel; - friend class BestListModel; - friend class WebSearchModel; - Q_OBJECT -public: - explicit SearchResultItem(QObject *parent = nullptr); - ~SearchResultItem() = default; -private: - //此插件所有搜索结果<具体信息> - QVector m_result_info_list; -}; class SearchResultModel : public QAbstractItemModel { Q_OBJECT public: SearchResultModel(const QString &plugin_id); - ~SearchResultModel() = default; + ~SearchResultModel(); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent) const override; @@ -54,13 +42,12 @@ public: const SearchPluginIface::ResultInfo & getInfo(const QModelIndex&); void setExpanded(const bool&); const bool &isExpanded(); - QStringList getActions(const QModelIndex &); - QString getKey(const QModelIndex &); void refresh(); public Q_SLOTS: void appendInfo(const SearchPluginIface::ResultInfo &); void startSearch(const QString &); + void stopSearchSlot(); Q_SIGNALS: void stopSearch(); @@ -69,7 +56,7 @@ Q_SIGNALS: private: void initConnections(); - SearchResultItem * m_item = nullptr; + QVector m_items; QString m_plugin_id; SearchResultManager * m_search_manager = nullptr; bool m_isExpanded = false; diff --git a/frontend/model/web-search-model.cpp b/frontend/model/web-search-model.cpp deleted file mode 100644 index 8efcdd1..0000000 --- a/frontend/model/web-search-model.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright (C) 2021, KylinSoft Co., Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Authors: jixiaoxu - * - */ -#include "web-search-model.h" -#include - -using namespace UkuiSearch; -WebSearchModel::WebSearchModel(QObject *parent) - : QAbstractItemModel(parent) -{ - m_item = new SearchResultItem; -} - -QModelIndex WebSearchModel::index(int row, int column, const QModelIndex &parent) const -{ - if(row < 0 || row > m_item->m_result_info_list.length() - 1) - return QModelIndex(); - return createIndex(row, column, m_item); -} - -QModelIndex WebSearchModel::parent(const QModelIndex &index) const -{ - return QModelIndex(); -} - -int WebSearchModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) { - return 0; - } - else - return 1; -} - -int WebSearchModel::columnCount(const QModelIndex &parent) const -{ - return parent.isValid() ? 0 : 1; -} - -QVariant WebSearchModel::data(const QModelIndex &index, int role) const -{ - switch(role) { - case Qt::DecorationRole: { - return m_item->m_result_info_list.at(index.row()).icon; - } - case Qt::DisplayRole: { - return m_item->m_result_info_list.at(index.row()).name; - } - case Qt::ToolTipRole: { - return m_item->m_result_info_list.at(index.row()).name; - } - default: - return QVariant(); - } - return QVariant(); -} - -void WebSearchModel::startSearch(const QString &keyword) -{ - this->beginResetModel(); - m_item->m_result_info_list.clear(); - SearchPluginIface::ResultInfo info; - info.icon = QIcon(":/res/icons/edit-find-symbolic.svg"); - info.name = keyword; - m_item->m_result_info_list.append(info); - this->endResetModel(); -} diff --git a/frontend/model/web-search-model.h b/frontend/model/web-search-model.h deleted file mode 100644 index 7e14bbf..0000000 --- a/frontend/model/web-search-model.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef WEBSEARCHMODEL_H -#define WEBSEARCHMODEL_H - -#include -#include -#include -#include "search-result-model.h" - -namespace UkuiSearch { -class WebSearchModel : public QAbstractItemModel -{ - Q_OBJECT - -public: - explicit WebSearchModel(QObject *parent = nullptr); - - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &index) const override; - - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; -public Q_SLOTS: - void startSearch(const QString &); - -private: - SearchResultItem * m_item = nullptr; -}; -} -#endif // WEBSEARCHMODEL_H diff --git a/frontend/org.ukui.search.service.xml b/frontend/org.ukui.search.service.xml new file mode 100644 index 0000000..c0bb900 --- /dev/null +++ b/frontend/org.ukui.search.service.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsearch/search-app-widget-plugin/provider/data/search.conf b/frontend/search-app-widget-plugin/provider/data/search.conf similarity index 71% rename from libsearch/search-app-widget-plugin/provider/data/search.conf rename to frontend/search-app-widget-plugin/provider/data/search.conf index 60e5d47..7dfe2c7 100644 --- a/libsearch/search-app-widget-plugin/provider/data/search.conf +++ b/frontend/search-app-widget-plugin/provider/data/search.conf @@ -12,3 +12,6 @@ targetCellWidth = 2 targetCellHeight = 1 updatePeriodMillis = 0 describe = ukui-search app widget +[LanguageFiles] +zh_CN = /usr/share/appwidget/translations/search_zh_CN.qm +bo_CN = /usr/share/appwidget/translations/search_bo_CN.qm diff --git a/libsearch/search-app-widget-plugin/provider/data/search.png b/frontend/search-app-widget-plugin/provider/data/search.png similarity index 100% rename from libsearch/search-app-widget-plugin/provider/data/search.png rename to frontend/search-app-widget-plugin/provider/data/search.png diff --git a/libsearch/search-app-widget-plugin/provider/data/search.qml b/frontend/search-app-widget-plugin/provider/data/search.qml old mode 100644 new mode 100755 similarity index 56% rename from libsearch/search-app-widget-plugin/provider/data/search.qml rename to frontend/search-app-widget-plugin/provider/data/search.qml index 7b9bc02..f0d6c63 --- a/libsearch/search-app-widget-plugin/provider/data/search.qml +++ b/frontend/search-app-widget-plugin/provider/data/search.qml @@ -4,7 +4,7 @@ import QtQuick.Controls 2.5 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.ukui.appwidget 1.0 -import org.ukui.qqc2style.private 1.0 as StylePrivate +//import org.ukui.qqc2style.private 1.0 as StylePrivate AppWidget { visible: true @@ -41,6 +41,14 @@ AppWidget { onDatavalueChanged: updateSearchBarColor(); + onUserstatusChanged: { + if (userstatus === "Normal") { + mouseArea.enabled = true; + } else if (userstatus === "Editable") { + mouseArea.enabled = false; + } + } + Rectangle { id:searchBar anchors.centerIn: parent @@ -48,10 +56,23 @@ AppWidget { height: 64 * scaling radius: searchBar.height / 2 + MouseArea { + id: mouseArea + anchors.fill: parent; + propagateComposedEvents: true; + + onClicked: { + window.qmldefineeventchangedsignal("clicked", "search", ""); + } + onPressAndHold: { + mouse.accepted = false; + } + } + RowLayout { id: layout - anchors.fill: parent - spacing: 0 + anchors.fill: parent; + spacing: 0; Image { id: image_search @@ -60,46 +81,46 @@ AppWidget { Layout.preferredWidth: 32 * scaling; Layout.preferredHeight: 32 * scaling; - Layout.alignment: Qt.AlignVCenter - source: "file:///usr/share/appwidget/search/ukui-search.svg" + Layout.alignment: Qt.AlignVCenter; + source: "file:///usr/share/appwidget/search/ukui-search.svg"; } Item { clip: true; - Layout.fillWidth: true + Layout.fillWidth: true; Layout.fillHeight: true; Layout.rightMargin: 32 * scaling; - TextInput { + Label { id: searchtext anchors.fill: parent; - Keys.enabled: true - Keys.onEnterPressed: { - window.qmldefineeventchangedsignal("enter", "search", searchtext.text); - searchtext.remove(0, searchtext.length); - } - Keys.onReturnPressed: { - window.qmldefineeventchangedsignal("return", "search", searchtext.text); - searchtext.remove(0, searchtext.length); - } +// Keys.enabled: true; +// Keys.onEnterPressed: { +// window.qmldefineeventchangedsignal("enter", "search", searchtext.text); +// searchtext.remove(0, searchtext.length); +// } +// Keys.onReturnPressed: { +// window.qmldefineeventchangedsignal("return", "search", searchtext.text); +// searchtext.remove(0, searchtext.length); +// } - focus: true - color: StylePrivate.StyleHelper.windowtextcolorrole - maximumLength: 100 * scaling - selectByMouse: true - verticalAlignment: Qt.AlignVCenter - font.pixelSize: 21 * scaling +// focus: true; +// color: StylePrivate.StyleHelper.windowtextcolorrole; +// maximumLength: 100 * scaling; +// selectByMouse: true; +// verticalAlignment: Qt.AlignVCenter; +// font.pixelSize: 21 * scaling; - property string placeholderText: /*qsTr("search")*/"全局搜索" + property string placeholderText: qsTr("search")/*"全局搜索"*/ Text { id: placeholderText text: searchtext.placeholderText font.pixelSize: 21 * scaling - visible: !searchtext.text - anchors.verticalCenter: parent.verticalCenter + visible: !searchtext.text; + anchors.verticalCenter: parent.verticalCenter; } } } diff --git a/libsearch/search-app-widget-plugin/provider/data/ukui-search.svg b/frontend/search-app-widget-plugin/provider/data/ukui-search.svg similarity index 100% rename from libsearch/search-app-widget-plugin/provider/data/ukui-search.svg rename to frontend/search-app-widget-plugin/provider/data/ukui-search.svg diff --git a/libsearch/search-app-widget-plugin/provider/org.ukui.appwidget.provider.search.service b/frontend/search-app-widget-plugin/provider/org.ukui.appwidget.provider.search.service similarity index 100% rename from libsearch/search-app-widget-plugin/provider/org.ukui.appwidget.provider.search.service rename to frontend/search-app-widget-plugin/provider/org.ukui.appwidget.provider.search.service diff --git a/libsearch/search-app-widget-plugin/search-app-widget-plugin.pri b/frontend/search-app-widget-plugin/search-app-widget-plugin.pri similarity index 100% rename from libsearch/search-app-widget-plugin/search-app-widget-plugin.pri rename to frontend/search-app-widget-plugin/search-app-widget-plugin.pri diff --git a/libsearch/search-app-widget-plugin/search.cpp b/frontend/search-app-widget-plugin/search.cpp similarity index 60% rename from libsearch/search-app-widget-plugin/search.cpp rename to frontend/search-app-widget-plugin/search.cpp index 453fa60..b1ca19f 100644 --- a/libsearch/search-app-widget-plugin/search.cpp +++ b/frontend/search-app-widget-plugin/search.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "search.h" #include @@ -9,11 +28,6 @@ #include #include -#define CONTROL_CENTER_PERSONALISE_GSETTINGS_ID "org.ukui.control-center.personalise" -#define TRANSPARENCY_KEY "transparency" -#define THEME_GSETTINGS_ID "org.ukui.style" -#define STYLE_NAME_KEY "styleName" - using namespace UkuiSearch; AppWidgetPlugin::AppWidgetPlugin(QString providername, QObject *parent) : KAppWidgetProvider(providername, parent) @@ -30,23 +44,23 @@ AppWidgetPlugin::AppWidgetPlugin(QString providername, QObject *parent) : KAppWi m_manager = new AppWidget::KAppWidgetManager(this); - connect(GlobalSettings::getInstance(), &GlobalSettings::transparencyChanged, [ & ] { - qDebug() << "transparency changed"; - this->appWidgetUpdate(); - }); - - connect(GlobalSettings::getInstance(), &GlobalSettings::styleChanged, [ & ] { - qDebug() << "style changed"; - this->appWidgetUpdate(); + connect(&GlobalSettings::getInstance(), &GlobalSettings::valueChanged, [ & ] (const QString& key, QVariant value) { + if (key == TRANSPARENCY_KEY || key == STYLE_NAME_KEY) { + this->appWidgetUpdate(); + qDebug() << key << " has changed to" << value; + } }); } void AppWidgetPlugin::appWidgetRecevie(const QString &eventname, const QString &widgetname, const QDBusVariant &value) { qDebug() << widgetname << value.variant(); - if (eventname == "enter" or eventname == "return") { - QString keyword = value.variant().toString(); - Q_EMIT this->startSearch(keyword); +// if (eventname == "enter" or eventname == "return") { +// QString keyword = value.variant().toString(); +// Q_EMIT this->startSearch(keyword); +// } else + if (eventname == "clicked") { + Q_EMIT this->start(); } else { qWarning() << "event:" << eventname << "has no trigger now."; } @@ -54,7 +68,7 @@ void AppWidgetPlugin::appWidgetRecevie(const QString &eventname, const QString & void AppWidgetPlugin::appWidgetUpdate() { - QString theme = GlobalSettings::getInstance()->getValue(STYLE_NAME_KEY).toString(); + QString theme = GlobalSettings::getInstance().getValue(STYLE_NAME_KEY).toString(); QJsonObject obj; if (theme == "ukui-dark") { obj.insert("red", QJsonValue(0)); @@ -68,7 +82,7 @@ void AppWidgetPlugin::appWidgetUpdate() obj.insert("placeHolderTextColor", QJsonValue("#72000000")); } - obj.insert("alpha", QJsonValue(GlobalSettings::getInstance()->getValue(TRANSPARENCY_KEY).toDouble())); + obj.insert("alpha", QJsonValue(GlobalSettings::getInstance().getValue(TRANSPARENCY_KEY).toDouble())); QString jsonData = QString(QJsonDocument(obj).toJson()); QVariantMap dataMap; diff --git a/frontend/search-app-widget-plugin/search.h b/frontend/search-app-widget-plugin/search.h new file mode 100644 index 0000000..166130d --- /dev/null +++ b/frontend/search-app-widget-plugin/search.h @@ -0,0 +1,56 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ +#ifndef SEARCH_H +#define SEARCH_H +#define signals Q_SIGNALS +#define slots Q_SLOTS + +#include "ukui/kappwidgetprovider.h" +#include "ukui/kappwidgetmanager.h" + +#undef signals +#undef slots + +#include "global-settings.h" +#include + +namespace UkuiSearch { +class AppWidgetPlugin : public AppWidget::KAppWidgetProvider + +{ + Q_OBJECT +public: + explicit AppWidgetPlugin(QString providername = "search", QObject *parent = nullptr); + void appWidgetRecevie(const QString &eventname, const QString &widgetname, const QDBusVariant &value); + void appWidgetUpdate(); + +Q_SIGNALS: + void startSearch(QString); + void start(); + +private: + QDBusInterface* m_interface = nullptr; + AppWidget::KAppWidgetManager* m_manager = nullptr; +}; +} + + + +#endif // SEARCH_H diff --git a/frontend/ukui-search-dbus-service.cpp b/frontend/ukui-search-dbus-service.cpp index 58d7110..f18958c 100644 --- a/frontend/ukui-search-dbus-service.cpp +++ b/frontend/ukui-search-dbus-service.cpp @@ -1,40 +1,195 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #include "ukui-search-dbus-service.h" +#include +#include +#include "serviceadaptor.h" using namespace UkuiSearch; -void UkuiSearchDbusServices::showWindow(){ - qDebug() << "showWindow called"; - m_mainWindow->bootOptionsFilter("-s"); +void UkuiSearchDbusServices::showWindow() +{ + QString display = checkDisplay(); + qDebug() << "showWindow called, from display:" << display << "current display: " << m_display; + if(!display.isEmpty() && display != m_display) { + Q_EMIT showWindowSignal(display); + return; + } + onShowWindow(m_display); } void UkuiSearchDbusServices::searchKeyword(QString keyword) { - showWindow(); - m_mainWindow->setText(keyword); + QString display = checkDisplay(); + qDebug() << "searchKeyword called, from display:" << display << "current display: " << m_display; + if(!display.isEmpty() && display != m_display) { + Q_EMIT searchKeywordSignal(display, keyword); + return; + } + onSearchKeyword(m_display, keyword); } void UkuiSearchDbusServices::mainWindowSwitch() { - if (m_mainWindow->isActiveWindow()) { - m_mainWindow->tryHide(); + QString display = checkDisplay(); + qDebug() << "mainWindowSwitch called, from display:" << display << "current display: " << m_display; + if(!display.isEmpty() && display != m_display) { + Q_EMIT mainWindowSwitchSignal(display); + return; + } + onMainWindowSwitch(m_display); +} + +UkuiSearchDbusServices::UkuiSearchDbusServices(MainWindow *m, QObject *parent): + QObject(parent), + m_mainWindow(m) +{ + m_mainWindow = m; + m_display = qApp->property("display").toString(); + //注册服务 + bool isServiceRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("com.ukui.search.service")); + if(isServiceRegistered) { + initWatcher(); } else { + if(!registerService()) { + initWatcher(); + } + } +} + +void UkuiSearchDbusServices::initWatcher() +{ + m_watcher = new QDBusServiceWatcher(QStringLiteral("com.ukui.search.service"),QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this); + connect(m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &UkuiSearchDbusServices::onServiceOwnerChanged); + connectToService(); +} + +bool UkuiSearchDbusServices::registerService() +{ + if(!m_adaptor) { + m_adaptor = new ServiceAdaptor(this); + } + QDBusConnection conn = QDBusConnection::sessionBus(); + auto reply = conn.interface()->registerService(QStringLiteral("com.ukui.search.service"), + QDBusConnectionInterface::ReplaceExistingService, + QDBusConnectionInterface::DontAllowReplacement); + if (reply.value() == QDBusConnectionInterface::ServiceNotRegistered) { + return false; + } + + bool res = QDBusConnection::sessionBus().registerObject("/", this); + if (!res) { + QDBusConnection::sessionBus().interface()->unregisterService(QStringLiteral("com.ukui.search.service")); + } + return res; +} + +void +UkuiSearchDbusServices::onServiceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner) +{ + if (newOwner.isEmpty()) { + bool success = registerService(); + if (success) { + disConnectToService(); + m_watcher->deleteLater(); + } + qDebug() << "try to register service:" << success; + return; + } + + uint newOwnerPid = QDBusConnection::sessionBus().interface()->servicePid(newOwner); + qDebug() << "newOwnerPid:" << newOwnerPid << ", myPid:" << QCoreApplication::applicationPid() << ", display:" << m_display; +} + +void UkuiSearchDbusServices::connectToService() +{ + m_serviceIface = new OrgUkuiSearchServiceInterface(QStringLiteral("com.ukui.search.service"), "/", QDBusConnection::sessionBus(), this); + connect(m_serviceIface, &OrgUkuiSearchServiceInterface::showWindowSignal, this, &UkuiSearchDbusServices::onShowWindow); + connect(m_serviceIface, &OrgUkuiSearchServiceInterface::searchKeywordSignal, this, &UkuiSearchDbusServices::onSearchKeyword); + connect(m_serviceIface, &OrgUkuiSearchServiceInterface::mainWindowSwitchSignal, this, &UkuiSearchDbusServices::onMainWindowSwitch); +} + +void UkuiSearchDbusServices::disConnectToService() +{ + if(m_serviceIface) { + m_serviceIface->disconnect(); + m_serviceIface->deleteLater(); + } +} + +void UkuiSearchDbusServices::onShowWindow(const QString &display) +{ + if(m_display == display) { m_mainWindow->bootOptionsFilter("-s"); } } -UkuiSearchDbusServices::UkuiSearchDbusServices(MainWindow *m) +void UkuiSearchDbusServices::onSearchKeyword(const QString &display, const QString &keyword) { - m_mainWindow = m; - //注册服务 - QDBusConnection sessionBus = QDBusConnection::sessionBus(); - QDBusConnection::sessionBus().unregisterService("com.ukui.search.service"); - if(!sessionBus.registerService("com.ukui.search.service")){ - qWarning() << "ukui-search dbus register service failed reason:" << sessionBus.lastError(); - } - - if(!sessionBus.registerObject("/", this, QDBusConnection::ExportAllSlots)){ - qWarning() << "ukui-search dbus register object failed reason:" << sessionBus.lastError(); + if(m_display == display) { + m_mainWindow->bootOptionsFilter("-s"); + m_mainWindow->setText(keyword); } } -UkuiSearchDbusServices::~UkuiSearchDbusServices(){ +void UkuiSearchDbusServices::onMainWindowSwitch(const QString &display) +{ + if(m_display == display) { + if (m_mainWindow->isActiveWindow()) { + m_mainWindow->tryHide(); + } else { + m_mainWindow->bootOptionsFilter("-s"); + } + } +} + +QString UkuiSearchDbusServices::checkDisplay() +{ + uint pid = 0; + QDBusReply pidReply = connection().interface()->servicePid(message().service()); + qDebug() << "caller pid: " << pidReply.value(); + if(pidReply.isValid()) { + pid = pidReply.value(); + } else { + return {}; + } + return UkuiSearchDbusServices::displayFromPid(pid);; +} + +QString UkuiSearchDbusServices::displayFromPid(uint pid) +{ + QFile environFile(QStringLiteral("/proc/%1/environ").arg(QString::number(pid))); + if (environFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + const QByteArray DISPLAY = qApp->property("sessionType").toString() == "wayland" ? QByteArrayLiteral("WAYLAND_DISPLAY") + : QByteArrayLiteral("DISPLAY"); + const auto lines = environFile.readAll().split('\0'); + for (const QByteArray &line : lines) { + const int equalsIdx = line.indexOf('='); + if (equalsIdx <= 0) { + continue; + } + const QByteArray key = line.left(equalsIdx); + if (key == DISPLAY) { + const QByteArray value = line.mid(equalsIdx + 1); + return value; + } + } + } + return {}; } diff --git a/frontend/ukui-search-dbus-service.h b/frontend/ukui-search-dbus-service.h index 58eb25d..35f2dff 100644 --- a/frontend/ukui-search-dbus-service.h +++ b/frontend/ukui-search-dbus-service.h @@ -1,29 +1,74 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef UKUISEARCHDBUSSERVICE_H #define UKUISEARCHDBUSSERVICE_H #include #include +#include #include "mainwindow.h" +#include "service_interface.h" +class ServiceAdaptor; namespace UkuiSearch { -class UkuiSearchDbusServices: public QObject{ +class UkuiSearchDbusServices: public QObject, public QDBusContext +{ Q_OBJECT - Q_CLASSINFO("D-Bus Interface","org.ukui.search.service") public: - explicit UkuiSearchDbusServices(MainWindow *m); - ~UkuiSearchDbusServices(); + explicit UkuiSearchDbusServices(MainWindow *m, QObject *parent = nullptr); public Q_SLOTS: void showWindow(); void searchKeyword(QString keyword); void mainWindowSwitch(); +Q_SIGNALS: + void showWindowSignal(const QString &display); + void searchKeywordSignal(const QString &display, QString keyword); + void mainWindowSwitchSignal(const QString &display); + +private Q_SLOTS: + void onShowWindow(const QString &display); + void onSearchKeyword(const QString &display, const QString &keyword); + void onMainWindowSwitch(const QString &display); + private: + void initWatcher(); + bool registerService(); + void onServiceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner); + void connectToService(); + void disConnectToService(); + QString checkDisplay(); + QString displayFromPid(uint pid); + MainWindow *m_mainWindow = nullptr; + QDBusServiceWatcher *m_watcher = nullptr; + QString m_display; + OrgUkuiSearchServiceInterface *m_serviceIface = nullptr; + ServiceAdaptor * m_adaptor = nullptr; + + }; } diff --git a/frontend/ukui-search-gui.cpp b/frontend/ukui-search-gui.cpp index 2f1482e..9cd0da3 100644 --- a/frontend/ukui-search-gui.cpp +++ b/frontend/ukui-search-gui.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "ukui-search-gui.h" #include #include @@ -5,13 +24,19 @@ #include #include #include "plugin-manager.h" -#include "search-plugin-manager.h" -#include "document.h" +#include "icon-loader.h" using namespace UkuiSearch; -UkuiSearchGui::UkuiSearchGui(int &argc, char *argv[], const QString &applicationName): QtSingleApplication (applicationName, argc, argv) +UkuiSearchGui::UkuiSearchGui(int &argc, + char *argv[], + const QString &display, + const QString &sessionType, + const QString &applicationName): + QtSingleApplication (applicationName + display, argc, argv) { - qDebug()<<"ukui search gui constructor start" << applicationName; + qDebug()<<"ukui search gui constructor start, session type:" << sessionType << "display:" << display; + qApp->setProperty("display", display); + qApp->setProperty("sessionType", sessionType); setApplicationVersion(QString("v%1").arg(VERSION)); if (!this->isRunning()) { connect(this, &QtSingleApplication::messageReceived, [=](QString msg) { @@ -20,17 +45,13 @@ UkuiSearchGui::UkuiSearchGui(int &argc, char *argv[], const QString &application setQuitOnLastWindowClosed(false); -// qRegisterMetaType>("QPair"); -// qRegisterMetaType("Document"); - - //load translations. QTranslator *translator = new QTranslator(this); try { - if(! translator->load("/usr/share/ukui-search/translations/" + QLocale::system().name())) throw - 1; + if(! translator->load(UKUI_SEARCH_QM_INSTALL_PATH"/" + QLocale::system().name())) throw - 1; this->installTranslator(translator); } catch(...) { - qDebug() << "Load translations file" << QLocale() << "failed!"; + qDebug() << "Load translations file: " << UKUI_SEARCH_QM_INSTALL_PATH << QLocale() << "failed!"; } QTranslator *qt_translator = new QTranslator(this); @@ -43,7 +64,7 @@ UkuiSearchGui::UkuiSearchGui(int &argc, char *argv[], const QString &application QTranslator *lib_translator = new QTranslator(this); try { - if(! lib_translator->load("/usr/share/ukui-search/translations/libukui-search_" + QLocale::system().name())) throw - 1; + if(! lib_translator->load("/usr/share/ukui-search/translations/libukui-search/libukui-search_" + QLocale::system().name())) throw - 1; this->installTranslator(lib_translator); } catch(...) { qDebug() << "Load translations file" << QLocale() << "failed!"; @@ -54,8 +75,8 @@ UkuiSearchGui::UkuiSearchGui(int &argc, char *argv[], const QString &application PluginManager::getInstance(); m_mainWindow = new UkuiSearch::MainWindow(); - m_dbusService = new UkuiSearch::UkuiSearchDbusServices(m_mainWindow); - qApp->setWindowIcon(QIcon::fromTheme("kylin-search")); + m_dbusService = new UkuiSearch::UkuiSearchDbusServices(m_mainWindow, this); + qApp->setWindowIcon(IconLoader::loadIconQt("kylin-search")); this->setActivationWindow(m_mainWindow); } diff --git a/frontend/ukui-search-gui.h b/frontend/ukui-search-gui.h index 652a88f..04dac42 100644 --- a/frontend/ukui-search-gui.h +++ b/frontend/ukui-search-gui.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef UKUISEARCHGUI_H #define UKUISEARCHGUI_H @@ -12,7 +31,7 @@ class UkuiSearchGui : public QtSingleApplication { Q_OBJECT public: - UkuiSearchGui(int &argc, char *argv[], const QString &applicationName = "ukui-search-gui"); + UkuiSearchGui(int &argc, char *argv[] , const QString &display, const QString &sessionType, const QString &applicationName = "ukui-search-gui"); ~UkuiSearchGui(); protected Q_SLOTS: diff --git a/frontend/view/best-list-view.cpp b/frontend/view/best-list-view.cpp index 4f6d56a..74178a8 100644 --- a/frontend/view/best-list-view.cpp +++ b/frontend/view/best-list-view.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #include "best-list-view.h" #define MAIN_MARGINS 0,0,0,0 #define MAIN_SPACING 0 @@ -148,21 +167,6 @@ const bool &BestListView::isExpanded() return m_model->isExpanded(); } -/** - * @brief BestListView::onMenuTriggered 点击右键菜单的槽函数 - * @param action - */ -void BestListView::onMenuTriggered(QAction *action) -{ - //NEW_TODO 接口调整后需要修改 -// SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_plugin_id); -// if (plugin) { -//// plugin->openAction(action->text(), m_model->getKey(this->currentIndex())); -// } else { -// qWarning()<<"Get plugin failed!"; -// } -} - void BestListView::mousePressEvent(QMouseEvent *event) { m_tmpCurrentIndex = this->currentIndex(); diff --git a/frontend/view/best-list-view.h b/frontend/view/best-list-view.h index 75c8a04..2acb63e 100644 --- a/frontend/view/best-list-view.h +++ b/frontend/view/best-list-view.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef BESTLISTVIEW_H #define BESTLISTVIEW_H #include @@ -34,7 +53,6 @@ public Q_SLOTS: void onItemListChanged(const int &); void setExpanded(const bool &); const bool &isExpanded(); - void onMenuTriggered(QAction *); protected: void mousePressEvent(QMouseEvent *event); diff --git a/frontend/view/result-view-delegate.cpp b/frontend/view/result-view-delegate.cpp index e5b8de3..25db800 100644 --- a/frontend/view/result-view-delegate.cpp +++ b/frontend/view/result-view-delegate.cpp @@ -1,5 +1,25 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #include "result-view-delegate.h" #include +#include using namespace UkuiSearch; static ResultItemStyle *global_instance_of_item_style = nullptr; diff --git a/frontend/view/result-view-delegate.h b/frontend/view/result-view-delegate.h index fb9eea4..ed915a8 100644 --- a/frontend/view/result-view-delegate.h +++ b/frontend/view/result-view-delegate.h @@ -30,7 +30,6 @@ #include #include #include -#include "global-settings.h" namespace UkuiSearch { class HightLightEffectHelper : public QSyntaxHighlighter diff --git a/frontend/view/result-view.cpp b/frontend/view/result-view.cpp index de1c567..889e544 100644 --- a/frontend/view/result-view.cpp +++ b/frontend/view/result-view.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #include "result-view.h" #define MAIN_MARGINS 0,0,0,0 #define MAIN_SPACING 0 @@ -306,6 +325,7 @@ const bool &ResultView::isExpanded() */ void ResultView::onMenuTriggered(QAction *action) { + Q_UNUSED(action) //NEW_TODO 接口调整后需要修改 SearchPluginIface *plugin = SearchPluginManager::getInstance()->getPlugin(m_plugin_id); if (plugin) { @@ -403,7 +423,7 @@ void ResultView::initConnections() m_styleDelegate->setSearchKeyword(keyword); m_model->startSearch(keyword); }); - connect(this, &ResultView::stopSearch, m_model, &SearchResultModel::stopSearch); + connect(this, &ResultView::stopSearch, m_model, &SearchResultModel::stopSearchSlot); //connect(this->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ResultView::onRowSelectedSlot); connect(this, &ResultView::clicked, this, &ResultView::onRowSelectedSlot); connect(this, &ResultView::activated, this, &ResultView::onRowDoubleClickedSlot); diff --git a/frontend/view/result-view.h b/frontend/view/result-view.h index dd9a3f2..15df034 100644 --- a/frontend/view/result-view.h +++ b/frontend/view/result-view.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef RESULTVIEW_H #define RESULTVIEW_H #include diff --git a/frontend/view/view.pri b/frontend/view/view.pri deleted file mode 100644 index 04b29eb..0000000 --- a/frontend/view/view.pri +++ /dev/null @@ -1,13 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/best-list-view.h \ - $$PWD/result-view-delegate.h \ - $$PWD/result-view.h \ - $$PWD/web-search-view.h - -SOURCES += \ - $$PWD/best-list-view.cpp \ - $$PWD/result-view-delegate.cpp \ - $$PWD/result-view.cpp \ - $$PWD/web-search-view.cpp diff --git a/frontend/view/web-search-view.cpp b/frontend/view/web-search-view.cpp deleted file mode 100644 index 1bae643..0000000 --- a/frontend/view/web-search-view.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * - * Copyright (C) 2021, KylinSoft Co., Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Authors: jixiaoxu - * - */ -#include -#include "web-search-view.h" -#define MAIN_MARGINS 0,0,0,0 -#define MAIN_SPACING 0 -#define TITLE_HEIGHT 30 -#define VIEW_ICON_SIZE 24 - -using namespace UkuiSearch; -WebSearchView::WebSearchView(QWidget *parent) : QTreeView(parent) -{ - setStyle(ResultItemStyle::getStyle()); - this->setFrameShape(QFrame::NoFrame); - this->viewport()->setAutoFillBackground(false); - this->setRootIsDecorated(false); - this->setIconSize(QSize(VIEW_ICON_SIZE, VIEW_ICON_SIZE)); - this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - this->setSelectionBehavior(QAbstractItemView::SelectRows); - this->setSelectionMode(QAbstractItemView::SingleSelection); - this->setHeaderHidden(true); - m_model = new WebSearchModel(this); - this->setModel(m_model); - m_styleDelegate = new ResultViewDelegate(this); - this->setItemDelegate(m_styleDelegate); -} - -bool WebSearchView::isSelected() -{ - return m_is_selected; -} - -int WebSearchView::showHeight() -{ - return this->rowHeight(this->model()->index(0, 0, QModelIndex())); -} - -QModelIndex WebSearchView::getModlIndex(int row, int column) -{ - return this->m_model->index(row, column); -} - -void WebSearchView::clearSelectedRow() -{ - if (!m_is_selected) { - this->blockSignals(true); - //this->clearSelection(); - this->setCurrentIndex(QModelIndex()); - this->blockSignals(false); - } -} - -void WebSearchView::startSearch(const QString & keyword) -{ - this->m_styleDelegate->setSearchKeyword(keyword); - this->m_model->startSearch(keyword); - m_keyWord = keyword; -} - -void WebSearchView::mouseReleaseEvent(QMouseEvent *event) -{ - QModelIndex index = indexAt(event->pos()); - if (!index.isValid()) { - this->clearSelection(); - } - return QTreeView::mouseReleaseEvent(event); -} - -void WebSearchView::LaunchBrowser() -{ - QString address; - QString engine = GlobalSettings::getInstance()->getValue("web_engine").toString(); - if(!engine.isEmpty()) { - if(engine == "360") { - address = "https://so.com/s?q=" + m_keyWord; //360 - } else if(engine == "sougou") { - address = "https://www.sogou.com/web?query=" + m_keyWord; //搜狗 - } else { - address = "http://baidu.com/s?word=" + m_keyWord; //百度 - } - } else { //默认值 - address = "http://baidu.com/s?word=" + m_keyWord ; //百度 - } - bool res(false); - QDBusInterface * appLaunchInterface = new QDBusInterface("com.kylin.AppManager", - "/com/kylin/AppManager", - "com.kylin.AppManager", - QDBusConnection::sessionBus()); - if(!appLaunchInterface->isValid()) { - qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message()); - res = false; - } else { - appLaunchInterface->setTimeout(10000); - QDBusReply reply = appLaunchInterface->call("LaunchDefaultAppWithUrl", address); - if(reply.isValid()) { - res = reply; - } else { - qWarning() << "SoftWareCenter dbus called failed!"; - res = false; - } - } - if(appLaunchInterface) { - delete appLaunchInterface; - } - appLaunchInterface = NULL; - if (res) - return; - QDesktopServices::openUrl(address); -} - -void WebSearchView::initConnections() -{ - -} - -WebSearchWidget::WebSearchWidget(QWidget *parent) : QWidget(parent) -{ - this->initUi(); - initConnections(); -} - -QString WebSearchWidget::getWidgetName() -{ - return m_titleLabel->text(); -} - -void WebSearchWidget::setEnabled(const bool &enabled) -{ - m_enabled = enabled; -} - -void WebSearchWidget::clearResultSelection() -{ - this->m_webSearchView->setCurrentIndex(QModelIndex()); -} - -QModelIndex WebSearchWidget::getModlIndex(int row, int column) -{ - return this->m_webSearchView->getModlIndex(row, column); -} - -void WebSearchWidget::setResultSelection(const QModelIndex &index) -{ - this->m_webSearchView->setCurrentIndex(index); -} - -void WebSearchWidget::LaunchBrowser() -{ - this->m_webSearchView->LaunchBrowser(); -} - -void WebSearchWidget::initUi() -{ - m_mainLyt = new QVBoxLayout(this); - this->setLayout(m_mainLyt); - m_mainLyt->setContentsMargins(MAIN_MARGINS); - m_mainLyt->setSpacing(MAIN_SPACING); - - m_titleLabel = new TitleLabel(this); - m_titleLabel->setText(tr("Web Page")); - m_titleLabel->setFixedHeight(TITLE_HEIGHT); - - m_webSearchView = new WebSearchView(this); - - m_mainLyt->addWidget(m_titleLabel); - m_mainLyt->addWidget(m_webSearchView); - this->setFixedHeight(m_webSearchView->height() + TITLE_HEIGHT); - this->setFixedWidth(656); -} - -void WebSearchWidget::initConnections() -{ - connect(this, &WebSearchWidget::startSearch, m_webSearchView, &WebSearchView::startSearch); - connect(m_webSearchView, &WebSearchView::clicked, this, [=] () { - this->LaunchBrowser(); - }); -} diff --git a/frontend/view/web-search-view.h b/frontend/view/web-search-view.h deleted file mode 100644 index ffd73e0..0000000 --- a/frontend/view/web-search-view.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef WEBSEARCHVIEW_H -#define WEBSEARCHVIEW_H -#include -#include -#include -#include "web-search-model.h" -#include "result-view-delegate.h" -#include "title-label.h" - -namespace UkuiSearch { -class WebSearchView : public QTreeView -{ - Q_OBJECT -public: - WebSearchView(QWidget *parent = nullptr); - ~WebSearchView() = default; - - bool isSelected(); - int showHeight(); - QModelIndex getModlIndex(int row, int column); - void LaunchBrowser(); - -public Q_SLOTS: - void clearSelectedRow(); - void startSearch(const QString &); - -protected: - void mouseReleaseEvent(QMouseEvent *event); - -private: - void initConnections(); - - WebSearchModel * m_model = nullptr; - bool m_is_selected = false; - ResultViewDelegate * m_styleDelegate = nullptr; - QString m_keyWord; -}; - -class WebSearchWidget : public QWidget -{ - Q_OBJECT -public: - WebSearchWidget(QWidget *parent = nullptr); - ~WebSearchWidget() = default; - - QString getWidgetName(); - void setEnabled(const bool&); - void clearResultSelection(); - QModelIndex getModlIndex(int row, int column); - void setResultSelection(const QModelIndex &index); - void LaunchBrowser(); - -private: - void initUi(); - void initConnections(); - - bool m_enabled = true; - QVBoxLayout * m_mainLyt = nullptr; - QHBoxLayout * m_resultLyt = nullptr; - TitleLabel * m_titleLabel = nullptr; - WebSearchView * m_webSearchView = nullptr; - QLabel * m_queryIcon = nullptr; - -Q_SIGNALS: - void startSearch(const QString &); - void clearSelectedRow(); - void rowClicked(); - -}; - -} -#endif // WEBSEARCHVIEW_H diff --git a/frontend/xatom/xatom.pri b/frontend/xatom/xatom.pri deleted file mode 100644 index 2d5b140..0000000 --- a/frontend/xatom/xatom.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/xatom-helper.h \ - -SOURCES += \ - $$PWD/xatom-helper.cpp \ diff --git a/libchinese-segmentation/CMakeLists.txt b/libchinese-segmentation/CMakeLists.txt new file mode 100644 index 0000000..28312be --- /dev/null +++ b/libchinese-segmentation/CMakeLists.txt @@ -0,0 +1,170 @@ +cmake_minimum_required(VERSION 3.14) +project(chinese-segmentation LANGUAGES CXX) + +set(VERSION_MAJOR 1) +set(VERSION_MINOR 1) +set(VERSION_MICRO 0) +set(CHINESE_SEGMENTATION_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) + +set(HEADERS + chinese-segmentation.h + common-struct.h + hanzi-to-pinyin.h + Traditional-to-Simplified.h + pinyin4cpp-common.h + libchinese-segmentation_global.h) + +set(CHINESE_SEGMENTATION_SRC + Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.cpp + Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.h + Traditional-to-Simplified.cpp + Traditional-to-Simplified-private.h + chinese-segmentation.cpp + chinese-segmentation-private.h + cppjieba/DatTrie.hpp + cppjieba/DictTrie.hpp + cppjieba/FullSegment.hpp + cppjieba/HMMModel.hpp + cppjieba/HMMSegment.hpp + cppjieba/IdfTrie.hpp + cppjieba/Jieba.hpp + cppjieba/KeywordExtractor.hpp + cppjieba/MPSegment.hpp + cppjieba/MixSegment.hpp + cppjieba/PinYinTrie.hpp + cppjieba/PosTagger.hpp + cppjieba/PreFilter.hpp + cppjieba/QuerySegment.hpp + cppjieba/SegmentBase.hpp + cppjieba/SegmentTagged.hpp + cppjieba/TextRankExtractor.hpp + cppjieba/Unicode.hpp + cppjieba/idf-trie/idf-trie.cpp cppjieba/idf-trie/idf-trie.h + cppjieba/limonp/ArgvContext.hpp + cppjieba/limonp/BlockingQueue.hpp + cppjieba/limonp/BoundedBlockingQueue.hpp + cppjieba/limonp/BoundedQueue.hpp + cppjieba/limonp/Closure.hpp + cppjieba/limonp/Colors.hpp + cppjieba/limonp/Condition.hpp + cppjieba/limonp/Config.hpp + cppjieba/limonp/FileLock.hpp + cppjieba/limonp/ForcePublic.hpp + cppjieba/limonp/LocalVector.hpp + cppjieba/limonp/Logging.hpp + cppjieba/limonp/Md5.hpp + cppjieba/limonp/MutexLock.hpp + cppjieba/limonp/NonCopyable.hpp + cppjieba/limonp/StdExtension.hpp + cppjieba/limonp/StringUtil.hpp + cppjieba/limonp/Thread.hpp + cppjieba/limonp/ThreadPool.hpp + cppjieba/segment-trie/segment-trie.cpp + cppjieba/segment-trie/segment-trie.h + hanzi-to-pinyin.cpp + hanzi-to-pinyin-private.h + pinyin4cpp/pinyin4cpp-trie.cpp + pinyin4cpp/pinyin4cpp-trie.h + pinyin4cpp/pinyin4cpp_dataTrie.cpp + pinyin4cpp/pinyin4cpp_dataTrie.h + pinyin4cpp/pinyin4cpp_dictTrie.cpp + pinyin4cpp/pinyin4cpp_dictTrie.h + storage-base/cedar/cedar.h + storage-base/cedar/cedarpp.h + storage-base/darts-clone/darts.h + storage-base/storage-base.cpp + storage-base/storage-base.h + storage-base/storage-base.hpp) + +add_library(chinese-segmentation SHARED + ${CHINESE_SEGMENTATION_SRC} + ${HEADERS} + ) + +include_directories(chinese-segmentation + storage-base/cedar + storage-base + cppjieba + cppjieba/limonp + pinyin4cpp + Traditional-Chinese-Simplified-conversion + ) + +target_link_libraries(chinese-segmentation PUBLIC + Qt${QT_VERSION_MAJOR}::Core +) + +include(CMakePackageConfigHelpers) +set(CMAKE_CONFIG_INSTALL_DIR "/usr/share/cmake/chinese-segmentation") +set(HEADERS_INSTALL_DIR "/usr/include/chinese-segmentation") +set(PC_INSTALL_DIR "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig") +set(DICT_INSTALL_PATH "/usr/share/chinese-segmentation/res/dict") +add_compile_definitions( + VERSION="${CHINESE_SEGMENTATION_VERSION}" + DICT_INSTALL_PATH="${DICT_INSTALL_PATH}" +) +target_include_directories(chinese-segmentation PUBLIC $) + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/chinese-segmentation-config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/chinese-segmentation-config.cmake" + INSTALL_DESTINATION ${CMAKE_CONFIG_INSTALL_DIR}) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/chinese-segmentation-config-version.cmake + VERSION ${CHINESE_SEGMENTATION_VERSION} + COMPATIBILITY SameMajorVersion +) + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/chinese-segmentation.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/chinese-segmentation.pc" + INSTALL_DESTINATION ${PC_INSTALL_DIR}) + +set_target_properties(chinese-segmentation PROPERTIES + VERSION ${CHINESE_SEGMENTATION_VERSION} + SOVERSION ${VERSION_MAJOR} + OUTPUT_NAME chinese-segmentation + ) +install(TARGETS chinese-segmentation + EXPORT chinese-segmentation + PUBLIC_HEADER DESTINATION ${HEADERS_INSTALL_DIR} + LIBRARY DESTINATION /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} + ) +install(EXPORT chinese-segmentation + FILE chinese-segmentation-targets.cmake + DESTINATION ${CMAKE_CONFIG_INSTALL_DIR}) +install(FILES ${HEADERS} DESTINATION ${HEADERS_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/chinese-segmentation.pc DESTINATION ${PC_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/chinese-segmentation-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/chinese-segmentation-config-version.cmake + DESTINATION ${CMAKE_CONFIG_INSTALL_DIR}) +set(DICT_FILES + dict/hmm_model.utf8 + dict/idf.utf8 + dict/jieba.dict.utf8 + dict/stop_words.utf8 + dict/user.dict.utf8 + dict/pinyinWithoutTone.txt + dict/pos_dict/char_state_tab.utf8 + dict/pos_dict/prob_emit.utf8 + dict/pos_dict/prob_start.utf8 + dict/pos_dict/prob_trans.utf8 + pinyin4cpp/dict/singleWordPinyin.txt + pinyin4cpp/dict/wordsPinyin.txt + Traditional-Chinese-Simplified-conversion/dict/TraditionalChineseSimplifiedDict.txt + ) +install(FILES ${DICT_FILES} DESTINATION ${DICT_INSTALL_PATH}) + +if (BUILD_TEST) + add_subdirectory(test) +endif () + + + diff --git a/libchinese-segmentation/README.md b/libchinese-segmentation/README.md new file mode 100644 index 0000000..aaf1ba5 --- /dev/null +++ b/libchinese-segmentation/README.md @@ -0,0 +1,170 @@ +# chinese-segmentation + +#### 介绍 +libchinese-segmentation工程以单例的形式分别提供了中文分词、汉字转拼音和中文繁体简体转换功能。 + +接口文件分别为: +chinese-segmentation.h +libchinese-segmentation_global.h +common-struct.h + +hanzi-to-pinyin.h +pinyin4cpp-common.h + +Traditional-to-Simplified.h +安装路径:/usr/include/chinese-seg + +#### 使用说明 + +其中中文分词相关功能由chinese-segmentation.h提供接口,主要包括以下功能函数: + +``` + static ChineseSegmentation *getInstance();//全局单例 + /** + * @brief ChineseSegmentation::callSegment + * 调用extractor进行关键词提取,先使用Mix方式初步分词,再使用Idf词典进行关键词提取,只包含两字以上关键词 + * + * @param sentence 要提取关键词的句子 + * @return vector 存放提取后关键词的信息的容器 + */ + vector callSegment(const string &sentence); + vector callSegment(QString &sentence); + + /** + * @brief ChineseSegmentation::callMixSegmentCutStr + * 使用Mix方法进行分词,即先使用最大概率法MP初步分词,再用隐式马尔科夫模型HMM进一步分词,可以准确切出词典已有词和未登录词,结果比较准确 + * + * @param sentence 要分词的句子 + * @return vector 只存放分词后每个词的内容的容器 + */ + vector callMixSegmentCutStr(const string& sentence); + + /** + * @brief ChineseSegmentation::callMixSegmentCutWord + * 和callMixSegmentCutStr功能相同 + * @param sentence 要分词的句子 + * @return vector 存放分词后每个词所有信息的容器 + */ + vector callMixSegmentCutWord(const string& str); + + /** + * @brief ChineseSegmentation::lookUpTagOfWord + * 查询word的词性 + * @param word 要查询词性的词 + * @return string word的词性 + */ + string lookUpTagOfWord(const string& word); + + /** + * @brief ChineseSegmentation::getTagOfWordsInSentence + * 使用Mix分词后获取每个词的词性 + * @param sentence 要分词的句子 + * @return vector> 分词后的每个词的内容(firsr)和其对应的词性(second) + */ + vector> getTagOfWordsInSentence(const string &sentence); + + /** + * @brief ChineseSegmentation::callFullSegment + * 使用Full进行分词,Full会切出字典里所有的词。 + * @param sentence 要分词的句子 + * @return vector 存放分词后每个词所有信息的容器 + */ + vector callFullSegment(const string& sentence); + + /** + * @brief ChineseSegmentation::callQuerySegment + * 使用Query进行分词,即先使用Mix,对于长词再用Full,结果最精确,但词的数量也最大 + * @param sentence 要分词的句子 + * @return vector 存放分词后每个词所有信息的容器 + */ + vector callQuerySegment(const string& sentence); + + /** + * @brief ChineseSegmentation::callHMMSegment + * 使用隐式马尔科夫模型HMM进行分词 + * @param sentence 要分词的句子 + * @return vector 存放分词后每个词所有信息的容器 + */ + vector callHMMSegment(const string& sentence); + + /** + * @brief ChineseSegmentation::callMPSegment + * 使用最大概率法MP进行分词 + * @param sentence 要分词的句子 + * @return vector 存放分词后每个词所有信息的容器 + */ + vector callMPSegment(const string& sentence); + +``` + +汉字转拼音相关功能由hanzi-to-pinyin.h提供接口,主要包括以下功能函数: + +``` + static HanZiToPinYin * getInstance();//全局单例 + + /** + * @brief HanZiToPinYin::isMultiTone 判断是否为多音字/词/句 + * @param word 要判断的字/词/句 + * @return bool 不是返回false + */ + bool isMultiTone(string &word); + bool isMultiTone(string &&word); + bool isMultiTone(const string &word); + bool isMultiTone(const string &&word); + + /** + * @brief HanZiToPinYin::contains 查询某个字/词/句是否有拼音(是否在数据库包含) + * @param word 要查询的字/词/句 + * @return bool 数据库不包含返回false + */ + bool contains(string &word); + + /** + * @brief HanZiToPinYin::getResults 获取某个字/词/句的拼音 + * @param word 要获取拼音的字/词/句 + * @param results word的拼音列表(有可能多音字),每次调用results会被清空 + * @return int 获取到返回0,否则返回-1 + */ + int getResults(string word, QStringList &results); + + /** + * @brief setConfig 设置HanZiToPinYin的各项功能,详见pinyin4cpp-common.h + * @param dataStyle 返回数据风格,默认defult + * @param segType 是否启用分词,默认启用 + * @param polyphoneType 是否启用多音字,默认不启用 + * @param processType 无拼音数据处理模式,默认defult + */ + void setConfig(PinyinDataStyle dataStyle,SegType segType,PolyphoneType polyphoneType,ExDataProcessType processType); + +``` + +中文繁体转简体相关功能由Traditional-to-Simplified.h提供接口,主要包括以下功能函数: + +``` + static Traditional2Simplified * getInstance();//全局单例 + /** + * @brief Traditional2Simplified::isMultiTone 判断是否为繁体字,是则返回true + * @param oneWord 要判断的字 + * @return bool 不是返回false + */ + bool isTraditional(string &oneWord); + + /** + * @brief Traditional2Simplified::getResults 转换某个字/词/句的繁体字 + * @param words 要转换为简体中文的字/词/句 + * @return words 的简体中文结果 + */ + string getResults(string words); + +``` + +除此之外工程中提供了测试程序位于chinese-segmentation/test,运行界面如下: +![输入图片说明](https://foruda.gitee.com/images/1682048388802220746/245a2ec3_8021248.png "image.png") + +#### 参与贡献 + +1. Fork 本仓库 +2. 新建分支 +3. 提交代码 +4. 新建 Pull Request + diff --git a/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified.pri b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified.pri new file mode 100644 index 0000000..8d93f87 --- /dev/null +++ b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified.pri @@ -0,0 +1,10 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/Traditional2Simplified_trie.h + +SOURCES += \ + $$PWD/Traditional2Simplified_trie.cpp + +DISTFILES += \ + Traditional-Chinese-Simplified-conversion/dict/TraditionalChineseSimplifiedDict.txt diff --git a/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.cpp b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.cpp new file mode 100644 index 0000000..a277c18 --- /dev/null +++ b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: jixiaoxu + * + */ +#include "Traditional2Simplified_trie.h" + +Traditional2SimplifiedTrie::Traditional2SimplifiedTrie(string dat_cache_path) + : StorageBase(vector{TRADITIONAL_CHINESE_SIMPLIFIED_DICT_PATH}, dat_cache_path) +{ + this->Init(); +} + +Traditional2SimplifiedTrie::Traditional2SimplifiedTrie(const vector file_paths, string dat_cache_path) + : StorageBase(file_paths, dat_cache_path) +{ + this->Init(); +} + +bool Traditional2SimplifiedTrie::IsTraditional(const string &word) { + string result = this->Find(word); + if (!result.empty()) + return true; + return false; +} + +void Traditional2SimplifiedTrie::LoadSourceFile(const string &dat_cache_file, const string &md5) +{ + CacheFileHeaderBase header; + assert(sizeof(header.md5_hex) == md5.size()); + memcpy(&header.md5_hex[0], md5.c_str(), md5.size()); + + int offset(0), elements_num(0), write_bytes(0), data_trie_size(0); + string tmp_filepath = string(dat_cache_file) + "_XXXXXX"; + umask(S_IWGRP | S_IWOTH); + const int fd =mkstemp((char *)tmp_filepath.data()); + assert(fd >= 0); + fchmod(fd, 0644); + + write_bytes = write(fd, (const char *)&header, sizeof(CacheFileHeaderBase)); + + this->LoadDict(fd, write_bytes, offset, elements_num); + + write_bytes += write(fd, this->GetDataTrieArray(), this->GetDataTrieTotalSize()); + + lseek(fd, sizeof(header.md5_hex), SEEK_SET); + write(fd, &elements_num, sizeof(int)); + write(fd, &offset, sizeof(int)); + data_trie_size = this->GetDataTrieSize(); + write(fd, &data_trie_size, sizeof(int)); + + close(fd); + assert((size_t)write_bytes == sizeof(CacheFileHeaderBase) + offset + this->GetDataTrieTotalSize()); + + tryRename(tmp_filepath, dat_cache_file); +} + +string Traditional2SimplifiedTrie::Find(const string &key) +{ + int result = this->ExactMatchSearch(key.c_str(), key.size()); + if (result < 0) + return string(); + return string(&this->GetElementPtr()[result]); +} + +void Traditional2SimplifiedTrie::LoadDict(const int &fd, int &write_bytes, int &offset, int &elements_num) +{ + ifstream ifs(TRADITIONAL_CHINESE_SIMPLIFIED_DICT_PATH); + string line; + vector buf; + + for (; getline(ifs, line);) { + if (limonp::StartsWith(line, "#") or line.empty()) { + continue; + } + limonp::Split(line, buf, ":"); + if (buf.size() != 2) + continue; + this->Update(buf[0].c_str(), buf[0].size(), offset); + offset += (buf[1].size() + 1); + elements_num++; + write_bytes += write(fd, buf[1].c_str(), buf[1].size() + 1); + } +} diff --git a/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.h b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.h new file mode 100644 index 0000000..c4a46e1 --- /dev/null +++ b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/Traditional2Simplified_trie.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: jixiaoxu + * + */ +#ifndef Traditional2SimplifiedTrie_H +#define Traditional2SimplifiedTrie_H + +#include "storage-base.hpp" + +const char * const TRADITIONAL_CHINESE_SIMPLIFIED_DICT_PATH = DICT_INSTALL_PATH"/TraditionalChineseSimplifiedDict.txt"; + +class Traditional2SimplifiedTrie : public StorageBase +{ +public: + Traditional2SimplifiedTrie(string dat_cache_path = ""); + Traditional2SimplifiedTrie(const vector file_paths, string dat_cache_path = ""); + void LoadSourceFile(const string &dat_cache_file, const string &md5) override; + string Find(const string &key); + bool IsTraditional(const string &word); + +private: + void LoadDict(const int &fd, int &write_bytes, int &offset, int &elements_num); +}; + +#endif // Traditional2SimplifiedTrie_H diff --git a/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/dict/TraditionalChineseSimplifiedDict.txt b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/dict/TraditionalChineseSimplifiedDict.txt new file mode 100644 index 0000000..4f9fd32 --- /dev/null +++ b/libchinese-segmentation/Traditional-Chinese-Simplified-conversion/dict/TraditionalChineseSimplifiedDict.txt @@ -0,0 +1,3001 @@ +丟:丢 +並:并 +么:幺 +乗:乘 +乾:干 +亂:乱 +亙:亘 +亜:亚 +亞:亚 +仝:同 +佇:伫 +佈:布 +併:并 +來:来 +侖:仑 +価:价 +侶:侣 +俁:俣 +係:系 +俔:伣 +俠:侠 +俥:伡 +倀:伥 +倂:併 +倆:俩 +倈:俫 +倉:仓 +個:个 +們:们 +倖:幸 +倫:伦 +倹:俭 +偉:伟 +側:侧 +偵:侦 +偸:偷 +偽:伪 +傑:杰 +傖:伧 +傘:伞 +備:备 +傢:家 +傭:佣 +傳:传 +傴:伛 +債:债 +傷:伤 +傾:倾 +僂:偻 +僅:仅 +僉:佥 +僑:侨 +僕:仆 +僞:伪 +僥:侥 +僨:偾 +僱:雇 +價:价 +儀:仪 +儂:侬 +億:亿 +儈:侩 +儉:俭 +儍:傻 +儎:傤 +儐:傧 +儔:俦 +儕:侪 +儘:尽 +償:偿 +優:优 +儲:储 +儷:俪 +儺:傩 +儻:傥 +儼:俨 +兇:凶 +兊:兑 +兌:兑 +兎:兔 +兒:儿 +內:内 +兩:两 +兪:俞 +兿:艺 +円:圆 +冊:册 +冪:幂 +凈:净 +凍:冻 +凜:凛 +処:处 +凱:凯 +別:别 +刦:劫 +刧:劫 +刪:删 +刴:剁 +刼:劫 +剄:刭 +則:则 +剋:克 +剎:刹 +剗:刬 +剛:刚 +剝:剥 +剣:剑 +剤:剂 +剮:剐 +剰:剩 +剱:剑 +剴:剀 +創:创 +劃:划 +劇:剧 +劉:刘 +劊:刽 +劌:刿 +劍:剑 +劎:剑 +劑:剂 +劒:剑 +劔:剑 +労:劳 +勁:劲 +動:动 +務:务 +勛:勋 +勝:胜 +勞:劳 +勢:势 +勧:劝 +勩:勚 +勱:劢 +勵:励 +勸:劝 +勻:匀 +匭:匦 +匯:汇 +匱:匮 +區:区 +協:协 +卻:却 +卽:即 +厙:厍 +厛:厅 +厭:厌 +厲:厉 +厳:严 +厴:厣 +參:参 +叄:叁 +叢:丛 +吒:咤 +吳:吴 +吶:呐 +呂:吕 +呉:吴 +呑:吞 +咼:呙 +員:员 +唄:呗 +唖:哑 +唸:念 +問:问 +啓:启 +啞:哑 +啟:启 +啢:唡 +喆:哲 +喎:㖞 +喚:唤 +喞:唧 +喪:丧 +喬:乔 +單:单 +喲:哟 +営:营 +嗆:呛 +嗇:啬 +嗊:唝 +嗎:吗 +嗚:呜 +嗩:唢 +嗶:哔 +嘆:叹 +嘍:喽 +嘓:啯 +嘔:呕 +嘖:啧 +嘗:尝 +嘜:唛 +嘨:啸 +嘩:哗 +嘮:唠 +嘯:啸 +嘰:叽 +嘵:哓 +嘸:呒 +嘽:啴 +噁:恶 +噓:嘘 +噛:啮 +噝:咝 +噠:哒 +噥:哝 +噦:哕 +噯:嗳 +噲:哙 +噴:喷 +噸:吨 +噹:当 +嚀:咛 +嚇:吓 +嚌:哜 +嚐:尝 +嚔:嚏 +嚕:噜 +嚙:啮 +嚥:咽 +嚦:呖 +嚨:咙 +嚮:向 +嚲:亸 +嚳:喾 +嚴:严 +嚶:嘤 +囀:啭 +囁:嗫 +囂:嚣 +囅:冁 +囈:呓 +囉:啰 +囌:苏 +囑:嘱 +囓:啮 +囘:回 +囬:回 +囲:围 +図:图 +圇:囵 +國:国 +圍:围 +圏:圈 +園:园 +圓:圆 +圖:图 +團:团 +圧:压 +垜:垛 +垻:坝 +埡:垭 +執:执 +堃:昆 +堅:坚 +堊:垩 +堖:垴 +堝:埚 +堯:尧 +報:报 +場:场 +塊:块 +塋:茔 +塏:垲 +塒:埘 +塗:涂 +塡:填 +塢:坞 +塤:埙 +塩:盐 +塲:场 +塵:尘 +塹:堑 +墊:垫 +増:增 +墜:坠 +墮:堕 +墳:坟 +墻:墙 +墾:垦 +壇:坛 +壊:坏 +壋:垱 +壓:压 +壘:垒 +壙:圹 +壚:垆 +壜:坛 +壞:坏 +壟:垄 +壠:垅 +壢:坜 +壩:坝 +壯:壮 +売:卖 +壷:壶 +壺:壶 +壼:壸 +壽:寿 +変:变 +夠:够 +夢:梦 +夥:伙 +夾:夹 +奐:奂 +奧:奥 +奨:奖 +奩:奁 +奪:夺 +奮:奋 +妝:妆 +妳:你 +姍:姗 +姦:奸 +娛:娱 +娯:娱 +婁:娄 +婦:妇 +婭:娅 +媧:娲 +媯:妫 +媼:媪 +媽:妈 +嫗:妪 +嫵:妩 +嫺:娴 +嫻:娴 +嫿:婳 +嬀:妫 +嬃:媭 +嬈:娆 +嬋:婵 +嬌:娇 +嬙:嫱 +嬡:嫒 +嬢:娘 +嬤:嬷 +嬪:嫔 +嬰:婴 +嬸:婶 +孃:娘 +孌:娈 +孫:孙 +孶:孳 +學:学 +孿:孪 +実:实 +宮:宫 +寛:宽 +寜:宁 +寢:寝 +實:实 +寧:宁 +審:审 +寫:写 +寬:宽 +寳:宝 +寵:宠 +寶:宝 +対:对 +専:专 +將:将 +專:专 +尋:寻 +對:对 +導:导 +尙:尚 +尭:尧 +尶:尴 +尷:尴 +屆:届 +屍:尸 +屓:屃 +屛:屏 +屜:屉 +屢:屡 +層:层 +屨:屦 +屬:属 +屭:屃 +岡:冈 +峩:峨 +峴:岘 +島:岛 +峽:峡 +崍:崃 +崑:昆 +崗:岗 +崙:仑 +崢:峥 +崬:岽 +嵐:岚 +嶁:嵝 +嶄:崭 +嶇:岖 +嶔:嵚 +嶗:崂 +嶠:峤 +嶢:峣 +嶧:峄 +嶨:峃 +嶮:崄 +嶲:隽 +嶸:嵘 +嶺:岭 +嶼:屿 +嶽:岳 +巋:岿 +巌:岩 +巒:峦 +巔:巅 +巣:巢 +巰:巯 +巻:卷 +帥:帅 +師:师 +帲:帡 +帳:帐 +帶:带 +幀:帧 +幃:帏 +幇:帮 +幗:帼 +幘:帻 +幟:帜 +幣:币 +幫:帮 +幬:帱 +幹:干 +幾:几 +庁:厅 +広:广 +庫:库 +廁:厕 +廂:厢 +廃:废 +廄:厩 +廈:厦 +廎:庼 +廚:厨 +廝:厮 +廟:庙 +廠:厂 +廡:庑 +廢:废 +廣:广 +廩:廪 +廬:庐 +廰:厅 +廳:厅 +廼:乃 +廽:廻 +弒:弑 +弔:吊 +弳:弪 +張:张 +強:强 +弾:弹 +彆:别 +彈:弹 +彌:弥 +彎:弯 +彔:录 +彙:汇 +彜:彛 +彞:彝 +彠:彟 +彥:彦 +彫:雕 +彲:彨 +彷:仿 +後:后 +徑:径 +従:从 +從:从 +徠:徕 +復:复 +徳:德 +徵:征 +徹:彻 +応:应 +恆:恒 +恥:耻 +恵:惠 +悅:悦 +悞:悮 +悩:恼 +悪:恶 +悵:怅 +悶:闷 +惡:恶 +惱:恼 +惲:恽 +惻:恻 +愛:爱 +愜:惬 +愴:怆 +愷:恺 +愼:慎 +愾:忾 +慂:恿 +慄:栗 +態:态 +慍:愠 +慘:惨 +慚:惭 +慟:恸 +慣:惯 +慤:悫 +慪:怄 +慫:怂 +慮:虑 +慳:悭 +慶:庆 +慺:㥪 +慾:欲 +憂:忧 +憊:惫 +憐:怜 +憑:凭 +憒:愦 +憖:慭 +憚:惮 +憤:愤 +憫:悯 +憮:怃 +憲:宪 +憶:忆 +懇:恳 +應:应 +懌:怿 +懍:懔 +懐:怀 +懟:怼 +懣:懑 +懨:恹 +懲:惩 +懶:懒 +懷:怀 +懸:悬 +懺:忏 +懼:惧 +懾:慑 +戀:恋 +戇:戆 +戔:戋 +戦:战 +戧:戗 +戩:戬 +戰:战 +戱:戯 +戲:戏 +戶:户 +払:拂 +択:择 +拋:抛 +拝:拜 +拡:扩 +挅:挆 +挩:捝 +挾:挟 +捨:舍 +捫:扪 +捱:挨 +捴:搃 +掃:扫 +掄:抡 +掗:挜 +掙:挣 +掛:挂 +採:采 +揀:拣 +揔:搃 +揚:扬 +換:换 +揮:挥 +揯:搄 +揹:背 +損:损 +搖:摇 +搗:捣 +搥:捶 +搵:揾 +搶:抢 +摀:捂 +摂:摄 +摑:掴 +摜:掼 +摟:搂 +摠:搃 +摯:挚 +摳:抠 +摶:抟 +摺:折 +摻:掺 +撈:捞 +撏:挦 +撐:撑 +撓:挠 +撟:挢 +撣:掸 +撥:拨 +撫:抚 +撲:扑 +撳:揿 +撹:搅 +撻:挞 +撾:挝 +撿:捡 +擁:拥 +擄:掳 +擆:撯 +擇:择 +擊:击 +擋:挡 +擔:担 +擕:携 +擙:扷 +據:据 +擠:挤 +擡:抬 +擧:挙 +擬:拟 +擯:摈 +擰:拧 +擱:搁 +擲:掷 +擴:扩 +擷:撷 +擺:摆 +擻:擞 +擼:撸 +擾:扰 +攄:摅 +攆:撵 +攏:拢 +攔:拦 +攖:撄 +攙:搀 +攛:撺 +攜:携 +攝:摄 +攢:攒 +攣:挛 +攤:摊 +攪:搅 +攬:揽 +敎:教 +敓:敚 +敗:败 +敘:叙 +敵:敌 +數:数 +斂:敛 +斃:毙 +斅:敩 +斆:敩 +斉:齐 +斎:斋 +斕:斓 +斬:斩 +斷:断 +於:于 +昿:旷 +時:时 +晉:晋 +晝:昼 +暁:晓 +暈:晕 +暉:晖 +暘:旸 +暢:畅 +暫:暂 +暱:昵 +曄:晔 +曆:历 +曇:昙 +曉:晓 +曖:暧 +曠:旷 +曨:昽 +曬:晒 +書:书 +會:会 +朧:胧 +朶:朵 +東:东 +枱:台 +柵:栅 +柺:拐 +栄:荣 +桜:樱 +桟:栈 +桿:杆 +梘:枧 +條:条 +梟:枭 +梲:棁 +棄:弃 +棖:枨 +棗:枣 +棟:栋 +棧:栈 +棲:栖 +棶:梾 +椏:桠 +検:检 +楊:杨 +楓:枫 +楞:愣 +楨:桢 +業:业 +極:极 +楽:乐 +榪:杩 +榮:荣 +榲:榅 +榿:桤 +構:构 +槍:枪 +槓:杠 +様:样 +槤:梿 +槧:椠 +槪:概 +槮:椮 +槳:桨 +槼:椝 +樁:桩 +樂:乐 +樅:枞 +樓:楼 +標:标 +樞:枢 +樣:样 +樧:榝 +権:权 +樳:桪 +樴:枳 +樸:朴 +樹:树 +樺:桦 +樿:椫 +橈:桡 +橋:桥 +橒:枟 +機:机 +橢:椭 +橫:横 +檁:檩 +檉:柽 +檔:档 +檜:桧 +檟:槚 +檢:检 +檣:樯 +檮:梼 +檯:台 +檳:槟 +檸:柠 +檻:槛 +櫃:柜 +櫉:橱 +櫓:橹 +櫚:榈 +櫛:栉 +櫝:椟 +櫞:橼 +櫟:栎 +櫥:橱 +櫧:槠 +櫨:栌 +櫪:枥 +櫫:橥 +櫬:榇 +櫳:栊 +櫸:榉 +櫻:樱 +欄:栏 +權:权 +欏:椤 +欒:栾 +欖:榄 +欞:棂 +欽:钦 +歎:叹 +歐:欧 +歓:欢 +歟:欤 +歡:欢 +歯:齿 +歲:岁 +歳:岁 +歷:历 +歸:归 +歿:殁 +殘:残 +殞:殒 +殤:殇 +殫:殚 +殭:僵 +殮:殓 +殯:殡 +殲:歼 +殺:杀 +殻:壳 +殼:壳 +毀:毁 +毆:殴 +毎:每 +毿:毵 +氂:牦 +氈:毡 +氊:毡 +氌:氇 +気:气 +氣:气 +氫:氢 +氬:氩 +氳:氲 +汙:污 +汚:污 +決:决 +沒:没 +沖:冲 +沢:泽 +況:况 +洶:汹 +浄:净 +浹:浃 +涇:泾 +涗:涚 +涜:渎 +涼:凉 +淒:凄 +淚:泪 +淥:渌 +淨:净 +淪:沦 +淵:渊 +淶:涞 +淸:清 +淺:浅 +済:济 +渉:涉 +渙:涣 +減:减 +渢:沨 +渦:涡 +測:测 +渾:浑 +湊:凑 +湞:浈 +湧:涌 +湯:汤 +満:满 +溈:沩 +溌:泼 +準:准 +溝:沟 +溫:温 +溮:浉 +溳:涢 +溼:湿 +滄:沧 +滅:灭 +滌:涤 +滎:荥 +滙:汇 +滝:泷 +滬:沪 +滯:滞 +滲:渗 +滷:卤 +滸:浒 +滻:浐 +滾:滚 +滿:满 +漁:渔 +漊:溇 +漑:溉 +漚:沤 +漢:汉 +漣:涟 +漬:渍 +漲:涨 +漸:渐 +漿:浆 +潁:颍 +潅:灌 +潑:泼 +潔:洁 +潙:沩 +潛:潜 +潤:润 +潯:浔 +潰:溃 +潷:滗 +潿:涠 +澀:涩 +澆:浇 +澇:涝 +澐:沄 +澗:涧 +澠:渑 +澤:泽 +澦:滪 +澩:泶 +澮:浍 +澱:淀 +濁:浊 +濃:浓 +濔:沵 +濕:湿 +濘:泞 +濚:溁 +濛:蒙 +濜:浕 +濟:济 +濤:涛 +濫:滥 +濰:潍 +濱:滨 +濳:潜 +濺:溅 +濼:泺 +濾:滤 +瀀:沋 +瀅:滢 +瀆:渎 +瀉:泻 +瀋:沈 +瀏:浏 +瀕:濒 +瀘:泸 +瀝:沥 +瀟:潇 +瀠:潆 +瀦:潴 +瀧:泷 +瀨:濑 +瀰:弥 +瀲:潋 +瀾:澜 +灄:滠 +灎:滟 +灑:洒 +灔:滟 +灘:滩 +灝:灏 +灣:湾 +灤:滦 +灧:滟 +災:灾 +為:为 +烏:乌 +烴:烃 +焔:焰 +無:无 +焼:烧 +煉:炼 +煒:炜 +煙:烟 +煢:茕 +煥:焕 +煩:烦 +煬:炀 +煱:㶽 +熅:煴 +熒:荧 +熗:炝 +熱:热 +熲:颎 +熾:炽 +燁:烨 +燈:灯 +燉:炖 +燒:烧 +燙:烫 +燜:焖 +營:营 +燣:燷 +燦:灿 +燬:毀 +燭:烛 +燴:烩 +燼:烬 +燾:焘 +爍:烁 +爐:炉 +爛:烂 +爭:争 +爲:为 +爺:爷 +爾:尔 +牀:床 +牆:墙 +牘:牍 +牽:牵 +犖:荦 +犢:犊 +犧:牺 +狀:状 +狹:狭 +狽:狈 +猙:狰 +猶:犹 +猻:狲 +獁:犸 +獃:呆 +獄:狱 +獅:狮 +獎:奖 +獨:独 +獪:狯 +獫:猃 +獮:狝 +獰:狞 +獲:获 +獵:猎 +獷:犷 +獸:兽 +獺:獭 +獻:献 +獼:猕 +玀:猡 +現:现 +琺:珐 +琿:珲 +瑋:玮 +瑒:玚 +瑣:琐 +瑤:瑶 +瑩:莹 +瑪:玛 +瑯:琅 +瑲:玱 +璉:琏 +璡:琎 +璣:玑 +璦:瑷 +璫:珰 +環:环 +璵:玙 +璸:瑸 +璽:玺 +瓊:琼 +瓏:珑 +瓔:璎 +瓚:瓒 +甁:瓶 +甌:瓯 +產:产 +産:产 +甯:宁 +畄:留 +畝:亩 +畢:毕 +畫:画 +異:异 +畵:画 +當:当 +疇:畴 +疊:叠 +痙:痉 +痲:麻 +瘂:痖 +瘋:疯 +瘍:疡 +瘓:痪 +瘡:疮 +瘧:疟 +瘮:瘆 +瘱:瘗 +瘲:疭 +瘻:瘘 +療:疗 +癆:痨 +癇:痫 +癉:瘅 +癒:愈 +癘:疠 +癛:癝 +癟:瘪 +癡:痴 +癢:痒 +癤:疖 +癧:疬 +癩:癞 +癬:癣 +癭:瘿 +癮:瘾 +癰:痈 +癱:瘫 +癲:癫 +発:发 +發:发 +皚:皑 +皸:皲 +皹:皲 +皺:皱 +盃:杯 +盜:盗 +盞:盏 +盡:尽 +監:监 +盤:盘 +盧:卢 +盪:荡 +眾:众 +睏:困 +睜:睁 +睞:睐 +瞇:眯 +瞘:眍 +瞞:瞒 +瞭:了 +瞶:瞆 +瞼:睑 +矇:蒙 +矓:眬 +矚:瞩 +矯:矫 +硜:硁 +硤:硖 +硨:砗 +硯:砚 +碁:棋 +碩:硕 +碭:砀 +碸:砜 +確:确 +碼:码 +磑:硙 +磚:砖 +磠:硵 +磣:碜 +磧:碛 +磯:矶 +磽:硗 +礄:硚 +礆:硷 +礎:础 +礙:碍 +礟:炮 +礦:矿 +礪:砺 +礫:砾 +礮:砲 +礱:砻 +祿:禄 +禍:祸 +禎:祯 +禕:祎 +禡:祃 +禦:御 +禪:禅 +禮:礼 +禰:祢 +禱:祷 +禿:秃 +稅:税 +稜:棱 +稟:禀 +種:种 +稱:称 +稲:稻 +穀:谷 +穂:穗 +穇:䅟 +穌:稣 +積:积 +穎:颖 +穏:稳 +穠:秾 +穡:穑 +穢:秽 +穩:稳 +穫:获 +穭:穞 +窩:窝 +窪:洼 +窮:穷 +窯:窑 +窰:窑 +窵:窎 +窶:窭 +窺:窥 +竄:窜 +竅:窍 +竇:窦 +竈:灶 +竊:窃 +竜:龙 +竪:竖 +競:竞 +筆:笔 +筍:笋 +筧:笕 +箋:笺 +箏:筝 +節:节 +範:范 +築:筑 +篋:箧 +篔:筼 +篠:筿 +篤:笃 +篩:筛 +篭:笼 +篳:筚 +簀:箦 +簍:篓 +簘:箫 +簞:箪 +簡:简 +簣:篑 +簪:簮 +簫:箫 +簷:檐 +簹:筜 +簽:签 +簾:帘 +籃:篮 +籌:筹 +籔:䉤 +籙:箓 +籛:篯 +籜:箨 +籟:籁 +籠:笼 +籤:签 +籩:笾 +籪:簖 +籬:篱 +籮:箩 +籲:吁 +粛:肃 +粵:粤 +糉:粽 +糚:粧 +糝:糁 +糞:粪 +糧:粮 +糰:团 +糲:粝 +糴:籴 +糾:纠 +紀:纪 +紂:纣 +約:约 +紅:红 +紆:纡 +紇:纥 +紈:纨 +紉:纫 +紋:纹 +納:纳 +紐:纽 +紓:纾 +純:纯 +紕:纰 +紖:纼 +紗:纱 +紘:纮 +紙:纸 +級:级 +紛:纷 +紜:纭 +紝:纴 +紡:纺 +紮:扎 +細:细 +紱:绂 +紲:绁 +紳:绅 +紵:纻 +紹:绍 +紺:绀 +紼:绋 +紿:绐 +絀:绌 +終:终 +組:组 +絆:绊 +経:经 +絎:绗 +結:结 +絕:绝 +絝:绔 +絞:绞 +絡:络 +絢:绚 +給:给 +絨:绒 +絰:绖 +統:统 +絲:丝 +絳:绛 +絵:绘 +絶:绝 +絹:绢 +綁:绑 +綃:绡 +綆:绠 +綈:绨 +綌:绤 +綏:绥 +經:经 +綜:综 +綞:缍 +綠:绿 +綢:绸 +綣:绻 +綫:线 +綬:绶 +維:维 +綯:绹 +綰:绾 +綱:纲 +網:网 +綳:绷 +綴:缀 +綵:采 +綸:纶 +綹:绺 +綺:绮 +綻:绽 +綽:绰 +綾:绫 +綿:绵 +緄:绲 +緇:缁 +緊:紧 +緋:绯 +総:总 +緑:绿 +緒:绪 +緓:绬 +緔:绱 +緖:绪 +緗:缃 +緘:缄 +緙:缂 +線:线 +緝:缉 +緞:缎 +締:缔 +緡:缗 +緣:缘 +緦:缌 +編:编 +緩:缓 +緬:缅 +緯:纬 +緱:缑 +緲:缈 +練:练 +緶:缏 +緹:缇 +緻:致 +緼:缊 +緾:缠 +縂:总 +縈:萦 +縉:缙 +縊:缢 +縋:缒 +縐:绉 +縑:缣 +縕:缊 +縗:缞 +縛:缚 +縝:缜 +縞:缟 +縟:缛 +縣:县 +縦:纵 +縧:绦 +縫:缝 +縭:缡 +縮:缩 +縱:纵 +縲:缧 +縵:缦 +縶:絷 +縷:缕 +縹:缥 +總:总 +績:绩 +繃:绷 +繅:缫 +繆:缪 +繍:绣 +繒:缯 +織:织 +繕:缮 +繚:缭 +繞:绕 +繡:绣 +繢:缋 +繩:绳 +繪:绘 +繫:系 +繭:茧 +繮:缰 +繯:缳 +繰:缲 +繳:缴 +繹:绎 +繼:继 +繽:缤 +繾:缱 +纇:颣 +纈:缬 +纊:纩 +續:续 +纏:缠 +纒:缠 +纓:缨 +纔:才 +纖:纤 +纘:缵 +纜:缆 +缽:钵 +罈:坛 +罌:罂 +罎:坛 +罰:罚 +罵:骂 +罷:罢 +罸:罚 +羅:罗 +羆:罴 +羈:羁 +羥:羟 +羨:羡 +義:义 +羴:羶 +習:习 +翬:翚 +翹:翘 +翺:翱 +翽:翙 +耬:耧 +耮:耢 +聖:圣 +聞:闻 +聯:联 +聰:聪 +聲:声 +聳:耸 +聴:听 +聵:聩 +聶:聂 +職:职 +聹:聍 +聼:听 +聽:听 +聾:聋 +肅:肃 +脅:胁 +脈:脉 +脛:胫 +脫:脱 +脹:胀 +腁:胼 +腎:肾 +腖:胨 +腡:脶 +腦:脑 +腫:肿 +腳:脚 +腸:肠 +膃:腽 +膓:肠 +膕:腘 +膚:肤 +膠:胶 +膩:腻 +膽:胆 +膾:脍 +膿:脓 +臉:脸 +臍:脐 +臏:膑 +臓:脏 +臘:腊 +臚:胪 +臟:脏 +臠:脔 +臢:臜 +臥:卧 +臨:临 +臺:台 +與:与 +興:兴 +舉:举 +舊:旧 +舖:铺 +舗:铺 +艙:舱 +艤:舣 +艦:舰 +艫:舻 +艱:艰 +艶:艳 +艷:艳 +芻:刍 +苧:苎 +茲:兹 +荊:荆 +荘:庄 +莊:庄 +莖:茎 +莢:荚 +莧:苋 +菓:果 +華:华 +菸:烟 +萇:苌 +萊:莱 +萕:荠 +萬:万 +萴:荝 +萵:莴 +葉:叶 +葒:荭 +著:着 +葤:荮 +葦:苇 +葯:药 +葷:荤 +蒓:莼 +蒔:莳 +蒕:蒀 +蒞:莅 +蒼:苍 +蓀:荪 +蓋:盖 +蓮:莲 +蓯:苁 +蓽:荜 +蔉:蓘 +蔔:卜 +蔞:蒌 +蔣:蒋 +蔥:葱 +蔦:茑 +蔭:荫 +蔴:麻 +蕁:荨 +蕆:蒇 +蕎:荞 +蕒:荬 +蕓:芸 +蕕:莸 +蕘:荛 +蕢:蒉 +蕩:荡 +蕪:芜 +蕭:萧 +蕷:蓣 +薀:蕰 +薈:荟 +薊:蓟 +薌:芗 +薑:姜 +薔:蔷 +薘:荙 +薟:莶 +薦:荐 +薩:萨 +薫:薰 +薬:药 +薳:䓕 +薺:荠 +藉:借 +藍:蓝 +藎:荩 +藝:艺 +藥:药 +藪:薮 +藴:蕴 +藶:苈 +藸:蕏 +藹:蔼 +藺:蔺 +蘀:萚 +蘄:蕲 +蘆:芦 +蘇:苏 +蘊:蕴 +蘋:苹 +蘍:薫 +蘚:藓 +蘞:蔹 +蘢:茏 +蘭:兰 +蘺:蓠 +蘿:萝 +處:处 +虛:虚 +虜:虏 +號:号 +虧:亏 +虯:虬 +蛍:萤 +蛺:蛱 +蛻:蜕 +蜆:蚬 +蜖:蛔 +蝄:蛧 +蝋:蜡 +蝕:蚀 +蝟:猬 +蝦:虾 +蝨:虱 +蝸:蜗 +蝿:蝇 +螄:蛳 +螞:蚂 +螢:萤 +螻:蝼 +螿:螀 +蟄:蛰 +蟈:蝈 +蟎:螨 +蟣:虮 +蟬:蝉 +蟯:蛲 +蟲:虫 +蟶:蛏 +蟻:蚁 +蠁:蚃 +蠅:蝇 +蠆:虿 +蠐:蛴 +蠑:蝾 +蠔:蚝 +蠟:蜡 +蠣:蛎 +蠨:蟏 +蠱:蛊 +蠶:蚕 +蠺:蚕 +蠻:蛮 +衆:众 +衊:蔑 +術:术 +衕:同 +衚:胡 +衛:卫 +衝:冲 +衞:卫 +袞:衮 +裊:袅 +裏:里 +補:补 +裝:装 +裡:里 +製:制 +複:复 +褌:裈 +褘:袆 +褲:裤 +褳:裢 +褸:褛 +褻:亵 +襇:裥 +襏:袯 +襖:袄 +襝:裣 +襠:裆 +襤:褴 +襪:袜 +襬:摆 +襯:衬 +襲:袭 +襴:襕 +覇:霸 +覊:羁 +見:见 +覌:观 +覎:觃 +規:规 +覓:觅 +視:视 +覘:觇 +覚:觉 +覡:觋 +覥:觍 +覦:觎 +覧:览 +親:亲 +覬:觊 +覯:觏 +覲:觐 +観:观 +覷:觑 +覺:觉 +覽:览 +覿:觌 +觀:观 +觔:筋 +觴:觞 +觶:觯 +觸:触 +訁:讠 +訂:订 +訃:讣 +計:计 +訊:讯 +訌:讧 +討:讨 +訐:讦 +訒:讱 +訓:训 +訕:讪 +訖:讫 +託:托 +記:记 +訛:讹 +訝:讶 +訟:讼 +訣:诀 +訥:讷 +訩:讻 +訪:访 +設:设 +許:许 +訳:译 +訴:诉 +訶:诃 +診:诊 +註:注 +詁:诂 +詆:诋 +詎:讵 +詐:诈 +詒:诒 +詔:诏 +評:评 +詖:诐 +詗:诇 +詘:诎 +詛:诅 +詞:词 +詠:咏 +詡:诩 +詢:询 +詣:诣 +試:试 +詩:诗 +詫:诧 +詬:诟 +詭:诡 +詮:诠 +詰:诘 +話:话 +該:该 +詳:详 +詵:诜 +詼:诙 +詿:诖 +誄:诔 +誅:诛 +誆:诓 +誇:夸 +誌:志 +認:认 +誑:诳 +誒:诶 +誕:诞 +誘:诱 +誚:诮 +語:语 +誠:诚 +誡:诫 +誣:诬 +誤:误 +誥:诰 +誦:诵 +誨:诲 +說:说 +説:说 +読:读 +誰:谁 +課:课 +誶:谇 +誹:诽 +誼:谊 +誾:訚 +調:调 +諂:谄 +諄:谆 +談:谈 +諉:诿 +請:请 +諍:诤 +諏:诹 +諑:诼 +諒:谅 +論:论 +諗:谂 +諛:谀 +諜:谍 +諝:谞 +諞:谝 +諡:谥 +諢:诨 +諤:谔 +諦:谛 +諧:谐 +諫:谏 +諭:谕 +諮:谘 +諱:讳 +諳:谙 +諶:谌 +諷:讽 +諸:诸 +諺:谚 +諼:谖 +諾:诺 +謀:谋 +謁:谒 +謂:谓 +謄:誊 +謅:诌 +謊:谎 +謎:谜 +謐:谧 +謔:谑 +謖:谡 +謗:谤 +謙:谦 +謚:谥 +講:讲 +謝:谢 +謠:谣 +謨:谟 +謫:谪 +謬:谬 +謭:谫 +謳:讴 +謹:谨 +謾:谩 +譁:哗 +證:证 +譎:谲 +譏:讥 +譖:谮 +識:识 +譙:谯 +譚:谭 +譜:谱 +譡:谠 +譫:谵 +譭:毀 +譯:译 +議:议 +譴:谴 +護:护 +譸:诪 +譽:誉 +讀:读 +讅:谉 +變:变 +讋:詟 +讌:䜩 +讎:雠 +讒:谗 +讓:让 +讕:谰 +讖:谶 +讚:赞 +讞:谳 +豈:岂 +豎:竖 +豐:丰 +豬:猪 +豶:豮 +貍:狸 +貓:猫 +貘:獏 +貛:獾 +貝:贝 +貞:贞 +貟:贠 +負:负 +財:财 +貢:贡 +貧:贫 +貨:货 +販:贩 +貪:贪 +貫:贯 +責:责 +貯:贮 +貰:贳 +貲:赀 +貳:贰 +貴:贵 +貶:贬 +買:买 +貸:贷 +貺:贶 +費:费 +貼:贴 +貽:贻 +貿:贸 +賀:贺 +賁:贲 +賂:赂 +賃:赁 +賄:贿 +賅:赅 +資:资 +賈:贾 +賊:贼 +賎:贱 +賑:赈 +賒:赊 +賓:宾 +賕:赇 +賙:赒 +賚:赉 +賜:赐 +賞:赏 +賠:赔 +賡:赓 +賢:贤 +賣:卖 +賤:贱 +賦:赋 +賧:赕 +質:质 +賫:赍 +賬:账 +賭:赌 +賴:赖 +賵:赗 +賺:赚 +賻:赙 +購:购 +賽:赛 +贄:贽 +贅:赘 +贇:赟 +贈:赠 +贊:赞 +贋:赝 +贍:赡 +贏:赢 +贐:赆 +贓:赃 +贔:赑 +贖:赎 +贗:赝 +贛:赣 +贜:赃 +赬:赪 +趕:赶 +趙:赵 +趨:趋 +趲:趱 +跡:迹 +跥:跺 +踐:践 +踴:踊 +蹌:跄 +蹕:跸 +蹣:蹒 +蹤:踪 +蹺:跷 +躂:跶 +躉:趸 +躊:踌 +躋:跻 +躍:跃 +躑:踯 +躒:跞 +躓:踬 +躕:蹰 +躚:跹 +躡:蹑 +躥:蹿 +躦:躜 +躪:躏 +躱:躲 +軀:躯 +車:车 +軋:轧 +軌:轨 +軍:军 +軑:轪 +軒:轩 +軔:轫 +軛:轭 +軟:软 +転:转 +軤:轷 +軫:轸 +軲:轱 +軸:轴 +軹:轵 +軺:轺 +軻:轲 +軼:轶 +軽:轻 +軾:轼 +較:较 +輅:辂 +輇:辁 +輈:辀 +載:载 +輊:轾 +輌:辆 +輒:辄 +輔:辅 +輕:轻 +輛:辆 +輜:辎 +輝:辉 +輞:辋 +輟:辍 +輥:辊 +輦:辇 +輩:辈 +輪:轮 +輬:辌 +輯:辑 +輳:辏 +輸:输 +輻:辐 +輼:辒 +輾:辗 +輿:舆 +轀:辒 +轂:毂 +轄:辖 +轅:辕 +轆:辘 +轉:转 +轍:辙 +轎:轿 +轔:辚 +轟:轰 +轡:辔 +轢:轹 +轤:轳 +辦:办 +辭:辞 +辮:辫 +辯:辩 +農:农 +辺:边 +迊:迎 +迴:回 +迺:乃 +逕:迳 +這:这 +連:连 +逥:迴 +逬:迸 +週:周 +進:进 +逺:远 +遀:迶 +遊:游 +運:运 +過:过 +達:达 +違:违 +遙:遥 +遜:逊 +遞:递 +遠:远 +適:适 +遲:迟 +遶:绕 +遷:迁 +選:选 +遺:遗 +遼:辽 +邁:迈 +還:还 +邇:迩 +邊:边 +邏:逻 +邐:逦 +郟:郏 +郵:邮 +鄆:郓 +鄉:乡 +鄒:邹 +鄔:邬 +鄕:乡 +鄖:郧 +鄧:邓 +鄭:郑 +鄰:邻 +鄲:郸 +鄴:邺 +鄶:郐 +鄺:邝 +酇:酂 +酈:郦 +醃:腌 +醗:酦 +醜:丑 +醞:酝 +醤:酱 +醫:医 +醬:酱 +醱:酦 +釀:酿 +釁:衅 +釃:酾 +釅:酽 +釈:释 +釋:释 +釐:厘 +釒:钅 +釓:钆 +釔:钇 +釕:钌 +釗:钊 +釘:钉 +釙:钋 +針:针 +釣:钓 +釤:钐 +釧:钏 +釩:钒 +釵:钗 +釷:钍 +釹:钕 +釺:钎 +鈀:钯 +鈁:钫 +鈃:钘 +鈄:钭 +鈈:钚 +鈉:钠 +鈍:钝 +鈎:钩 +鈐:钤 +鈑:钣 +鈒:钑 +鈔:钞 +鈕:钮 +鈞:钧 +鈣:钙 +鈥:钬 +鈦:钛 +鈧:钪 +鈬:铎 +鈮:铌 +鈰:铈 +鈳:钶 +鈴:铃 +鈷:钴 +鈸:钹 +鈹:铍 +鈺:钰 +鈽:钸 +鈾:铀 +鈿:钿 +鉀:钾 +鉄:铁 +鉅:钜 +鉈:铊 +鉉:铉 +鉋:铇 +鉍:铋 +鉑:铂 +鉕:钷 +鉗:钳 +鉚:铆 +鉛:铅 +鉞:钺 +鉢:钵 +鉤:钩 +鉦:钲 +鉬:钼 +鉭:钽 +鉱:矿 +鉶:铏 +鉸:铰 +鉺:铒 +鉻:铬 +鉿:铪 +銀:银 +銃:铳 +銅:铜 +銍:铚 +銑:铣 +銓:铨 +銖:铢 +銘:铭 +銚:铫 +銛:铦 +銜:衔 +銠:铑 +銣:铷 +銥:铱 +銦:铟 +銨:铵 +銩:铥 +銪:铕 +銫:铯 +銬:铐 +銭:钱 +銱:铞 +銳:锐 +銷:销 +銹:锈 +銻:锑 +銼:锉 +鋁:铝 +鋃:锒 +鋅:锌 +鋇:钡 +鋌:铤 +鋏:铗 +鋒:锋 +鋙:铻 +鋝:锊 +鋟:锓 +鋣:铘 +鋤:锄 +鋥:锃 +鋦:锔 +鋨:锇 +鋩:铓 +鋪:铺 +鋭:锐 +鋮:铖 +鋯:锆 +鋰:锂 +鋱:铽 +鋳:铸 +鋶:锍 +鋸:锯 +鋼:钢 +錁:锞 +錄:录 +錆:锖 +錇:锫 +錈:锩 +錏:铔 +錐:锥 +錒:锕 +錕:锟 +錘:锤 +錙:锱 +錚:铮 +錛:锛 +錟:锬 +錠:锭 +錡:锜 +錢:钱 +錦:锦 +錨:锚 +錩:锠 +錫:锡 +錮:锢 +錯:错 +録:录 +錳:锰 +錶:表 +錸:铼 +鍀:锝 +鍁:锨 +鍃:锪 +鍆:钔 +鍇:锴 +鍈:锳 +鍊:炼 +鍋:锅 +鍍:镀 +鍔:锷 +鍘:铡 +鍚:钖 +鍛:锻 +鍠:锽 +鍤:锸 +鍥:锲 +鍩:锘 +鍬:锹 +鍰:锾 +鍵:键 +鍶:锶 +鍾:钟 +鎂:镁 +鎄:锿 +鎇:镅 +鎊:镑 +鎔:镕 +鎖:锁 +鎗:枪 +鎘:镉 +鎚:锤 +鎛:镈 +鎡:镃 +鎢:钨 +鎣:蓥 +鎦:镏 +鎧:铠 +鎩:铩 +鎪:锼 +鎬:镐 +鎭:镇 +鎮:镇 +鎰:镒 +鎲:镋 +鎳:镍 +鎵:镓 +鎸:镌 +鎿:镎 +鏃:镞 +鏇:镟 +鏈:链 +鏌:镆 +鏍:镙 +鏐:镠 +鏑:镝 +鏗:铿 +鏘:锵 +鏜:镗 +鏝:镘 +鏞:镛 +鏟:铲 +鏡:镜 +鏢:镖 +鏤:镂 +鏨:錾 +鏰:镚 +鏵:铧 +鏷:镤 +鏹:镪 +鏽:锈 +鐃:铙 +鐋:铴 +鐐:镣 +鐒:铹 +鐓:镦 +鐔:镡 +鐘:钟 +鐙:镫 +鐝:镢 +鐠:镨 +鐦:锎 +鐧:锏 +鐨:镄 +鐫:镌 +鐮:镰 +鐲:镯 +鐳:镭 +鐵:铁 +鐶:镮 +鐸:铎 +鐺:铛 +鐿:镱 +鑄:铸 +鑊:镬 +鑌:镔 +鑑:鉴 +鑒:鉴 +鑔:镲 +鑕:锧 +鑚:钻 +鑛:矿 +鑞:镴 +鑠:铄 +鑣:镳 +鑥:镥 +鑭:镧 +鑰:钥 +鑱:镵 +鑲:镶 +鑷:镊 +鑹:镩 +鑼:锣 +鑽:钻 +鑾:銮 +鑿:凿 +钂:镋 +門:门 +閂:闩 +閃:闪 +閆:闫 +閈:闬 +閉:闭 +開:开 +閌:闶 +閎:闳 +閏:闰 +閑:闲 +閒:闲 +間:间 +閔:闵 +閗:斗 +閘:闸 +閙:闹 +閡:阂 +関:关 +閣:阁 +閤:合 +閥:阀 +閨:闺 +閩:闽 +閫:阃 +閬:阆 +閭:闾 +閱:阅 +閲:阅 +閶:阊 +閹:阉 +閻:阎 +閼:阏 +閽:阍 +閾:阈 +閿:阌 +闃:阒 +闆:板 +闈:闱 +闊:阔 +闋:阕 +闌:阑 +闍:阇 +闐:阗 +闒:阘 +闓:闿 +闔:阖 +闕:阙 +闖:闯 +闗:关 +闘:斗 +關:关 +闞:阚 +闠:阓 +闡:阐 +闢:辟 +闤:阛 +闥:闼 +陘:陉 +陜:陕 +陝:陕 +陞:升 +陣:阵 +陥:陷 +陰:阴 +陳:陈 +陸:陆 +険:险 +陽:阳 +隊:队 +階:阶 +隕:陨 +際:际 +隠:隐 +隨:随 +險:险 +隱:隐 +隴:陇 +隸:隶 +隻:只 +雈:萑 +雋:隽 +雑:杂 +雖:虽 +雙:双 +雛:雏 +雜:杂 +雞:鸡 +離:离 +難:难 +雲:云 +電:电 +霢:霡 +霧:雾 +霽:霁 +靂:雳 +靄:霭 +靆:叇 +靈:灵 +靉:叆 +靑:青 +靚:靓 +靜:静 +靝:靔 +靦:腼 +靨:靥 +鞏:巩 +鞦:秋 +鞽:鞒 +韁:缰 +韃:鞑 +韆:千 +韉:鞯 +韋:韦 +韌:韧 +韍:韨 +韓:韩 +韙:韪 +韜:韬 +韞:韫 +韲:齑 +韻:韵 +響:响 +頁:页 +頂:顶 +頃:顷 +項:项 +順:顺 +頇:顸 +須:须 +頊:顼 +頋:顾 +頌:颂 +頎:颀 +頏:颃 +預:预 +頑:顽 +頒:颁 +頓:顿 +頗:颇 +領:领 +頜:颌 +頡:颉 +頤:颐 +頦:颏 +頬:颊 +頭:头 +頮:颒 +頰:颊 +頲:颋 +頴:颕 +頷:颔 +頸:颈 +頹:颓 +頻:频 +頽:颓 +顆:颗 +題:题 +額:额 +顎:颚 +顏:颜 +顒:颙 +顓:颛 +顔:颜 +顖:囟 +願:愿 +顙:颡 +顚:颠 +顛:颠 +類:类 +顢:颟 +顥:颢 +顧:顾 +顫:颤 +顬:颥 +顯:显 +顰:颦 +顱:颅 +顳:颞 +顴:颧 +風:风 +颭:飐 +颮:飑 +颯:飒 +颱:台 +颳:刮 +颶:飓 +颸:飔 +颺:飏 +颻:飖 +颼:飕 +飀:飗 +飄:飘 +飆:飙 +飇:飚 +飛:飞 +飠:饣 +飢:饥 +飣:饤 +飥:饦 +飩:饨 +飪:饪 +飫:饫 +飭:饬 +飯:饭 +飲:饮 +飴:饴 +飼:饲 +飽:饱 +飾:饰 +飿:饳 +餃:饺 +餄:饸 +餅:饼 +餉:饷 +養:养 +餌:饵 +餎:饹 +餏:饻 +餑:饽 +餒:馁 +餓:饿 +餕:馂 +餖:饾 +餘:余 +餚:肴 +餛:馄 +餜:馃 +餞:饯 +餠:饼 +餡:馅 +館:馆 +餬:糊 +餳:饧 +餵:喂 +餶:馉 +餷:馇 +餺:馎 +餻:糕 +餼:饩 +餾:馏 +餿:馊 +饁:馌 +饃:馍 +饅:馒 +饈:馐 +饉:馑 +饊:馓 +饋:馈 +饌:馔 +饑:饥 +饒:饶 +饗:飨 +饜:餍 +饞:馋 +饢:馕 +馭:驭 +馮:冯 +馱:驮 +馳:驰 +馴:驯 +馹:驲 +駁:驳 +駆:驱 +駐:驻 +駑:驽 +駒:驹 +駔:驵 +駕:驾 +駘:骀 +駙:驸 +駛:驶 +駝:驼 +駟:驷 +駡:骂 +駢:骈 +駭:骇 +駰:骃 +駱:骆 +駸:骎 +駿:骏 +騁:骋 +騂:骍 +騅:骓 +騈:骈 +騌:骔 +騍:骒 +騎:骑 +騏:骐 +験:验 +騖:骛 +騙:骗 +騤:骙 +騫:骞 +騭:骘 +騮:骝 +騰:腾 +騶:驺 +騷:骚 +騸:骟 +騾:骡 +驀:蓦 +驁:骜 +驂:骖 +驃:骠 +驄:骢 +驅:驱 +驊:骅 +驌:骕 +驍:骁 +驏:骣 +驕:骄 +驗:验 +驚:惊 +驛:驿 +驟:骤 +驢:驴 +驤:骧 +驥:骥 +驦:骦 +驪:骊 +驫:骉 +骯:肮 +髏:髅 +髒:脏 +體:体 +髕:髌 +髖:髋 +髮:发 +鬆:松 +鬍:胡 +鬚:须 +鬢:鬓 +鬥:斗 +鬦:斗 +鬧:闹 +鬨:哄 +鬩:阋 +鬪:斗 +鬬:斗 +鬭:斗 +鬮:阄 +鬱:郁 +鬹:鬶 +魎:魉 +魘:魇 +魚:鱼 +魛:鱽 +魢:鱾 +魨:鲀 +魯:鲁 +魴:鲂 +魷:鱿 +魺:鲄 +鮁:鲅 +鮃:鲆 +鮊:鲌 +鮋:鲉 +鮍:鲏 +鮎:鲇 +鮐:鲐 +鮑:鲍 +鮒:鲋 +鮓:鲊 +鮚:鲒 +鮜:鲘 +鮝:鲞 +鮞:鲕 +鮦:鲖 +鮪:鲔 +鮫:鲛 +鮭:鲑 +鮮:鲜 +鮳:鲓 +鮶:鲪 +鮺:鲝 +鯀:鲧 +鯁:鲠 +鯇:鲩 +鯉:鲤 +鯊:鲨 +鯒:鲬 +鯔:鲻 +鯕:鲯 +鯖:鲭 +鯛:鲷 +鯝:鲴 +鯡:鲱 +鯢:鲵 +鯤:鲲 +鯧:鲳 +鯨:鲸 +鯪:鲮 +鯫:鲰 +鯰:鲶 +鯴:鲺 +鯵:鲹 +鯷:鳀 +鯽:鲫 +鯿:鳊 +鰁:鳈 +鰂:鲗 +鰃:鳂 +鰈:鲽 +鰉:鳇 +鰍:鳅 +鰏:鲾 +鰐:鳄 +鰒:鳆 +鰓:鳃 +鰛:鳁 +鰜:鳒 +鰟:鳑 +鰠:鳋 +鰣:鲥 +鰥:鳏 +鰨:鳎 +鰩:鳐 +鰭:鳍 +鰮:鳁 +鰱:鲢 +鰲:鳌 +鰳:鳓 +鰵:鳘 +鰷:鲦 +鰹:鲣 +鰻:鳗 +鰼:鳛 +鰾:鳔 +鱂:鳉 +鱅:鳙 +鱈:鳕 +鱉:鳖 +鱒:鳟 +鱔:鳝 +鱖:鳜 +鱗:鳞 +鱘:鲟 +鱝:鲼 +鱟:鲎 +鱠:鲙 +鱣:鳣 +鱤:鳡 +鱧:鳢 +鱨:鲿 +鱭:鲚 +鱯:鳠 +鱷:鳄 +鱸:鲈 +鱺:鲡 +鱻:鲜 +鳥:鸟 +鳧:凫 +鳩:鸠 +鳬:凫 +鳮:鸡 +鳯:凤 +鳲:鸤 +鳳:凤 +鳴:鸣 +鳶:鸢 +鴆:鸩 +鴇:鸨 +鴉:鸦 +鴌:凤 +鴎:鸥 +鴒:鸰 +鴕:鸵 +鴛:鸳 +鴝:鸲 +鴞:鸮 +鴟:鸱 +鴣:鸪 +鴦:鸯 +鴨:鸭 +鴬:莺 +鴯:鸸 +鴰:鸹 +鴴:鸻 +鴻:鸿 +鴿:鸽 +鵂:鸺 +鵃:鸼 +鵉:鸾 +鵐:鹀 +鵑:鹃 +鵒:鹆 +鵓:鹁 +鵜:鹈 +鵝:鹅 +鵞:鹅 +鵠:鹄 +鵡:鹉 +鵪:鹌 +鵬:鹏 +鵮:鹐 +鵯:鹎 +鵰:雕 +鵲:鹊 +鵷:鹓 +鵾:鹍 +鶇:鸫 +鶉:鹑 +鶊:鹒 +鶏:鸡 +鶓:鹋 +鶖:鹙 +鶘:鹕 +鶚:鹗 +鶡:鹖 +鶥:鹛 +鶦:鹕 +鶩:鹜 +鶬:鸧 +鶯:莺 +鶲:鹟 +鶴:鹤 +鶵:雏 +鶹:鹠 +鶺:鹡 +鶻:鹘 +鶼:鹣 +鷀:鹚 +鷁:鹢 +鷂:鹞 +鷄:鸡 +鷊:鹝 +鷓:鹧 +鷖:鹥 +鷗:鸥 +鷙:鸷 +鷚:鹨 +鷥:鸶 +鷦:鹪 +鷫:鹔 +鷯:鹩 +鷲:鹫 +鷳:鹇 +鷴:鹇 +鷸:鹬 +鷹:鹰 +鷺:鹭 +鷽:鸴 +鸇:鹯 +鸌:鹱 +鸏:鹲 +鸕:鸬 +鸘:鹴 +鸚:鹦 +鸛:鹳 +鸝:鹂 +鸞:鸾 +鹵:卤 +鹸:硷 +鹹:咸 +鹺:鹾 +鹼:硷 +鹽:盐 +麗:丽 +麥:麦 +麩:麸 +麪:面 +麯:曲 +麴:曲 +麵:面 +麼:么 +麽:么 +黃:黄 +黌:黉 +黒:黑 +點:点 +黨:党 +黲:黪 +黴:霉 +黶:黡 +黷:黩 +黽:黾 +黿:鼋 +鼂:鼌 +鼉:鼍 +鼡:鼠 +鼴:鼹 +齊:齐 +齋:斋 +齏:齑 +齒:齿 +齔:龀 +齕:龁 +齗:龂 +齙:龅 +齜:龇 +齟:龃 +齠:龆 +齡:龄 +齢:龄 +齣:出 +齦:龈 +齧:啮 +齪:龊 +齬:龉 +齲:龋 +齷:龌 +龍:龙 +龎:厐 +龐:庞 +龔:龚 +龕:龛 +龜:龟 +龞:鳖 +𧩙:䜥 +𩶘:䲞 diff --git a/libchinese-segmentation/Traditional-to-Simplified-private.h b/libchinese-segmentation/Traditional-to-Simplified-private.h new file mode 100644 index 0000000..c4ddb2d --- /dev/null +++ b/libchinese-segmentation/Traditional-to-Simplified-private.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: jixiaoxu + * + */ + +#ifndef Traditional2SimplifiedPRIVATE_H +#define Traditional2SimplifiedPRIVATE_H + +#include +#include +#include "Traditional-to-Simplified.h" +#include "Traditional2Simplified_trie.h" + +using namespace std; + +class TRADITIONAL_CHINESE_SIMPLIFIED_EXPORT Traditional2SimplifiedPrivate +{ +public: + Traditional2SimplifiedPrivate(Traditional2Simplified *parent = nullptr); + ~Traditional2SimplifiedPrivate(); + +public: + bool isTraditional(string &word) {return m_Traditional2SimplifiedTrie.IsTraditional(word);} + + string getResults(string words); + +private: + + Traditional2Simplified *q = nullptr; + Traditional2SimplifiedTrie m_Traditional2SimplifiedTrie; +}; +#endif // Traditional2SimplifiedPRIVATE_H diff --git a/libchinese-segmentation/Traditional-to-Simplified.cpp b/libchinese-segmentation/Traditional-to-Simplified.cpp new file mode 100644 index 0000000..2e3f85c --- /dev/null +++ b/libchinese-segmentation/Traditional-to-Simplified.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: jixiaoxu + * + */ + +#include +#include +#include "Traditional-to-Simplified.h" +#include "Traditional-to-Simplified-private.h" +#include "cppjieba/Unicode.hpp" + +Traditional2Simplified * Traditional2Simplified::g_Traditional2SimplifiedManager = nullptr; +std::once_flag g_Traditional2SimplifiedSingleFlag; + +string Traditional2SimplifiedPrivate::getResults(string words) +{ + string results; + if (words.empty()) { + return words; + } else if (cppjieba::IsSingleWord(words)) {//单个字符 + results = m_Traditional2SimplifiedTrie.Find(words); + if (results.empty()) { + results = words;//原数据返回 + } + } else {//多个字符 + string oneWord; + string data; + cppjieba::RuneStrArray runeArray; + cppjieba::DecodeRunesInString(words, runeArray); + for (auto i = runeArray.begin(); i != runeArray.end(); ++i) { + oneWord = cppjieba::GetStringFromRunes(words, i, i); + data = m_Traditional2SimplifiedTrie.Find(oneWord); + if (data.empty()) {//单字无结果 + results.append(oneWord); + } else { + results.append(data); + } + } + } + return results; +} + +Traditional2SimplifiedPrivate::Traditional2SimplifiedPrivate(Traditional2Simplified *parent) : q(parent) +{ +} + +Traditional2SimplifiedPrivate::~Traditional2SimplifiedPrivate() +{ +} + +Traditional2Simplified * Traditional2Simplified::getInstance() +{ + call_once(g_Traditional2SimplifiedSingleFlag, []() { + g_Traditional2SimplifiedManager = new Traditional2Simplified; + }); + return g_Traditional2SimplifiedManager; +} + +bool Traditional2Simplified::isTraditional(string &oneWord) +{ + return d->isTraditional(oneWord); +} + +string Traditional2Simplified::getResults(string words) +{ + return d->getResults(words); +} + +Traditional2Simplified::Traditional2Simplified() : d(new Traditional2SimplifiedPrivate) +{ +} diff --git a/libchinese-segmentation/Traditional-to-Simplified.h b/libchinese-segmentation/Traditional-to-Simplified.h new file mode 100644 index 0000000..560c72f --- /dev/null +++ b/libchinese-segmentation/Traditional-to-Simplified.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: jixiaoxu + * + */ + +#ifndef Traditional2Simplified_H +#define Traditional2Simplified_H + +#include +#include +#define TRADITIONAL_CHINESE_SIMPLIFIED_EXPORT Q_DECL_IMPORT + +using namespace std; + +class Traditional2SimplifiedPrivate; +class TRADITIONAL_CHINESE_SIMPLIFIED_EXPORT Traditional2Simplified +{ +public: + static Traditional2Simplified * getInstance(); + +public: + /** + * @brief Traditional2Simplified::isMultiTone 判断是否为繁体字,是则返回true + * @param oneWord 要判断的字 + * @return bool 不是返回false + */ + bool isTraditional(string &oneWord); + + /** + * @brief Traditional2Simplified::getResults 转换某个字/词/句的繁体字 + * @param words 要转换为简体中文的字/词/句 + * @return words 的简体中文结果 + */ + string getResults(string words); + +protected: + Traditional2Simplified(); + ~Traditional2Simplified(); + Traditional2Simplified(const Traditional2Simplified&) = delete; + Traditional2Simplified& operator =(const Traditional2Simplified&) = delete; +private: + static Traditional2Simplified *g_Traditional2SimplifiedManager; + Traditional2SimplifiedPrivate *d = nullptr; +}; + +#endif // PINYINMANAGER_H diff --git a/libchinese-segmentation/chinese-segmentation-config.cmake.in b/libchinese-segmentation/chinese-segmentation-config.cmake.in new file mode 100644 index 0000000..d4fb4d4 --- /dev/null +++ b/libchinese-segmentation/chinese-segmentation-config.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(Qt@QT_VERSION_MAJOR@Core "@REQUIRED_QT_VERSION@") +if(TARGET Qt6::Core) + find_dependency(Qt6Core5Compat @REQUIRED_QT_VERSION@) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/chinese-segmentation-targets.cmake") \ No newline at end of file diff --git a/libchinese-segmentation/chinese-segmentation-private.h b/libchinese-segmentation/chinese-segmentation-private.h index 3214dff..45c9836 100644 --- a/libchinese-segmentation/chinese-segmentation-private.h +++ b/libchinese-segmentation/chinese-segmentation-private.h @@ -11,6 +11,7 @@ public: explicit ChineseSegmentationPrivate(ChineseSegmentation *parent = nullptr); ~ChineseSegmentationPrivate(); vector callSegment(const string& sentence); + vector callSegment(QString& sentence); vector callMixSegmentCutStr(const string& sentence); vector callMixSegmentCutWord(const string& sentence); diff --git a/libchinese-segmentation/chinese-segmentation.cpp b/libchinese-segmentation/chinese-segmentation.cpp index caeaf32..0e0a924 100644 --- a/libchinese-segmentation/chinese-segmentation.cpp +++ b/libchinese-segmentation/chinese-segmentation.cpp @@ -24,10 +24,10 @@ ChineseSegmentationPrivate::ChineseSegmentationPrivate(ChineseSegmentation *parent) : q(parent) { //const char * const DICT_PATH = "/usr/share/ukui-search/res/dict/jieba.dict.utf8"; - const char * const HMM_PATH = "/usr/share/ukui-search/res/dict/hmm_model.utf8"; + const char * const HMM_PATH = DICT_INSTALL_PATH"/hmm_model.utf8"; //const char * const USER_DICT_PATH = "/usr/share/ukui-search/res/dict/user.dict.utf8"; //const char * const IDF_PATH = "/usr/share/ukui-search/res/dict/idf.utf8"; - const char * const STOP_WORD_PATH = "/usr/share/ukui-search/res/dict/stop_words.utf8"; + const char * const STOP_WORD_PATH = DICT_INSTALL_PATH"/stop_words.utf8"; m_jieba = new cppjieba::Jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, @@ -51,6 +51,17 @@ vector ChineseSegmentationPrivate::callSegment(const string &sentence) } +vector ChineseSegmentationPrivate::callSegment(QString &sentence) { + //'\xEF\xBC\x8C' is "," "\xE3\x80\x82" is "。" use three " " to replace ,to ensure the offset info. + sentence = sentence.replace("\t", " ").replace("\xEF\xBC\x8C", " ").replace("\xE3\x80\x82", " "); + const size_t topk = -1; + vector keywordres; + ChineseSegmentationPrivate::m_jieba->extractor.Extract(sentence.left(20480000).toStdString(), keywordres, topk); + + return keywordres; + +} + vector ChineseSegmentationPrivate::callMixSegmentCutStr(const string &sentence) { vector keywordres; @@ -117,6 +128,11 @@ vector ChineseSegmentation::callSegment(const string &sentence) return d->callSegment(sentence); } +vector ChineseSegmentation::callSegment(QString &sentence) +{ + return d->callSegment(sentence); +} + vector ChineseSegmentation::callMixSegmentCutStr(const string &sentence) { return d->callMixSegmentCutStr(sentence); diff --git a/libchinese-segmentation/chinese-segmentation.h b/libchinese-segmentation/chinese-segmentation.h index c8c7fb2..3b81cc1 100644 --- a/libchinese-segmentation/chinese-segmentation.h +++ b/libchinese-segmentation/chinese-segmentation.h @@ -21,6 +21,7 @@ #ifndef CHINESESEGMENTATION_H #define CHINESESEGMENTATION_H +#include #include "libchinese-segmentation_global.h" #include "common-struct.h" @@ -37,6 +38,7 @@ public: * @return vector 存放提取后关键词的信息的容器 */ vector callSegment(const string &sentence); + vector callSegment(QString &sentence); /** * @brief ChineseSegmentation::callMixSegmentCutStr diff --git a/libchinese-segmentation/chinese-segmentation.pc.in b/libchinese-segmentation/chinese-segmentation.pc.in new file mode 100644 index 0000000..9b65864 --- /dev/null +++ b/libchinese-segmentation/chinese-segmentation.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib/@CMAKE_LIBRARY_ARCHITECTURE@ +includedir=${prefix}/include/chinese-segmentation + +Name: chinese-segmentation +Description: Chinese-segmentation header files +URL: https://www.ukui.org/ +Version: @VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lchinese-segmentation \ No newline at end of file diff --git a/libchinese-segmentation/cppjieba/idf-trie/idf-trie.cpp b/libchinese-segmentation/cppjieba/idf-trie/idf-trie.cpp index 17d141e..feac716 100644 --- a/libchinese-segmentation/cppjieba/idf-trie/idf-trie.cpp +++ b/libchinese-segmentation/cppjieba/idf-trie/idf-trie.cpp @@ -78,8 +78,7 @@ void IdfTrie::LoadSourceFile(const string &dat_cache_file, const string &md5) close(fd); assert((size_t)write_bytes == sizeof(IdfCacheFileHeader) + offset + this->GetDataTrieTotalSize()); - const auto rename_ret = rename(tmp_filepath.c_str(), dat_cache_file.c_str()); - assert(0 == rename_ret); + tryRename(tmp_filepath, dat_cache_file); } double IdfTrie::Find(const string &key) const diff --git a/libchinese-segmentation/cppjieba/idf-trie/idf-trie.h b/libchinese-segmentation/cppjieba/idf-trie/idf-trie.h index edf2471..e4bf9a0 100644 --- a/libchinese-segmentation/cppjieba/idf-trie/idf-trie.h +++ b/libchinese-segmentation/cppjieba/idf-trie/idf-trie.h @@ -22,7 +22,7 @@ #include "storage-base.hpp" -const char * const IDF_DICT_PATH = "/usr/share/ukui-search/res/dict/idf.utf8"; +const char * const IDF_DICT_PATH = DICT_INSTALL_PATH"/idf.utf8"; struct IdfCacheFileHeader : CacheFileHeaderBase { diff --git a/libchinese-segmentation/cppjieba/limonp/Md5.hpp b/libchinese-segmentation/cppjieba/limonp/Md5.hpp index db83e97..7c9caf9 100644 --- a/libchinese-segmentation/cppjieba/limonp/Md5.hpp +++ b/libchinese-segmentation/cppjieba/limonp/Md5.hpp @@ -1,33 +1,33 @@ -/*************************************************************************** -*Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991 -* 2020, KylinSoft Co., Ltd. -*All rights reserved. -* -*License to copy and use this software is granted provided that it -*is identified as the "RSA Data Security, Inc. MD5 Message-Digest -*Algorithm" in all material mentioning or referencing this software -*or this function. -* -*License is also granted to make and use derivative works provided -*that such works are identified as "derived from the RSA Data -*Security, Inc. MD5 Message-Digest Algorithm" in all material -*mentioning or referencing the derived work. -* -*RSA Data Security, Inc. makes no representations concerning either -*the merchantability of this software or the suitability of this -*software for any particular purpose. It is provided "as is" -*without express or implied warranty of any kind. -* -*These notices must be retained in any copies of any part of this -*documentation and/or software. -* -* -* -*The original md5 implementation avoids external libraries. -*This version has dependency on stdio.h for file input and -*string.h for memcpy. -* -***************************************************************************/ +/**************************************************************************** +**Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991 +** 2020, KylinSoft Co., Ltd. +**All rights reserved. +** +**License to copy and use this software is granted provided that it +**is identified as the "RSA Data Security, Inc. MD5 Message-Digest +**Algorithm" in all material mentioning or referencing this software +**or this function. +** +**License is also granted to make and use derivative works provided +**that such works are identified as "derived from the RSA Data +**Security, Inc. MD5 Message-Digest Algorithm" in all material +**mentioning or referencing the derived work. +** +**RSA Data Security, Inc. makes no representations concerning either +**the merchantability of this software or the suitability of this +**software for any particular purpose. It is provided "as is" +**without express or implied warranty of any kind. +** +**These notices must be retained in any copies of any part of this +**documentation and/or software. +** +** +** +**The original md5 implementation avoids external libraries. +**This version has dependency on stdio.h for file input and +**string.h for memcpy. +** +****************************************************************************/ #ifndef __MD5_H__ #define __MD5_H__ diff --git a/libchinese-segmentation/cppjieba/segment-trie/segment-trie.cpp b/libchinese-segmentation/cppjieba/segment-trie/segment-trie.cpp index 5d9e1ff..894eaa9 100644 --- a/libchinese-segmentation/cppjieba/segment-trie/segment-trie.cpp +++ b/libchinese-segmentation/cppjieba/segment-trie/segment-trie.cpp @@ -63,8 +63,7 @@ void DictTrie::LoadSourceFile(const string &dat_cache_file, const string &md5) close(fd); assert((size_t)write_bytes == sizeof(DictCacheFileHeader) + offset + this->GetDataTrieTotalSize()); - const auto rename_ret = rename(tmp_filepath.c_str(), dat_cache_file.c_str()); - assert(0 == rename_ret); + tryRename(tmp_filepath, dat_cache_file); } const DatMemElem * DictTrie::Find(const string &key) const diff --git a/libchinese-segmentation/cppjieba/segment-trie/segment-trie.h b/libchinese-segmentation/cppjieba/segment-trie/segment-trie.h index 0acd999..79796e1 100644 --- a/libchinese-segmentation/cppjieba/segment-trie/segment-trie.h +++ b/libchinese-segmentation/cppjieba/segment-trie/segment-trie.h @@ -25,8 +25,8 @@ using namespace cppjieba; -const char * const DICT_PATH = "/usr/share/ukui-search/res/dict/jieba.dict.utf8"; -const char * const USER_DICT_PATH = "/usr/share/ukui-search/res/dict/user.dict.utf8"; +const char * const DICT_PATH = DICT_INSTALL_PATH"/jieba.dict.utf8"; +const char * const USER_DICT_PATH = DICT_INSTALL_PATH"/user.dict.utf8"; struct DictCacheFileHeader : CacheFileHeaderBase { diff --git a/libchinese-segmentation/libchinese-segmentation.pro b/libchinese-segmentation/libchinese-segmentation.pro index f0aee07..3dc695f 100644 --- a/libchinese-segmentation/libchinese-segmentation.pro +++ b/libchinese-segmentation/libchinese-segmentation.pro @@ -23,13 +23,15 @@ QMAKE_CXXFLAGS += -execution-charset:utf-8 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 include(cppjieba/cppjieba.pri) include(pinyin4cpp/pinyin4cpp.pri) +include(Traditional-Chinese-Simplified-conversion/Traditional2Simplified.pri) include(storage-base/storage-base-cedar.pri) #LIBS += -L/usr/local/lib/libjemalloc -ljemalloc SOURCES += \ chinese-segmentation.cpp \ - hanzi-to-pinyin.cpp + hanzi-to-pinyin.cpp \ + Traditional-to-Simplified.cpp HEADERS += \ chinese-segmentation-private.h \ @@ -37,14 +39,19 @@ HEADERS += \ common-struct.h \ hanzi-to-pinyin-private.h \ hanzi-to-pinyin.h \ + Traditional-to-Simplified-private.h \ + Traditional-to-Simplified.h \ pinyin4cpp-common.h \ libchinese-segmentation_global.h +DICT_INSTALL_PATH = /usr/share/chinese-segmentation/res/dict +DEFINES += DICT_INSTALL_PATH='\\"$${DICT_INSTALL_PATH}\\"' -dict_files.path = /usr/share/ukui-search/res/dict/ +dict_files.path = DICT_INSTALL_PATH dict_files.files = $$PWD/dict/*.utf8\ dict_files.files += $$PWD/dict/pos_dict/*.utf8\ dict_files.files += $$PWD/dict/*.txt\ -dict_files.files += $$PWD/pinyin4cpp/dict/*.txt +dict_files.files += $$PWD/pinyin4cpp/dict/*.txt\ +dict_files.files += $$PWD/Traditional-Chinese-Simplified-conversion/dict/*.txt INSTALLS += \ dict_files \ @@ -57,13 +64,13 @@ unix { QMAKE_PKGCONFIG_VERSION = $$VERSION QMAKE_PKGCONFIG_LIBDIR = $$target.path QMAKE_PKGCONFIG_DESTDIR = pkgconfig - QMAKE_PKGCONFIG_INCDIR = /usr/include/chinese-seg - QMAKE_PKGCONFIG_CFLAGS += -I/usr/include/chinese-seg + QMAKE_PKGCONFIG_INCDIR = /usr/include/chinese-segmentation + QMAKE_PKGCONFIG_CFLAGS += -I/usr/include/chinese-segmentation !isEmpty(target.path): INSTALLS += target - header.path = /usr/include/chinese-seg - header.files += chinese-segmentation.h libchinese-segmentation_global.h common-struct.h hanzi-to-pinyin.h pinyin4cpp-common.h + header.path = /usr/include/chinese-segmentation + header.files += chinese-segmentation.h libchinese-segmentation_global.h common-struct.h hanzi-to-pinyin.h pinyin4cpp-common.h Traditional-to-Simplified.h header.files += development-files/header-files/* # headercppjieba.path = /usr/include/chinese-seg/cppjieba/ # headercppjieba.files = cppjieba/* diff --git a/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.cpp b/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.cpp index 1746bf8..7a78534 100644 --- a/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.cpp +++ b/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.cpp @@ -75,8 +75,7 @@ void Pinyin4cppTrie::LoadSourceFile(const string &dat_cache_file, const string & close(fd); assert((size_t)write_bytes == sizeof(CacheFileHeaderBase) + offset + this->GetDataTrieTotalSize()); - const auto rename_ret = rename(tmp_filepath.c_str(), dat_cache_file.c_str()); - assert(0 == rename_ret); + tryRename(tmp_filepath, dat_cache_file); } string Pinyin4cppTrie::Find(const string &key) diff --git a/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.h b/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.h index 21eebe3..61d5969 100644 --- a/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.h +++ b/libchinese-segmentation/pinyin4cpp/pinyin4cpp-trie.h @@ -22,8 +22,8 @@ #include "storage-base.hpp" -const char * const SINGLE_WORD_PINYIN_PATH = "/usr/share/ukui-search/res/dict/singleWordPinyin.txt"; -const char * const WORDS_PINYIN_PATH = "/usr/share/ukui-search/res/dict/wordsPinyin.txt"; +const char * const SINGLE_WORD_PINYIN_PATH = DICT_INSTALL_PATH"/singleWordPinyin.txt"; +const char * const WORDS_PINYIN_PATH = DICT_INSTALL_PATH"/wordsPinyin.txt"; class Pinyin4cppTrie : public StorageBase { diff --git a/libchinese-segmentation/storage-base/storage-base.cpp b/libchinese-segmentation/storage-base/storage-base.cpp index 3ca836b..1ce34ff 100644 --- a/libchinese-segmentation/storage-base/storage-base.cpp +++ b/libchinese-segmentation/storage-base/storage-base.cpp @@ -54,9 +54,9 @@ void StorageBase::Init() template string StorageBase::Find(const string &key) { - int result = m_double_array_data_trie->exactMatchSearch(key.c_str(), key.size()); + int result = m_double_array_data_trie->template exactMatchSearch(key.c_str(), key.size()); if (result < 0) - return string(); + return {}; return string(&m_elements_ptr[result]); } diff --git a/libchinese-segmentation/storage-base/storage-base.hpp b/libchinese-segmentation/storage-base/storage-base.hpp index c85f5d6..764b6d3 100644 --- a/libchinese-segmentation/storage-base/storage-base.hpp +++ b/libchinese-segmentation/storage-base/storage-base.hpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "Md5.hpp" #include "StringUtil.hpp" //#define USE_DARTS @@ -63,6 +65,19 @@ inline string CalcFileListMD5(const vector &files_list, int & file_size_ return string(md5.digestChars); } +inline bool isFileExist(const string filePath) { + ifstream infile(filePath); + return infile.good(); +} + +inline void tryRename(string tmpName, string name) { + if (0 != rename(tmpName.c_str(), name.c_str())) { + if (isFileExist(name)) { + remove(tmpName.c_str()); + } + } +} + struct CacheFileHeaderBase { //todo 字节对齐 char md5_hex[32] = {}; uint32_t elements_num = 0; diff --git a/libchinese-segmentation/test/CMakeLists.txt b/libchinese-segmentation/test/CMakeLists.txt new file mode 100644 index 0000000..bcd89b2 --- /dev/null +++ b/libchinese-segmentation/test/CMakeLists.txt @@ -0,0 +1,19 @@ +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Widgets REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Widgets REQUIRED) +add_executable(test + main.cpp + mainwindow.cpp + mainwindow.h + mainwindow.ui + ) +target_include_directories( test PRIVATE + ../) +target_link_libraries(test PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets + chinese-segmentation + ) diff --git a/libchinese-segmentation/test/mainwindow.cpp b/libchinese-segmentation/test/mainwindow.cpp index a8a2022..c2b8bd0 100644 --- a/libchinese-segmentation/test/mainwindow.cpp +++ b/libchinese-segmentation/test/mainwindow.cpp @@ -1,7 +1,8 @@ #include "mainwindow.h" #include "ui_mainwindow.h" -#include -#include +#include "hanzi-to-pinyin.h" +#include "chinese-segmentation.h" +#include "Traditional-to-Simplified.h" #include #include #include @@ -79,7 +80,7 @@ void MainWindow::initconnections() ui->lineEdit_4->setText(list.join(" ")); qDebug() << "result:" << list.join(" "); - vector result = ChineseSegmentation::getInstance()->callSegment(ui->lineEdit_2->text().toStdString()); + vector result = ChineseSegmentation::getInstance()->callSegment(text.toStdString()); list.clear(); for (auto &info:result) { @@ -87,6 +88,9 @@ void MainWindow::initconnections() } ui->lineEdit_6->setText(list.join("/")); + string simplified = Traditional2Simplified::getInstance()->getResults(text.toStdString()); + + ui->lineEdit_7->setText(QString().fromStdString(simplified)); }); } diff --git a/libchinese-segmentation/test/mainwindow.ui b/libchinese-segmentation/test/mainwindow.ui index c00d060..fd98541 100644 --- a/libchinese-segmentation/test/mainwindow.ui +++ b/libchinese-segmentation/test/mainwindow.ui @@ -27,61 +27,6 @@ 点击开始 - - - - 40 - 20 - 91 - 31 - - - - 输入文字: - - - true - - - - - - 40 - 70 - 711 - 41 - - - - - - - 40 - 310 - 121 - 31 - - - - 拼音转换结果: - - - true - - - - - - 40 - 360 - 711 - 41 - - - - true - - @@ -140,28 +85,77 @@ 无拼音数据原数据返回 - + 40 - 160 - 113 - 31 - - - - 分词结果: - - - - - - 40 - 220 + 20 711 - 41 + 391 + + + + + 输入文字: + + + true + + + + + + + + + + 分词结果: + + + + + + + + + + 拼音转换结果: + + + true + + + + + + + true + + + + + + + 繁简转换结果: + + + true + + + + + + + + + + true + + + + @@ -170,7 +164,7 @@ 0 0 800 - 28 + 29 diff --git a/libsearch/CMakeLists.txt b/libsearch/CMakeLists.txt new file mode 100644 index 0000000..78f0d62 --- /dev/null +++ b/libsearch/CMakeLists.txt @@ -0,0 +1,215 @@ +set(VERSION_MAJOR 2) +set(VERSION_MINOR 3) +set(VERSION_MICRO 0) +set(LIBUKUI_SEARCH_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus Widgets Xml Concurrent Sql LinguistTools REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus Widgets Xml Concurrent Sql LinguistTools REQUIRED) +find_package(PkgConfig REQUIRED) +find_package(KF5WindowSystem) +find_package(qt5xdg) + +set(LIBUKUI_SEARCH_EXTERNAL_LIBS "") +set(LIBUKUI_SEARCH_PC_PKGS + xapian-core + gio-2.0 + glib-2.0 + gio-unix-2.0 + gsettings-qt + poppler-qt5 + kysdk-qtwidgets + lept + uchardet + tesseract) + +foreach(PC_LIB IN ITEMS ${LIBUKUI_SEARCH_PC_PKGS}) + pkg_check_modules(${PC_LIB} REQUIRED IMPORTED_TARGET ${PC_LIB}) + if(${${PC_LIB}_FOUND}) + include_directories(${${PC_LIB}_INCLUDE_DIRS}) + link_directories(${${PC_LIB}_LIBRARY_DIRS}) + list(APPEND LIBUKUI_SEARCH_EXTERNAL_LIBS PkgConfig::${PC_LIB}) + endif() +endforeach() + +set(LIBUKUI_SEARCH_SRC + appdata/app-info-dbus-argument.h + appdata/app-info-table.cpp appdata/app-info-table.h + appdata/app-info-table-private.h + appdata/application-info.cpp appdata/application-info.h + appdata/application-property.h + appdata/application-property-helper.cpp appdata/application-property-helper.h + appsearch/app-search-plugin.cpp appsearch/app-search-plugin.h + common.h + dirwatcher/dir-watcher.cpp dirwatcher/dir-watcher.h + file-utils.cpp file-utils.h + filesystemwatcher/file-system-watcher.cpp filesystemwatcher/file-system-watcher.h + filesystemwatcher/file-system-watcher-private.h + global-settings.cpp global-settings.h + global-settings-private.h + gobject-template.cpp gobject-template.h + index/basic-indexer.cpp index/basic-indexer.h + index/batch-indexer.cpp index/batch-indexer.h + index/compatible-define.h + index/database.cpp index/database.h + index/document.cpp index/document.h + index/file-content-indexer.cpp index/file-content-indexer.h + index/file-indexer-config.cpp index/file-indexer-config.h + index/file-reader.cpp index/file-reader.h + index/file-search-plugin.cpp index/file-search-plugin.h + index/file-watcher.cpp index/file-watcher.h + index/index-scheduler.cpp index/index-scheduler.h + index/index-status-recorder.cpp index/index-status-recorder.h + index/index-updater.cpp index/index-updater.h + index/monitor.cpp index/monitor.h + index/ocrobject.cpp index/ocrobject.h + index/pending-file.cpp index/pending-file.h + index/pending-file-queue.cpp index/pending-file-queue.h + index/search-manager.cpp index/search-manager.h + index/ukui-search-qdbus.cpp index/ukui-search-qdbus.h + index/writable-database.cpp index/writable-database.h + libsearch.cpp libsearch.h + libsearch_global.h + log-utils.cpp log-utils.h + notesearch/note-search-plugin.cpp notesearch/note-search-plugin.h + parser/binary-parser.cpp parser/binary-parser.h + parser/common.h + plugininterface/action-label.cpp plugininterface/action-label.h + plugininterface/action-transmiter.cpp plugininterface/action-transmiter.h + plugininterface/data-queue.h + plugininterface/plugin-iface.h + plugininterface/search-plugin-iface.cpp plugininterface/search-plugin-iface.h + plugininterface/search-task-plugin-iface.h + plugininterface/separation-line.cpp plugininterface/separation-line.h + pluginmanage/plugin-info.h + pluginmanage/plugin-manager.cpp pluginmanage/plugin-manager.h + pluginmanage/search-plugin-manager.cpp pluginmanage/search-plugin-manager.h + pluginmanage/search-task-plugin-manager.cpp pluginmanage/search-task-plugin-manager.h + searchinterface/result-item.cpp searchinterface/result-item.h + searchinterface/search-controller.cpp searchinterface/search-controller.h + searchinterface/search-result-property.h + searchinterface/search-result-property-info.cpp searchinterface/search-result-property-info.h + searchinterface/searchtasks/app-search-task.cpp searchinterface/searchtasks/app-search-task.h + searchinterface/searchtasks/file-content-search-task.cpp searchinterface/searchtasks/file-content-search-task.h + searchinterface/searchtasks/file-search-task.cpp searchinterface/searchtasks/file-search-task.h + searchinterface/ukui-search-task.cpp searchinterface/ukui-search-task.h + settingsearch/settings-search-plugin.cpp settingsearch/settings-search-plugin.h + websearch/web-search-plugin.cpp websearch/web-search-plugin.h + icon-loader.cpp icon-loader.h + ) +set(QRC_FILES resource1.qrc) +file(GLOB TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../translations/libukui-search/*.ts) +set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION ${CMAKE_BINARY_DIR}/libsearch/.qm) +qt5_create_translation(QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${TS_FILES}) + +add_library(libukui-search SHARED + ${LIBUKUI_SEARCH_SRC} + ${QRC_FILES} + ${QM_FILES} +) +set(HEADERS + libsearch_global.h + plugininterface/action-label.h + plugininterface/action-transmiter.h + plugininterface/data-queue.h + plugininterface/plugin-iface.h + plugininterface/search-plugin-iface.h + plugininterface/search-task-plugin-iface.h + plugininterface/separation-line.h + appdata/application-info.h + appdata/application-property.h + appdata/application-property-helper.h + searchinterface/ukui-search-task.h + searchinterface/result-item.h + searchinterface/search-result-property.h + filesystemwatcher/file-system-watcher.h + development-files/header-files/UkuiSearchTask + development-files/header-files/UkuiSearchPluginIface + development-files/header-files/FileSystemWatcher + ) + +include_directories( + ../libchinese-segmentation + appdata + appsearch + dirwatcher + filesystemwatcher + index + notesearch + parser + plugininterface + pluginmanage + searchinterface + searchinterface/searchtasks + settingsearch + websearch +) + +target_compile_definitions(libukui-search PRIVATE + PLUGIN_INSTALL_DIRS="/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/ukui-search-plugins" + QT_NO_KEYWORDS + ) + +target_link_libraries(libukui-search PUBLIC + KF5::WindowSystem + Qt5Xdg + Qt${QT_VERSION_MAJOR}::Concurrent + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Sql + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Xml + chinese-segmentation + quazip5 + tesseract + uchardet + xapian + ${LIBUKUI_SEARCH_EXTERNAL_LIBS} + ) + +include(CMakePackageConfigHelpers) +set(CMAKE_CONFIG_INSTALL_DIR "/usr/share/cmake/ukui-search") +set(HEADERS_INSTALL_DIR /usr/include/ukui-search) +set(PC_INSTALL_DIR "/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig") + +target_include_directories(libukui-search PUBLIC $) + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/ukui-search-config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/ukui-search-config.cmake" + INSTALL_DESTINATION ${CMAKE_CONFIG_INSTALL_DIR}) +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/ukui-search-config-version.cmake + VERSION ${LIBUKUI_SEARCH_VERSION} + COMPATIBILITY SameMajorVersion +) +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/ukui-search.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/ukui-search.pc" + INSTALL_DESTINATION ${PC_INSTALL_DIR}) + +set_target_properties(libukui-search PROPERTIES + VERSION ${LIBUKUI_SEARCH_VERSION} + SOVERSION ${VERSION_MAJOR} + OUTPUT_NAME ukui-search + ) +install(TARGETS libukui-search + EXPORT libukui-search + PUBLIC_HEADER DESTINATION ${HEADERS_INSTALL_DIR} + LIBRARY DESTINATION /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} + ) +install(EXPORT libukui-search + FILE ukui-search-targets.cmake + DESTINATION ${CMAKE_CONFIG_INSTALL_DIR}) +install(FILES ${QM_FILES} DESTINATION /usr/share/ukui-search/translations/libukui-search) + +install(FILES ${HEADERS} DESTINATION ${HEADERS_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/ukui-search.pc DESTINATION ${PC_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ukui-search-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ukui-search-config-version.cmake + DESTINATION ${CMAKE_CONFIG_INSTALL_DIR}) \ No newline at end of file diff --git a/libsearch/app-db-common.h b/libsearch/app-db-common.h deleted file mode 100644 index 00a1ee0..0000000 --- a/libsearch/app-db-common.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef APPDBCOMMON_H -#define APPDBCOMMON_H - -#include - -namespace UkuiSearch { - -#define APP_DATABASE_PATH QDir::homePath()+"/.config/org.ukui/ukui-search/appdata/" -#define APP_DATABASE_NAME "app-info.db" - -struct AppInfoResult -{ -public: - QString desktopPath; - QString iconName; - QString appLocalName; - QString firstLetter; - QString category; - int top; - int favorite; - int launchTimes; - int lock; - - AppInfoResult() : top(0), favorite(0), launchTimes(0), lock(0) {} -}; -} - -Q_DECLARE_METATYPE(UkuiSearch::AppInfoResult) - -#endif // APPDBCOMMON_H diff --git a/libsearch/app-info-dbus-argument.h b/libsearch/app-info-dbus-argument.h deleted file mode 100644 index 161e5d7..0000000 --- a/libsearch/app-info-dbus-argument.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef APPINFODBUSARGUMENT_H -#define APPINFODBUSARGUMENT_H - -#include -#include "app-db-common.h" - -namespace UkuiSearch { - - QDBusArgument &operator << (QDBusArgument &argument, const AppInfoResult &infoResult) - { - argument.beginStructure(); - argument << infoResult.desktopPath << infoResult.iconName << infoResult.appLocalName << infoResult.firstLetter - << infoResult.category << infoResult.top << infoResult.favorite << infoResult.launchTimes << infoResult.lock; - argument.endStructure(); - return argument; - } - - const QDBusArgument &operator >> (const QDBusArgument &argument, AppInfoResult &infoResult) - { - argument.beginStructure(); - argument >> infoResult.desktopPath >> infoResult.iconName >> infoResult.appLocalName >> infoResult.firstLetter - >> infoResult.category >> infoResult.top >> infoResult.favorite >> infoResult.launchTimes >> infoResult.lock; - - argument.endStructure(); - return argument; - } - -} - - -#endif // APPINFODBUSARGUMENT_H diff --git a/libsearch/appdata/app-info-dbus-argument.h b/libsearch/appdata/app-info-dbus-argument.h new file mode 100644 index 0000000..a94a09f --- /dev/null +++ b/libsearch/appdata/app-info-dbus-argument.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef APPINFODBUSARGUMENT_H +#define APPINFODBUSARGUMENT_H + +#include +#include "application-property.h" + +using namespace UkuiSearch; +QDBusArgument &operator << (QDBusArgument &argument, const UkuiSearch::ApplicationProperty::Property &property) { + argument.beginStructure(); + argument << static_cast(property); + argument.endStructure(); + return argument; +} + +const QDBusArgument &operator >> (const QDBusArgument &argument, UkuiSearch::ApplicationProperty::Property &property) { + int value; + argument.beginStructure(); + argument >> value; + argument.endStructure(); + property = static_cast(value); + return argument; +} + +QDBusArgument &operator << (QDBusArgument &argument, const ApplicationPropertyMap &appPropertyInfo) +{ + argument.beginMap(/*qMetaTypeId()*/QVariant::Int, qMetaTypeId()); + for (auto i = appPropertyInfo.constBegin(); i != appPropertyInfo.constEnd(); ++i) { + QDBusVariant dbusVariant(i.value()); + argument.beginMapEntry(); + argument << static_cast(i.key()) << dbusVariant; + argument.endMapEntry(); + } + argument.endMap(); + return argument; +} + +const QDBusArgument &operator >> (const QDBusArgument &argument, ApplicationPropertyMap &appPropertyInfo) +{ + argument.beginMap(); + while (!argument.atEnd()) { + int key; + QVariant value; + argument.beginMapEntry(); + argument >> key >> value; + argument.endMapEntry(); + appPropertyInfo.insert(static_cast(key), value); + } + argument.endMap(); + return argument; +} + +QDBusArgument &operator << (QDBusArgument &argument, const ApplicationInfoMap &appInfo) +{ + argument.beginMap(QVariant::String, qMetaTypeId()); + for (auto i = appInfo.constBegin(); i != appInfo.constEnd(); ++i) { + argument.beginMapEntry(); + argument << i.key() << i.value(); + argument.endMapEntry(); + } + argument.endMap(); + return argument; +} + +const QDBusArgument &operator >> (const QDBusArgument &argument, ApplicationInfoMap &appInfo) +{ + argument.beginMap(); + while (!argument.atEnd()) { + QString key; + ApplicationPropertyMap value; + argument.beginMapEntry(); + argument >> key >> value; + argument.endMapEntry(); + appInfo.insert(key, value); + } + argument.endMap(); + return argument; +} +#endif // APPINFODBUSARGUMENT_H diff --git a/libsearch/appdata/app-info-table-private.h b/libsearch/appdata/app-info-table-private.h index b842718..f74ead9 100644 --- a/libsearch/appdata/app-info-table-private.h +++ b/libsearch/appdata/app-info-table-private.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef APPINFOTABLEPRIVATE_H #define APPINFOTABLEPRIVATE_H @@ -11,51 +30,36 @@ namespace UkuiSearch { class AppInfoTablePrivate : public QObject { Q_OBJECT + friend class AppInfoTable; public: explicit AppInfoTablePrivate(AppInfoTable *parent = nullptr); AppInfoTablePrivate(AppInfoTablePrivate &) = delete; AppInfoTablePrivate &operator =(const AppInfoTablePrivate &) = delete; //设置应用的置顶和收藏 - void setAppFavoritesState(QString &desktopfp, int num); - void setAppTopState(QString &desktopfp, int num); - - //改变置顶和收藏应用位置 - bool changeFavoriteAppPos(const QString &desktopfp, int pos); - bool changeTopAppPos(const QString &desktopfp, int pos); - - //获取所有应用信息 - bool getAppInfoResults(QVector &appInfoResults); - - //获取单个应用的某个状态(锁定,置顶,打开状态,收藏) - bool getAppLockState(QString &desktopfp, size_t &num); - bool getAppTopState(QString &desktopfp, size_t &num); - bool getAppLaunchedState(QString &desktopfp, size_t &num); - bool getAppFavoriteState(QString &desktopfp, size_t &num); - bool getAppCategory(QString &desktopfp, QString &category); - - //添加快捷方式 - bool addAppShortcut2Desktop(QString &desktopfp); - bool addAppShortcut2Panel(QString &desktopfp); + void setAppFavoritesState(const QString &desktopfp); + void setAppFavoritesState(const QString &desktopfp, uint num); + void setAppTopState(const QString &desktopfp); + void setAppTopState(const QString &desktopfp, uint num); + void setAppLaunchedState(const QString &desktopFilePath, bool launched); //搜索接口 bool searchInstallApp(QString &keyWord, QStringList &installAppInfoRes); bool searchInstallApp(QStringList &keyWord, QStringList &installAppInfoRes); - //卸载应用 - bool uninstallApp(QString &desktopfp); //数据库错误信息 QString lastError(void) const; + //通过pid查找desktop文件 + bool tranPidToDesktopFp(uint pid, QString &desktopfp); + bool tranWinIdToDesktopFilePath(const QVariant &winId, QString &desktopfp); + bool desktopFilePathFromName(const QString &desktopFileName, QString &desktopFilePath); + //下面的接口都不外放,暂时没啥用 - bool setAppLaunchTimes(QString &desktopfp, size_t num); - bool updateAppLaunchTimes(QString &desktopfp); - bool setAppLockState(QString &desktopfp, size_t num); - bool getAllAppDesktopList(QStringList &list); - bool getFavoritesAppList(QStringList &list); - bool getTopAppList(QStringList &list); - bool getLaunchTimesAppList(QStringList &list); + bool setAppLaunchTimes(const QString &desktopfp, size_t num); + bool updateAppLaunchTimes(const QString &desktopfp); + bool setAppLockState(const QString &desktopfp, size_t num); private: ~AppInfoTablePrivate(); @@ -71,9 +75,10 @@ private: QString m_ConnectionName; public Q_SLOTS: - void sendAppDBItemsUpdate(QVector results); - void sendAppDBItemsAdd(QVector results); - void sendAppDBItemsDelete(QStringList desktopfps); + void sendAppDBItemsUpdate(ApplicationInfoMap results); + void sendAppDBItemsUpdateAll(QStringList desktopFilePaths); + void sendAppDBItemsAdd(QStringList desktopFilePaths); + void sendAppDBItemsDelete(QStringList desktopFilePaths); }; diff --git a/libsearch/appdata/app-info-table.cpp b/libsearch/appdata/app-info-table.cpp index 634f438..741e6c7 100644 --- a/libsearch/appdata/app-info-table.cpp +++ b/libsearch/appdata/app-info-table.cpp @@ -14,20 +14,24 @@ #include #include #include -#include -#include +#include +#include +#include using namespace UkuiSearch; +static std::once_flag flag; +static AppInfoTable *global_intance = nullptr; AppInfoTablePrivate::AppInfoTablePrivate(AppInfoTable *parent) : QObject(parent), q(parent), m_database(new QSqlDatabase()) { //dbus接收数据库信号 + qRegisterMetaType("ApplicationProperty::Property"); + qRegisterMetaType("ApplicationInfoMap"); + qRegisterMetaType("ApplicationPropertyMap"); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); - qRegisterMetaType("AppInfoResult"); - qRegisterMetaType>("QVector"); - - qDBusRegisterMetaType(); - qDBusRegisterMetaType>(); m_signalTransInterface = new QDBusInterface("com.ukui.search.appdb.service", "/org/ukui/search/appDataBase/signalTransformer", "org.ukui.search.signalTransformer"); @@ -36,8 +40,9 @@ AppInfoTablePrivate::AppInfoTablePrivate(AppInfoTable *parent) : QObject(parent) qCritical() << "Create privateDirWatcher Interface Failed Because: " << QDBusConnection::sessionBus().lastError(); return; } else { - connect(m_signalTransInterface, SIGNAL(appDBItemsAdd(QVector)), this, SLOT(sendAppDBItemsAdd(QVector))); - connect(m_signalTransInterface, SIGNAL(appDBItemsUpdate(QVector)), this, SLOT(sendAppDBItemsUpdate(QVector))); + connect(m_signalTransInterface, SIGNAL(appDBItemsUpdate(ApplicationInfoMap)), this, SLOT(sendAppDBItemsUpdate(ApplicationInfoMap))); + connect(m_signalTransInterface, SIGNAL(appDBItemsUpdateAll(QStringList)), this, SLOT(sendAppDBItemsUpdateAll(QStringList))); + connect(m_signalTransInterface, SIGNAL(appDBItemsAdd(QStringList)), this, SLOT(sendAppDBItemsAdd(QStringList))); connect(m_signalTransInterface, SIGNAL(appDBItemsDelete(QStringList)), this, SLOT(sendAppDBItemsDelete(QStringList))); } @@ -59,166 +64,33 @@ AppInfoTablePrivate::AppInfoTablePrivate(AppInfoTable *parent) : QObject(parent) } } -void AppInfoTablePrivate::setAppFavoritesState(QString &desktopfp, int num) +void AppInfoTablePrivate::setAppFavoritesState(const QString &desktopfp) +{ + m_appDBInterface->call("updateFavoritesState", desktopfp); +} + +void AppInfoTablePrivate::setAppFavoritesState(const QString &desktopfp, uint num) { m_appDBInterface->call("updateFavoritesState", desktopfp, num); } -void AppInfoTablePrivate::setAppTopState(QString &desktopfp, int num) +void AppInfoTablePrivate::setAppTopState(const QString &desktopfp) +{ + m_appDBInterface->call("updateTopState", desktopfp); +} + +void AppInfoTablePrivate::setAppTopState(const QString &desktopfp, uint num) { m_appDBInterface->call("updateTopState", desktopfp, num); } -bool AppInfoTablePrivate::changeFavoriteAppPos(const QString &desktopfp, int pos) +void AppInfoTablePrivate::setAppLaunchedState(const QString &desktopFilePath, bool launched) { - QDBusReply reply = m_appDBInterface->call("changeFavoriteAppPos", desktopfp, pos); - if (reply.isValid()) { - return reply.value(); - } else { - qDebug() << m_appDBInterface->lastError(); - return false; - } -} - -bool AppInfoTablePrivate::changeTopAppPos(const QString &desktopfp, int pos) -{ - QDBusReply reply = m_appDBInterface->call("changeTopAppPos", desktopfp, pos); - if (reply.isValid()) { - return reply.value(); - } else { - qDebug() << m_appDBInterface->lastError(); - return false; - } -} - -bool AppInfoTablePrivate::getAppInfoResults(QVector &appInfoResults) -{ - QDBusReply> reply = m_appDBInterface->call("getAppInfoResults"); - if (reply.isValid()) { - appInfoResults = reply.value(); - return true; - } else { - return false; - } -} - -bool AppInfoTablePrivate::getAppLockState(QString &desktopfp, size_t &num) -{ - QDBusReply reply = m_appDBInterface->call("getAppLockState", desktopfp); - if (!reply.isValid()) { - qWarning() << m_appDBInterface->lastError(); - return false; - } else { - num = reply.value(); - if (num == -1) { - qWarning() << "There's something wrong while using database"; - return false; - } - return true; - } -} - -bool AppInfoTablePrivate::getAppTopState(QString &desktopfp, size_t &num) -{ - QDBusReply reply = m_appDBInterface->call("getAppTopState", desktopfp); - if (!reply.isValid()) { - qWarning() << m_appDBInterface->lastError(); - return false; - } else { - num = reply.value(); - if (num == -1) { - qWarning() << "There's something wrong while using database"; - return false; - } - return true; - } -} - -bool AppInfoTablePrivate::getAppLaunchedState(QString &desktopfp, size_t &num) -{ - QDBusReply reply = m_appDBInterface->call("getAppLaunchedState", desktopfp); - if (!reply.isValid()) { - qWarning() << m_appDBInterface->lastError(); - return false; - } else { - num = reply.value(); - if (num == -1) { - qWarning() << "There's something wrong while using database"; - return false; - } - return true; - } -} - -bool AppInfoTablePrivate::getAppFavoriteState(QString &desktopfp, size_t &num) -{ - QDBusReply reply = m_appDBInterface->call("getAppFavoriteState", desktopfp); - if (!reply.isValid()) { - qWarning() << m_appDBInterface->lastError(); - return false; - } else { - num = reply.value(); - if (num == -1) { - qWarning() << "There's something wrong while using database"; - return false; - } - return true; - } -} - -bool AppInfoTablePrivate::getAppCategory(QString &desktopfp, QString &category) -{ - QDBusReply reply = m_appDBInterface->call("getAppCategory", desktopfp); - if (reply.isValid()) { - category = reply.value(); - return true; - } else { - qDebug() << m_appDBInterface->lastError(); - return false; - } -} - -bool AppInfoTablePrivate::addAppShortcut2Desktop(QString &desktopfp) -{ - bool res(true); - QString dirpath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - QFileInfo fileInfo(desktopfp); - QString desktopfn = fileInfo.fileName(); - QFile file(desktopfp); - QString newName = QString(dirpath + "/" + desktopfn); - if(file.copy(QString(dirpath + "/" + desktopfn))) { - QProcess process; - process.startDetached(QString("chmod a+x %1").arg(newName)); - } else { - res = false; - } - return res; -} - -bool AppInfoTablePrivate::addAppShortcut2Panel(QString &desktopfp) -{ - bool res(true); - QDBusInterface iface("com.ukui.panel.desktop", - "/", - "com.ukui.panel.desktop", - QDBusConnection::sessionBus()); - if(iface.isValid()) { - QDBusReply isExist = iface.call("CheckIfExist", desktopfp); - if(isExist) { - qWarning() << "Add shortcut to panel failed, because it is already existed!"; - } else { - QDBusReply ret = iface.call("AddToTaskbar", desktopfp); - if (ret.value()) { - qDebug() << "Add shortcut to panel success."; - } else { - qWarning() << "Add shortcut to panel failed, reply:" << ret.error(); - res = false; - } - } - } else { - res = false; - } - return res; + ApplicationInfoMap infoMap; + infoMap[desktopFilePath].insert(ApplicationProperty::Launched, launched); + QVariant var; + var.setValue(infoMap); + m_appDBInterface->call("setValue", var); } bool AppInfoTablePrivate::searchInstallApp(QString &keyWord, QStringList &installAppInfoRes) @@ -300,54 +172,48 @@ bool AppInfoTablePrivate::searchInstallApp(QStringList &keyWord, QStringList &in return res; } -bool AppInfoTablePrivate::uninstallApp(QString &desktopfp) -{ - bool res(false); - QString cmd = QString("kylin-uninstaller %1") - .arg(desktopfp.toLocal8Bit().data()); - res = QProcess::startDetached(cmd); - qDebug() << "kylin-uninstaller uninstall:" << cmd << res; - return res; - - /* - bool isOsReleaseUbuntu(false); - QFile file("/etc/os-release"); - if (file.open(QFile::ReadOnly)) { - QByteArray line = file.readLine(); - file.close(); - - if (QString(line).contains("Ubuntu")) { //目前已无效 - isOsReleaseUbuntu = true; - } - } - QString cmd; - QProcess process; - if (!isOsReleaseUbuntu) { - cmd = QString("kylin-uninstaller %1") - .arg(desktopfp.toLocal8Bit().data()); - res = QProcess::startDetached(cmd); - qDebug() << "kylin-uninstaller uninstall:" << cmd << res; - } else { - cmd = QString("dpkg -S " + desktopfp); - process.start("sh", QStringList() << "-c" << cmd); - process.waitForFinished(); - QString output = process.readAllStandardOutput().trimmed(); - QString packageName = output.split(":").at(0); - cmd = QString("kylin-installer -remove %0") - .arg(packageName.toLocal8Bit().data()); - res = QProcess::startDetached(cmd); - qDebug() << "dpkg -S uninstall:" << cmd << res; - } - return res; - */ -} - QString AppInfoTablePrivate::lastError() const { return m_database->lastError().text(); } -bool AppInfoTablePrivate::setAppLaunchTimes(QString &desktopfp, size_t num) +bool AppInfoTablePrivate::tranPidToDesktopFp(uint pid, QString &desktopfp) +{ + QDBusReply reply = m_appDBInterface->call("tranPidToDesktopFp", pid); + if (reply.isValid()) { + desktopfp = reply.value(); + return true; + } else { + qDebug() << m_appDBInterface->lastError(); + return false; + } +} + +bool AppInfoTablePrivate::tranWinIdToDesktopFilePath(const QVariant &winId, QString &desktopfp) +{ + QDBusReply reply = m_appDBInterface->call("tranWinIdToDesktopFilePath", QVariant::fromValue(QDBusVariant(winId))); + if (reply.isValid()) { + desktopfp = reply.value(); + return true; + } else { + qDebug() << m_appDBInterface->lastError(); + return false; + } +} + +bool AppInfoTablePrivate::desktopFilePathFromName(const QString &desktopFileName, QString &desktopFilePath) +{ + QDBusReply reply = m_appDBInterface->call("desktopFilePathFromName", desktopFileName); + if (reply.isValid()) { + desktopFilePath = reply.value(); + return true; + } else { + qDebug() << m_appDBInterface->lastError(); + return false; + } +} + +bool AppInfoTablePrivate::setAppLaunchTimes(const QString &desktopfp, size_t num) { bool res(true); if (m_database->transaction()) { @@ -373,7 +239,7 @@ bool AppInfoTablePrivate::setAppLaunchTimes(QString &desktopfp, size_t num) return res; } -bool AppInfoTablePrivate::updateAppLaunchTimes(QString &desktopfp) +bool AppInfoTablePrivate::updateAppLaunchTimes(const QString &desktopfp) { bool res(true); if (m_database->transaction()) { @@ -410,7 +276,7 @@ bool AppInfoTablePrivate::updateAppLaunchTimes(QString &desktopfp) return res; } -bool AppInfoTablePrivate::setAppLockState(QString &desktopfp, size_t num) +bool AppInfoTablePrivate::setAppLockState(const QString &desktopfp, size_t num) { bool res(true); if (m_database->transaction()) { @@ -435,94 +301,6 @@ bool AppInfoTablePrivate::setAppLockState(QString &desktopfp, size_t num) return res; } -bool AppInfoTablePrivate::getAllAppDesktopList(QStringList &list) -{ - bool res(true); - QSqlQuery sql(*m_database); - QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM APPINFO"); - - if (sql.exec(cmd)) { - while (sql.next()) { - list.append(sql.value(0).toString()); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError(); - res = false; - } - - return res; -} - -bool AppInfoTablePrivate::getFavoritesAppList(QStringList &list) -{ - bool res(true); - QSqlQuery sql(*m_database); - QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM APPINFO WHERE FAVORITES!=0 ORDER BY FAVORITES"); - if (sql.exec(cmd)) { - while (sql.next()) { - list.append(sql.value(0).toString()); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError(); - res = false; - } - return res; -} - -bool AppInfoTablePrivate::getTopAppList(QStringList &list) -{ - bool res(true); - QSqlQuery sql(*m_database); - QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM APPINFO WHERE TOP!=0 ORDER BY TOP"); - - if (sql.exec(cmd)) { - while (sql.next()) { - list.append(sql.value(0).toString()); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError(); - res = false; - } - - return res; -} - -bool AppInfoTablePrivate::getLaunchTimesAppList(QStringList &list) -{ - bool res(true); - if (m_database->transaction()) { - QSqlQuery sql(*m_database); - QSqlQuery sqlque(*m_database); - QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM APPINFO ORDER BY LAUNCH_TIMES"); - int count = 0; - if (sql.exec(cmd)) { - while (sql.next()) { - list.append(sql.value(0).toString()); - cmd = QString("UPDATE appInfo SET TOP=%1 WHERE DESKTOP_FILE_PATH='%2'") - .arg(++count) - .arg(sql.value(0).toString()); - if (!sqlque.exec(cmd)) { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError(); - res = false; - break; - } - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError(); - res = false; - } - if (!m_database->commit()) { - qWarning() << "Failed to commit !" << cmd; - m_database->rollback(); - res = false; - } - } else { - qWarning() << "Failed to start transaction mode!!!"; - res = false; - } - return res; -} - AppInfoTablePrivate::~AppInfoTablePrivate() { this->closeDataBase(); @@ -564,83 +342,228 @@ void AppInfoTablePrivate::closeDataBase() QSqlDatabase::removeDatabase(m_ConnectionName); } -void AppInfoTablePrivate::sendAppDBItemsUpdate(QVector results) +void AppInfoTablePrivate::sendAppDBItemsUpdate(ApplicationInfoMap results) { Q_EMIT q->appDBItems2BUpdate(results); } -void AppInfoTablePrivate::sendAppDBItemsAdd(QVector results) +void AppInfoTablePrivate::sendAppDBItemsUpdateAll(QStringList desktopFilePaths) { - Q_EMIT q->appDBItems2BAdd(results); + Q_EMIT q->appDBItems2BUpdateAll(desktopFilePaths); } -void AppInfoTablePrivate::sendAppDBItemsDelete(QStringList desktopfps) +void AppInfoTablePrivate::sendAppDBItemsAdd(QStringList desktopFilePaths) { - Q_EMIT q->appDBItems2BDelete(desktopfps); + Q_EMIT q->appDBItems2BAdd(desktopFilePaths); +} + +void AppInfoTablePrivate::sendAppDBItemsDelete(QStringList desktopFilePaths) +{ + Q_EMIT q->appDBItems2BDelete(desktopFilePaths); +} + +AppInfoTable *AppInfoTable::self() +{ + std::call_once(flag, [ & ] { + global_intance = new AppInfoTable(); + }); + return global_intance; } AppInfoTable::AppInfoTable(QObject *parent) : QObject(parent), d(new AppInfoTablePrivate(this)) { } -void AppInfoTable::setAppFavoritesState(QString &desktopfp, size_t num) +bool AppInfoTable::query(ApplicationPropertyMap &propertyMap, const QString &desktopFile, ApplicationProperties properties) +{ + QString field; + for(const ApplicationProperty::Property &pro : properties) { + field.append(ApplicationPropertyHelper(pro).dataBaseField() + ","); + } + field.remove(field.length() - 1, 1); + if(field.isEmpty()) { + return true; + } + QSqlQuery query(*d->m_database); + query.setForwardOnly(true); + query.prepare(QString("SELECT %0 FROM APPINFO WHERE DESKTOP_FILE_PATH=:desktopFile").arg(field)); + query.bindValue(":desktopFile", desktopFile); + if (!query.exec()) { + qWarning() << d->m_database->lastError() << query.lastError(); + return false; + } + while (query.next()) { + for(int i = 0; i< properties.size(); i++) { + propertyMap.insert(properties.at(i), query.value(i)); + } + } + return true; +} + +bool AppInfoTable::query(ApplicationInfoMap &infoMap, ApplicationProperties properties) +{ + QString field; + for(const ApplicationProperty::Property &pro : properties) { + field.append(ApplicationPropertyHelper(pro).dataBaseField() + ","); + } + if(!properties.contains(ApplicationProperty::Property::DesktopFilePath)) { + field.append(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField()); + } else if(!field.isEmpty()) { + field.remove(field.length() - 1, 1); + } + + QString sql = QString("SELECT %0 FROM APPINFO").arg(field); + QSqlQuery query(*d->m_database); + query.setForwardOnly(true); + + if (!query.exec(sql)) { + qWarning() << d->m_database->lastError() << sql; + return false; + } + while (query.next()) { + ApplicationPropertyMap propertyMap; + for(const ApplicationProperty::Property &pro : properties) { + propertyMap.insert(pro, query.value(ApplicationPropertyHelper(pro).dataBaseField())); + + } + infoMap.insert(query.value(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField()).toString(), propertyMap); + } + return true; +} + +bool AppInfoTable::query(ApplicationInfoMap &infoMap, ApplicationProperties properties, ApplicationPropertyMap restrictions) +{ + QString field; + for(const ApplicationProperty::Property &pro : properties) { + field.append(ApplicationPropertyHelper(pro).dataBaseField() + ","); + } + if(!properties.contains(ApplicationProperty::Property::DesktopFilePath)) { + field.append(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField()); + } else if(!field.isEmpty()) { + field.remove(field.length() - 1, 1); + } + + QString condition; + for (const ApplicationProperty::Property prop: restrictions.keys()) { + condition.append(ApplicationPropertyHelper(prop).dataBaseField() + "=? AND "); + } + condition = condition.left(condition.lastIndexOf(" AND ")); + + QSqlQuery query(*d->m_database); + query.setForwardOnly(true); + query.prepare(QString("SELECT %0 FROM APPINFO WHERE %1") + .arg(field) + .arg(condition)); + int i = 0; + for (const QVariant &conditionValue : restrictions) { + query.bindValue(i, conditionValue); + i++; + } + if (!query.exec()) { + qWarning() << d->m_database->lastError() << query.lastError(); + return false; + } + while (query.next()) { + ApplicationPropertyMap propertyMap; + for(const ApplicationProperty::Property &pro : properties) { + propertyMap.insert(pro, query.value(ApplicationPropertyHelper(pro).dataBaseField())); + + } + infoMap.insert(query.value(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField()).toString(), propertyMap); + } + return true; +} + +bool AppInfoTable::query(ApplicationInfoMap &infoMap, ApplicationProperties properties, const QStringList &keywords, ApplicationPropertyMap restrictions) +{ + QString field; + for(const ApplicationProperty::Property &pro : properties) { + field.append(ApplicationPropertyHelper(pro).dataBaseField() + ","); + } + if(!properties.contains(ApplicationProperty::Property::DesktopFilePath)) { + field.append(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField()); + } else if(!field.isEmpty()) { + field.remove(field.length() - 1, 1); + } + + QString condition; + for (const ApplicationProperty::Property prop: restrictions.keys()) { + condition.append(ApplicationPropertyHelper(prop).dataBaseField() + "=? AND "); + } + + QString keywordCondition; + for(const QString& keyword : keywords) { + if(keyword.size() < 2) { + keywordCondition.append("(ifnull(LOCAL_NAME, '') like ? or ifnull(NAME_EN, '') like ? or ifnull(NAME_ZH, '') like ? or ifnull(FIRST_LETTER_OF_PINYIN, '') like ?) AND"); + } else { + keywordCondition.append("(ifnull(LOCAL_NAME, '') like ? or ifnull(NAME_EN, '') like ? or ifnull(NAME_ZH, '') like ? or ifnull(FIRST_LETTER_OF_PINYIN, '') like ? or ifnull(PINYIN_NAME, '') like ?) AND"); + } + } + if(!keywordCondition.isEmpty()) { + keywordCondition.remove(keywordCondition.length() - 3, 3); + } + + QString sql = QString("SELECT %0 FROM APPINFO WHERE %1 %2 ORDER BY LENGTH(LOCAL_NAME)").arg(field).arg(condition).arg(keywordCondition); + QSqlQuery query(*d->m_database); + query.setForwardOnly(true); + query.prepare(sql); + + int count = 0; + for (const QVariant &conditionValue : restrictions) { + query.bindValue(count, conditionValue); + count++; + } + + for(const QString &keyword : keywords) { + int i = 5; + if(keyword.size() < 2) { + i--; + } + for (int bindCount = 0; bindCount < i; bindCount++) { + query.bindValue(count, "%" + keyword + "%"); + count++; + } + } + + if (!query.exec()) { + qWarning() << d->m_database->lastError() << query.lastError() << query.lastQuery() << query.boundValues(); + return false; + } + + while (query.next()) { + ApplicationPropertyMap propertyMap; + for(const ApplicationProperty::Property &pro : properties) { + propertyMap.insert(pro, query.value(ApplicationPropertyHelper(pro).dataBaseField())); + + } + infoMap.insert(query.value(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField()).toString(), propertyMap); + } + return true; +} + +void AppInfoTable::setAppFavoritesState(const QString &desktopfp) +{ + return d->setAppFavoritesState(desktopfp); +} + +void AppInfoTable::setAppFavoritesState(const QString &desktopfp, size_t num) { return d->setAppFavoritesState(desktopfp, num); } -void AppInfoTable::setAppTopState(QString &desktopfp, size_t num) +void AppInfoTable::setAppTopState(const QString &desktopfp, size_t num) { return d->setAppTopState(desktopfp, num); } -bool AppInfoTable::getAppCategory(QString &desktopfp, QString &category) +void AppInfoTable::setAppLaunchedState(const QString &desktopFilePath, bool launched) { - return d->getAppCategory(desktopfp, category); + return d->setAppLaunchedState(desktopFilePath, launched); } -bool AppInfoTable::changeFavoriteAppPos(const QString &desktopfp, size_t pos) +void AppInfoTable::setAppTopState(const QString &desktopfp) { - return d->changeFavoriteAppPos(desktopfp, pos); -} - -bool AppInfoTable::changeTopAppPos(const QString &desktopfp, size_t pos) -{ - return d->changeTopAppPos(desktopfp, pos); -} - -bool AppInfoTable::getAppInfoResults(QVector &appInfoResults) -{ - return d->getAppInfoResults(appInfoResults); -} - -bool AppInfoTable::getAppLockState(QString &desktopfp, size_t &num) -{ - return d->getAppLockState(desktopfp, num); -} - -bool AppInfoTable::getAppTopState(QString &desktopfp, size_t &num) -{ - return d->getAppTopState(desktopfp, num); -} - -bool AppInfoTable::getAppLaunchedState(QString &desktopfp, size_t &num) -{ - return d->getAppLaunchedState(desktopfp, num); -} - -bool AppInfoTable::getAppFavoriteState(QString &desktopfp, size_t &num) -{ - return d->getAppFavoriteState(desktopfp, num); -} - -bool AppInfoTable::addAppShortcut2Desktop(QString &desktopfp) -{ - return d->addAppShortcut2Desktop(desktopfp); -} - -bool AppInfoTable::addAppShortcut2Panel(QString &desktopfp) -{ - return d->addAppShortcut2Panel(desktopfp); + return d->setAppTopState(desktopfp); } bool AppInfoTable::searchInstallApp(QString &keyWord, QStringList &installAppInfoRes) @@ -653,48 +576,38 @@ bool AppInfoTable::searchInstallApp(QStringList &keyWord, QStringList &installAp return d->searchInstallApp(keyWord, installAppInfoRes); } -bool AppInfoTable::uninstallApp(QString &desktopfp) -{ - return d->uninstallApp(desktopfp); -} - QString AppInfoTable::lastError() const { return d->lastError(); } +bool AppInfoTable::tranPidToDesktopFp(uint pid, QString &desktopfp) +{ + return d->tranPidToDesktopFp(pid, desktopfp); +} + +bool AppInfoTable::desktopFilePathFromName(const QString &desktopFileName, QString &desktopFilePath) +{ + return d->desktopFilePathFromName(desktopFileName, desktopFilePath); +} + +bool AppInfoTable::tranWinIdToDesktopFilePath(const QVariant &winId, QString &desktopfp) +{ + return d->tranWinIdToDesktopFilePath(winId, desktopfp); +} + //下面接口暂时没啥用,不外放。 -bool AppInfoTable::setAppLaunchTimes(QString &desktopfp, size_t num) +bool AppInfoTable::setAppLaunchTimes(const QString &desktopfp, size_t num) { return d->setAppLaunchTimes(desktopfp, num); } -bool AppInfoTable::updateAppLaunchTimes(QString &desktopfp) +bool AppInfoTable::updateAppLaunchTimes(const QString &desktopfp) { return d->updateAppLaunchTimes(desktopfp); } -bool AppInfoTable::setAppLockState(QString &desktopfp, size_t num) +bool AppInfoTable::setAppLockState(const QString &desktopfp, size_t num) { return d->setAppLockState(desktopfp, num); } - -bool AppInfoTable::getAllAppDesktopList(QStringList &list) -{ - return d->getAllAppDesktopList(list); -} - -bool AppInfoTable::getFavoritesAppList(QStringList &list) -{ - return d->getFavoritesAppList(list); -} - -bool AppInfoTable::getTopAppList(QStringList &list) -{ - return d->getTopAppList(list); -} - -bool AppInfoTable::getLaunchTimesAppList(QStringList &list) -{ - return d->getLaunchTimesAppList(list); -} diff --git a/libsearch/appdata/app-info-table.h b/libsearch/appdata/app-info-table.h index dbfb3ae..9fc819e 100644 --- a/libsearch/appdata/app-info-table.h +++ b/libsearch/appdata/app-info-table.h @@ -1,74 +1,85 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef APPINFOTABLE_H #define APPINFOTABLE_H #include -#include "app-db-common.h" +#include +#include +#include "application-property.h" namespace UkuiSearch { +const static QString APP_DATABASE_PATH = QDir::homePath()+"/.config/org.ukui/ukui-search/appdata/"; +const static QString APP_DATABASE_NAME = "app-info.db"; + class AppInfoTablePrivate; class AppInfoTable : public QObject { Q_OBJECT public: - explicit AppInfoTable(QObject *parent = nullptr); + static AppInfoTable* self(); + AppInfoTable(AppInfoTable &) = delete; AppInfoTable &operator =(const AppInfoTable &) = delete; + bool query(ApplicationPropertyMap &propertyMap, const QString &desktopFile, ApplicationProperties properties); + bool query(ApplicationInfoMap &infoMap, ApplicationProperties properties); + bool query(ApplicationInfoMap &infoMap, ApplicationProperties properties, ApplicationPropertyMap restrictions); + bool query(ApplicationInfoMap &infoMap, ApplicationProperties properties, const QStringList &keywords, ApplicationPropertyMap restrictions); + /** * @brief AppInfoTable::setAppFavoritesState - * set the favorites state of the app + * set the app to favorites apps(default is at 1) + * @param desktopfp: the desktop file path of app + */ + void setAppFavoritesState(const QString &desktopfp); + + /** + * @brief AppInfoTable::setAppFavoritesState + * set the favorites state of the app, you can also use to change the position of the app which is one of the Favorites Apps * @param desktopfp: the desktop file path of app * @param num: the favorites app's order(from 1) */ - void setAppFavoritesState(QString &desktopfp, size_t num); + void setAppFavoritesState(const QString &desktopfp, size_t num); /** * @brief AppInfoTable::setAppTopState - * set the top state of the app + * set the app to top apps(default is at 1) + * @param desktopfp: desktop file path of app + */ + void setAppTopState(const QString &desktopfp); + + /** + * @brief AppInfoTable::setAppTopState + * set the top state of the app, you can also use to change the position of the app which is one of the Top Apps * @param desktopfp: the desktop file path of app * @param num: the top app's order(from 1) */ - void setAppTopState(QString &desktopfp, size_t num); + void setAppTopState(const QString &desktopfp, size_t num); - /** - * @brief AppInfoTable::changeFavoriteAppPos - * change the position of the app which is one of the Favorites Apps - * @param desktopfp: desktop file path of app - * @param pos: the position which the app will be changed into - */ - bool changeFavoriteAppPos(const QString &desktopfp, size_t pos); - - /** - * @brief AppInfoTable::changeTopAppPos - * hange the position of the app which is one of the Top Apps - * @param desktopfp: desktop file path of app - * @param pos: the position which the app will be changed into - * @return bool: true if success, else false - */ - bool changeTopAppPos(const QString &desktopfp, size_t pos); - - /** - * @brief AppInfoTable::getAppInfoResults - * Get all App infos by passing AppInforesult Vector. - * @param AppInfoResults: a struct which includes all infos of each application - * @return bool: true if success, else false - */ - bool getAppInfoResults(QVector &appInfoResults); - - bool getAppLockState(QString &desktopfp, size_t &num); - bool getAppTopState(QString &desktopfp, size_t &num); - bool getAppLaunchedState(QString &desktopfp, size_t &num); - bool getAppFavoriteState(QString &desktopfp, size_t &num); - bool getAppCategory(QString &desktopfp, QString &category); - - bool addAppShortcut2Desktop(QString &desktopfp); - bool addAppShortcut2Panel(QString &desktopfp); + void setAppLaunchedState(const QString &desktopFilePath, bool launched); bool searchInstallApp(QString &keyWord, QStringList &installAppInfoRes); bool searchInstallApp(QStringList &keyWord, QStringList &installAppInfoRes); - bool uninstallApp(QString &desktopfp); /** * @brief AppInfoTable::lastError @@ -77,23 +88,34 @@ public: */ QString lastError(void) const; -private: - //暂不外放的接口 - bool setAppLaunchTimes(QString &desktopfp, size_t num); - bool setAppLockState(QString &desktopfp, size_t num); - bool updateAppLaunchTimes(QString &desktopfp); - bool getAllAppDesktopList(QStringList &list); - bool getFavoritesAppList(QStringList &list); - bool getTopAppList(QStringList &list); - bool getLaunchTimesAppList(QStringList &list); + /** + * @brief AppInfoTable::tranPid2DesktopFp + * find the desktop file path of the process which corresponds to the pid + * @param pid: the pid of the process which need to get its desktop file path + * @param desktopfp: the desktop file path of the process corresponding to pid + * @return bool:true if success,else false + */ + bool tranPidToDesktopFp(uint pid, QString &desktopfp); + + bool desktopFilePathFromName(const QString &desktopFileName, QString &desktopFilePath); + + bool tranWinIdToDesktopFilePath(const QVariant &winId, QString &desktopfp); private: + //暂不外放的接口 + bool setAppLaunchTimes(const QString &desktopfp, size_t num); + bool setAppLockState(const QString &desktopfp, size_t num); + bool updateAppLaunchTimes(const QString &desktopfp); + +private: + explicit AppInfoTable(QObject *parent = nullptr); AppInfoTablePrivate *d; Q_SIGNALS: void DBOpenFailed(); - void appDBItems2BUpdate(QVector); - void appDBItems2BAdd(QVector); + void appDBItems2BUpdate(ApplicationInfoMap); + void appDBItems2BUpdateAll(QStringList); + void appDBItems2BAdd(QStringList); void appDBItems2BDelete(QStringList); }; } diff --git a/libsearch/appdata/appdata.pri b/libsearch/appdata/appdata.pri deleted file mode 100644 index c265c1e..0000000 --- a/libsearch/appdata/appdata.pri +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/app-info-table-private.h \ - $$PWD/app-info-table.h - -SOURCES += \ - $$PWD/app-info-table.cpp - diff --git a/libsearch/appdata/application-info-storage.cpp b/libsearch/appdata/application-info-storage.cpp new file mode 100644 index 0000000..534b0c2 --- /dev/null +++ b/libsearch/appdata/application-info-storage.cpp @@ -0,0 +1,69 @@ +#include "application-info-storage.h" +#include +using namespace UkuiSearch; +namespace UkuiSearch { +class ApplicationInfoStoragePrivate +{ + friend class ApplicationInfoStorage; +private: + Properties m_properties; + ApplicationInfoMap m_data; +}; +} +ApplicationInfoStorage::ApplicationInfoStorage(): d(new ApplicationInfoStoragePrivate) +{ +} + +ApplicationInfoStorage::ApplicationInfoStorage(Properties properties): d(new ApplicationInfoStoragePrivate) +{ + d->m_properties = properties; +} + +ApplicationInfoStorage::ApplicationInfoStorage(const ApplicationInfoStorage &other): d(new ApplicationInfoStoragePrivate(*other.d)) +{ +} + +ApplicationInfoStorage::~ApplicationInfoStorage() +{ + if(d) { + delete d; + d = nullptr; + } +} + +ApplicationInfoStorage &ApplicationInfoStorage::operator=(const ApplicationInfoStorage &rhs) +{ + *d = *rhs.d; + return *this; +} + +QStringList ApplicationInfoStorage::applicationKeys() const +{ + return d->m_data.keys(); +} + +Properties &ApplicationInfoStorage::applicationInfoKeys() const +{ + return d->m_properties; +} + +QVariant ApplicationInfoStorage::ApplicationInfo(const QString &desktopFile, ApplicationProperty::Property property) +{ + return d->m_data.value(desktopFile).value(property); +} + +ApplicationInfoMap &ApplicationInfoStorage::allData() +{ + return d->m_data; +} + +void ApplicationInfoStorage::addData(const QString &desktopFile, ApplicationProperty::Property property, const QVariant &value) +{ + if(d->m_data.contains(desktopFile)) { + QMap info = d->m_data.value(desktopFile); + info.insert(property, value); + d->m_data.insert(desktopFile, info); + } else { + d->m_data.insert(desktopFile, QMap{{property, value}}); + } +} diff --git a/libsearch/appdata/application-info-storage.h b/libsearch/appdata/application-info-storage.h new file mode 100644 index 0000000..bf6a56c --- /dev/null +++ b/libsearch/appdata/application-info-storage.h @@ -0,0 +1,41 @@ +#ifndef APPLICATIONINFOSTORAGE_H +#define APPLICATIONINFOSTORAGE_H + +#include +#include "application-property.h" +namespace UkuiSearch { +class ApplicationInfoStoragePrivate; +class ApplicationInfoStorage +{ +public: + ApplicationInfoStorage(); + ApplicationInfoStorage(Properties properties); + ApplicationInfoStorage(const ApplicationInfoStorage &other); + ~ApplicationInfoStorage(); + + ApplicationInfoStorage & operator=(const ApplicationInfoStorage &rhs); + /** + * @brief 查询当前容器内包含的应用列表 + * @return 所有desktop路径的QStringlist + */ + QStringList applicationKeys() const; + /** + * @brief 查询当前容器包含的信息种类 + * @return QVector + */ + Properties &applicationInfoKeys() const; + /** + * @brief 查询某个应用的某个信息 + * @param desktopFile + * @param info + * @return 以info的数据类型格式返回特定信息 + */ + QVariant ApplicationInfo(const QString &desktopFile, ApplicationProperty::Property property); + ApplicationInfoMap &allData(); + void addData(const QString &desktopFile, ApplicationProperty::Property property, const QVariant &value); + +private: + ApplicationInfoStoragePrivate *d = nullptr; +}; +} +#endif // APPLICATIONINFOSTORAGE_H diff --git a/libsearch/appdata/application-info.cpp b/libsearch/appdata/application-info.cpp new file mode 100644 index 0000000..dd1eeec --- /dev/null +++ b/libsearch/appdata/application-info.cpp @@ -0,0 +1,113 @@ +#include "application-info.h" +#include "app-info-table.h" +#include "application-property-helper.h" +using namespace UkuiSearch; +namespace UkuiSearch { +class ApplicationInfoPrivate +{ +}; +} +ApplicationInfo::ApplicationInfo(QObject *parent) + : QObject(parent), d(new ApplicationInfoPrivate) +{ + connect(AppInfoTable::self(), &AppInfoTable::appDBItems2BUpdate, this, &ApplicationInfo::appDBItems2BUpdate); + connect(AppInfoTable::self(), &AppInfoTable::appDBItems2BUpdateAll, this, &ApplicationInfo::appDBItems2BUpdateAll); + connect(AppInfoTable::self(), &AppInfoTable::appDBItems2BAdd, this, &ApplicationInfo::appDBItems2BAdd); + connect(AppInfoTable::self(), &AppInfoTable::appDBItems2BDelete, this, &ApplicationInfo::appDBItems2BDelete); +} + +ApplicationInfo::~ApplicationInfo() +{ + if(d) { + delete d; + d = nullptr; + } +} + +QVariant UkuiSearch::ApplicationInfo::getInfo(const QString &desktopFile, ApplicationProperty::Property property) +{ + ApplicationPropertyMap map; + AppInfoTable::self()->query(map, desktopFile, ApplicationProperties{property}); + return map.value(property); +} + +ApplicationPropertyMap ApplicationInfo::getInfo(const QString &desktopFile, ApplicationProperties properties) +{ + ApplicationPropertyMap propertyMap; + AppInfoTable::self()->query(propertyMap, desktopFile, properties); + return propertyMap; +} + +ApplicationInfoMap ApplicationInfo::getInfo(ApplicationProperties properties) +{ + ApplicationInfoMap infoMap; + AppInfoTable::self()->query(infoMap, properties); + return infoMap; +} + +ApplicationInfoMap ApplicationInfo::getInfo(ApplicationProperties properties, ApplicationPropertyMap restrictions) +{ + ApplicationInfoMap infoMap; + AppInfoTable::self()->query(infoMap, properties, restrictions); + return infoMap; +} + + +ApplicationInfoMap ApplicationInfo::searchApp(ApplicationProperties properties, const QString &keyword, ApplicationPropertyMap restrictions) +{ + ApplicationInfoMap infoMap; + AppInfoTable::self()->query(infoMap, properties, QStringList{keyword}, restrictions); + return infoMap; +} + +ApplicationInfoMap ApplicationInfo::searchApp(ApplicationProperties properties, const QStringList &keywords, ApplicationPropertyMap restrictions) +{ + ApplicationInfoMap infoMap; + AppInfoTable::self()->query(infoMap, properties, keywords, restrictions); + return infoMap; +} + +void ApplicationInfo::setAppToFavorites(const QString &desktopFilePath) +{ + AppInfoTable::self()->setAppFavoritesState(desktopFilePath); +} + +void ApplicationInfo::setFavoritesOfApp(const QString &desktopFilePath, size_t num) +{ + AppInfoTable::self()->setAppFavoritesState(desktopFilePath, num); +} + +void ApplicationInfo::setAppToTop(const QString &desktopFilePath) +{ + AppInfoTable::self()->setAppTopState(desktopFilePath); +} + +void ApplicationInfo::setTopOfApp(const QString &desktopFilePath, size_t num) +{ + AppInfoTable::self()->setAppTopState(desktopFilePath, num); +} + +void ApplicationInfo::setAppLaunchedState(const QString &desktopFilePath, bool launched) +{ + AppInfoTable::self()->setAppLaunchedState(desktopFilePath, launched); +} + +bool ApplicationInfo::tranPidToDesktopFp(int pid, QString &desktopFilePath) +{ + return AppInfoTable::self()->tranPidToDesktopFp(pid, desktopFilePath); +} + +bool ApplicationInfo::tranPidToDesktopFp(uint pid, QString &desktopFilePath) +{ + return AppInfoTable::self()->tranPidToDesktopFp(pid, desktopFilePath); +} + +bool ApplicationInfo::desktopFilePathFromName(const QString &desktopFileName, QString &desktopFilePath) +{ + return AppInfoTable::self()->desktopFilePathFromName(desktopFileName, desktopFilePath); +} + +bool ApplicationInfo::tranWinIdToDesktopFilePath(const QVariant &winId, QString &desktopFilePath) +{ + return AppInfoTable::self()->tranWinIdToDesktopFilePath(winId, desktopFilePath); +} diff --git a/libsearch/appdata/application-info.h b/libsearch/appdata/application-info.h new file mode 100644 index 0000000..393ae11 --- /dev/null +++ b/libsearch/appdata/application-info.h @@ -0,0 +1,147 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef APPLICATIONINFO_H +#define APPLICATIONINFO_H + +#include + +#include "application-property.h" +namespace UkuiSearch { +class ApplicationInfoPrivate; +class ApplicationInfo : public QObject +{ + Q_OBJECT +public: + explicit ApplicationInfo(QObject *parent = nullptr); + ~ApplicationInfo(); + /** + * @brief getInfo 查询单个应用的单个属性 + * @param desktopFile + * @param property + * @return + */ + QVariant getInfo(const QString &desktopFile, ApplicationProperty::Property property); + /** + * @brief getInfo 查询单个应用的多个属性 + * @param desktopFile + * @param properties + * @return + */ + ApplicationPropertyMap getInfo(const QString &desktopFile, ApplicationProperties properties); + /** + * @brief getInfo 查询所有应用的多个属性 + * @param property + * @return + */ + ApplicationInfoMap getInfo(ApplicationProperties properties); + + /** + * @brief ApplicationInfo::getInfo + * get the application info that meets the restrictions + * @param restrictions: The restrictions that the search results should meet(e.g. u want get the app infos whose top state is 0) + * @param properties: Each application's information should contain these properties + * @return ApplicationInfoMap: the search result + */ + ApplicationInfoMap getInfo(ApplicationProperties properties, ApplicationPropertyMap restrictions); + + /** + * @brief ApplicationInfo::searchApp + * @param keyWord: the keyword of this search for applications + * @param installAppInfoRes: the search results of applications + * @return ApplicationInfoMap: the search result + */ + ApplicationInfoMap searchApp(ApplicationProperties properties, const QString &keyword, ApplicationPropertyMap restrictions); + ApplicationInfoMap searchApp(ApplicationProperties properties, const QStringList &keywords, ApplicationPropertyMap restrictions); + + /** + * @brief AppInfoTable::setAppToFavorites + * set the app to favorites apps(default is at 1) + * @param desktopfp: the desktop file path of app + */ + void setAppToFavorites(const QString &desktopFilePath); + + /** + * @brief AppInfoTable::setFavoritesTo + * set the favorites state of the app to num, you can also use to change the position of the app which is one of the Favorites Apps + * @param desktopfp: the desktop file path of app + * @param num: the favorites app's position(from 1). If num is 0, it will remove the app from the favorites apps + */ + void setFavoritesOfApp(const QString &desktopFilePath, size_t num); + + /** + * @brief AppInfoTable::setAppToTop + * set the app to top apps(default is at 1) + * @param desktopfp: desktop file path of app + */ + void setAppToTop(const QString &desktopFilePath); + + /** + * @brief AppInfoTable::setAppTopTo + * set the top state of the app to num, you can also use to change the position of the app which is one of the Top Apps + * @param desktopfp: the desktop file path of app + * @param num: the top app's position(from 1). If num is 0, it will remove the app from the top apps + */ + void setTopOfApp(const QString &desktopFilePath, size_t num); + + void setAppLaunchedState(const QString &desktopFilePath, bool launched = true); + + /** + * @brief ApplicationInfo::tranPid2DesktopFp + * find the desktop file path of the process which corresponds to the pid + * @param pid: the pid of the process which need to get its desktop file path + * @param desktopFilePath: the desktop file path of the process corresponding to pid + * @return bool:true if success,else false + */ + bool tranPidToDesktopFp(int pid, QString &desktopFilePath);//obsolete + bool tranPidToDesktopFp(uint pid, QString &desktopFilePath); + + /** + * @brief ApplicationInfo::desktopFilePathFromName + * find the desktop file path of the process which corresponds to the desktop file name (without .desktop) + * @param desktopFileName: the desktop file name of the process which need to get its desktop file path + * @param desktopFilePath: the desktop file path of the process corresponding to pid + * @return bool:true if success,else false + */ + bool desktopFilePathFromName(const QString &desktopFileName, QString &desktopFilePath); + + /** + * @brief ApplicationInfo::tranWinIdToDesktopFilePath + * find the desktop file path of the process which corresponds to the winId. + * it will find through tranPidToDesktopFp method first, and then use the winId if the desktop file can not be found by pid; + * @param winId: the winId of the process which need to get its desktop file path + * @param desktopFilePath: the desktop file path of the process corresponding to pid + * @return bool:true if success,else false + */ + bool tranWinIdToDesktopFilePath(const QVariant &winId, QString &desktopFilePath); + +Q_SIGNALS: + void DBOpenFailed(); + void appDBItems2BUpdate(ApplicationInfoMap); + void appDBItems2BUpdateAll(QStringList); + void appDBItems2BAdd(QStringList); + void appDBItems2BDelete(QStringList); + +private: + ApplicationInfoPrivate *d = nullptr; + +}; + +} +#endif // APPLICATIONINFO_H diff --git a/libsearch/appdata/application-property-helper.cpp b/libsearch/appdata/application-property-helper.cpp new file mode 100644 index 0000000..553dd12 --- /dev/null +++ b/libsearch/appdata/application-property-helper.cpp @@ -0,0 +1,170 @@ +#include "application-property-helper.h" +#include +using namespace UkuiSearch; +namespace UkuiSearch { + +class ApplicationPropertyHelperPrivate +{ + friend class ApplicationPropertyHelper; +private: + ApplicationProperty::Property m_property; + QString m_databaseField; + QMetaType::Type m_valueType; +}; +} +ApplicationPropertyHelper::ApplicationPropertyHelper(): d(new ApplicationPropertyHelperPrivate) +{ + d->m_property = ApplicationProperty::Invalid; + d->m_valueType = QMetaType::UnknownType; +} + +ApplicationPropertyHelper::ApplicationPropertyHelper(ApplicationProperty::Property property): d(new ApplicationPropertyHelperPrivate) +{ + d->m_property = property; + switch (property) { + case ApplicationProperty::DesktopFilePath: + d->m_databaseField = "DESKTOP_FILE_PATH"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::ModifiedTime: + d->m_databaseField = "MODIFYED_TIME"; + d->m_valueType = QMetaType::QDateTime; + break; + case ApplicationProperty::InsertTime: + d->m_databaseField = "INSERT_TIME"; + d->m_valueType = QMetaType::QDateTime; + break; + case ApplicationProperty::LocalName: + d->m_databaseField = "LOCAL_NAME"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::NameEn: + d->m_databaseField = "NAME_EN"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::NameZh: + d->m_databaseField = "NAME_EN"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::PinyinName: + d->m_databaseField = "PINYIN_NAME"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::FirstLetterOfPinyin: + d->m_databaseField = "FIRST_LETTER_OF_PINYIN"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::FirstLetterAll: + d->m_databaseField = "FIRST_LETTER_ALL"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::Icon: + d->m_databaseField = "ICON"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::Type: + d->m_databaseField = "TYPE"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::Category: + d->m_databaseField = "CATEGORY"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::Exec: + d->m_databaseField = "EXEC"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::Comment: + d->m_databaseField = "CATEGORY"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::Md5: + d->m_databaseField = "MD5"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::LaunchTimes: + d->m_databaseField = "LAUNCH_TIMES"; + d->m_valueType = QMetaType::Int; + break; + case ApplicationProperty::Favorites: + d->m_databaseField = "FAVORITES"; + d->m_valueType = QMetaType::Int; + break; + case ApplicationProperty::Launched: + d->m_databaseField = "LAUNCHED"; + d->m_valueType = QMetaType::Int; + break; + case ApplicationProperty::Top: + d->m_databaseField = "TOP"; + d->m_valueType = QMetaType::Int; + break; + case ApplicationProperty::Lock: + d->m_databaseField = "LOCK"; + d->m_valueType = QMetaType::Int; + break; + case ApplicationProperty::DontDisplay: + d->m_databaseField = "DONT_DISPLAY"; + d->m_valueType = QMetaType::Int; + break; + case ApplicationProperty::AutoStart: + d->m_databaseField = "AUTO_START"; + d->m_valueType = QMetaType::Int; + break; + default: + break; + } +} + +ApplicationPropertyHelper::ApplicationPropertyHelper(const ApplicationPropertyHelper &other): d(new ApplicationPropertyHelperPrivate(*other.d)) +{ + +} + +ApplicationPropertyHelper::~ApplicationPropertyHelper() +{ + if(d) { + delete d; + d = nullptr; + } +} + +ApplicationPropertyHelper &ApplicationPropertyHelper::operator =(const ApplicationPropertyHelper &rhs) +{ + *d = *rhs.d; + return *this; +} + +bool ApplicationPropertyHelper::operator ==(const ApplicationPropertyHelper &rhs) const +{ + return d->m_databaseField == rhs.d->m_databaseField && d->m_valueType == rhs.d->m_valueType; +} + +ApplicationProperty::Property ApplicationPropertyHelper::info() +{ + return d->m_property; +} + +QString ApplicationPropertyHelper::dataBaseField() +{ + return d->m_databaseField; +} + +QMetaType::Type ApplicationPropertyHelper::valueType() +{ + return d->m_valueType; +} + +QString ApplicationPropertyHelper::toDataBaseString(QVariant &value) +{ + switch (d->m_valueType) { + case QMetaType::Type::UnknownType: + return QString(); + case QMetaType::Type::QString: + return value.toString(); + case QMetaType::Type::QDateTime: + return value.toDateTime().toString("yyyy-MM-dd hh:mm:ss"); + default: + return {}; + break; + } +} diff --git a/libsearch/appdata/application-property-helper.h b/libsearch/appdata/application-property-helper.h new file mode 100644 index 0000000..1a2231f --- /dev/null +++ b/libsearch/appdata/application-property-helper.h @@ -0,0 +1,49 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef APPLICATIONINFOHELPER_H +#define APPLICATIONINFOHELPER_H + +#include "application-property.h" +#include +#include +namespace UkuiSearch { + +class ApplicationPropertyHelperPrivate; +class ApplicationPropertyHelper +{ +public: + ApplicationPropertyHelper(); + ApplicationPropertyHelper(ApplicationProperty::Property property); + ApplicationPropertyHelper(const ApplicationPropertyHelper &other); + ~ApplicationPropertyHelper(); + + ApplicationPropertyHelper& operator=(const ApplicationPropertyHelper &rhs); + bool operator==(const ApplicationPropertyHelper &rhs) const; + + ApplicationProperty::Property info(); + QString dataBaseField(); + QMetaType::Type valueType(); + QString toDataBaseString(QVariant &value); + +private: + ApplicationPropertyHelperPrivate *d = nullptr; +}; +} +#endif // APPLICATIONINFOHELPER_H diff --git a/libsearch/appdata/application-property.h b/libsearch/appdata/application-property.h new file mode 100644 index 0000000..c475e24 --- /dev/null +++ b/libsearch/appdata/application-property.h @@ -0,0 +1,68 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef APPLICATIONPROPERTY_H +#define APPLICATIONPROPERTY_H + +#include +#include +#include +#include +#include +namespace UkuiSearch { + +namespace ApplicationProperty { +/** + * @brief 表示应用基础信息 + */ +enum Property { + Invalid = 0, + DesktopFilePath, //desktop文件路径 + ModifiedTime, //数据修改时间 + InsertTime, //数据插入时间 + LocalName, //应用名(本地化) + NameEn, //应用英文名 + NameZh, //应用中文名 + PinyinName, //名称拼音 + FirstLetterOfPinyin, //拼音首字母 + FirstLetterAll, //名称首字母 + Icon, //应用图标 + Type, //种类(Application等) + Category, //分类(AudioVideo等) + Exec, //执行命令 + Comment, //简介 + Md5, //desktop文件的md5 + LaunchTimes, //启动次数 + Favorites, //收藏顺序(0 未收藏) + Launched, //是否从开始菜单启动过 + Top, //置顶顺序(0 未置顶) + Lock, //是否锁定(不允许显示或打开) + DontDisplay, //是否不需要显示(设置了Nodisplay等字段) + AutoStart //是否自启动(位于自启动目录/etc/xdg/autostart下) +}; +} //namespace ApplicationProperty +typedef QVector ApplicationProperties; +typedef QMap ApplicationPropertyMap; +typedef QMap ApplicationInfoMap; // desktopFile->ApplicationPropertyMap +} +Q_DECLARE_METATYPE(UkuiSearch::ApplicationProperty::Property) +Q_DECLARE_METATYPE(UkuiSearch::ApplicationPropertyMap) +Q_DECLARE_METATYPE(UkuiSearch::ApplicationInfoMap) +Q_DECLARE_METATYPE(UkuiSearch::ApplicationProperties) +#endif // APPLICATIONPROPERTY_H diff --git a/libsearch/appsearch/app-match.cpp b/libsearch/appsearch/app-match.cpp deleted file mode 100644 index 859bde2..0000000 --- a/libsearch/appsearch/app-match.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2020, KylinSoft Co., Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Authors: sunfengsheng - * - */ -#include "app-match.h" -#include -#include -#include -#include -#include "file-utils.h" -#include "app-search-plugin.h" - -using namespace UkuiSearch; -static AppMatch *app_match_Class = nullptr; - -AppMatch *AppMatch::getAppMatch() { - if(!app_match_Class) { - app_match_Class = new AppMatch; - } - return app_match_Class; -} -AppMatch::AppMatch(QObject *parent) : QThread(parent) -// m_versionCommand(new QProcess(this)) -{ - qDBusRegisterMetaType>(); - qDBusRegisterMetaType>>(); - m_interFace = new QDBusInterface("com.kylin.softwarecenter.getsearchresults", "/com/kylin/softwarecenter/getsearchresults", - "com.kylin.getsearchresults", - QDBusConnection::sessionBus()); - if(!m_interFace->isValid()) { - qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message()); - } - m_interFace->setTimeout(1500); - m_appInfoTable = new AppInfoTable; - qDebug() << "AppMatch init finished."; -} - -AppMatch::~AppMatch() { - if(m_interFace) { - delete m_interFace; - } - m_interFace = NULL; - if(m_appInfoTable) { - delete m_appInfoTable; - } - m_appInfoTable = NULL; -} - -void AppMatch::startMatchApp(QString input, size_t uniqueSymbol, DataQueue *searchResult) { - appNameMatch(input, uniqueSymbol, searchResult); - slotDBusCallFinished(input, uniqueSymbol, searchResult); - qDebug() << "App match finished!"; -} - -/** - * @brief AppMatch::appNameMatch - * 进行匹配 - * @param appname - * 应用名字 - */ -void AppMatch::appNameMatch(QString keyWord, size_t uniqueSymbol, DataQueue *searchResult) { - QStringList results; - //m_appInfoTable->searchInstallAppOrderByFavoritesDesc(keyWord, results); - for (int i = 0; i < results.size() / 3; i++) { - { - QMutexLocker locker(&AppSearchPlugin::m_mutex); - if (uniqueSymbol != AppSearchPlugin::uniqueSymbol) { - return; - } - } - - SearchPluginIface::ResultInfo ri; - ri.actionKey = results.at(i*3); - ri.name = results.at(i*3 + 1); - ri.icon = XdgIcon::fromTheme(results.at(i*3 + 2), QIcon(":/res/icons/desktop.png")); - ri.type = 0; - - searchResult->enqueue(ri); - } - -/* QMultiMap installAppMap; - m_appInfoTable->getInstallAppMap(installAppMap); - QMap resultAppMap; - for (auto i = installAppMap.begin(); i != installAppMap.end(); ++i) { - NameString name; - name.app_name = i.key(); - QStringList infoList; - infoList = i.value(); - resultAppMap.insert(name, infoList); - } - QMapIterator iter(resultAppMap); - while(iter.hasNext()) { - iter.next(); - if(iter.key().app_name.contains(keyWord, Qt::CaseInsensitive)) { - SearchPluginIface::ResultInfo ri; - creatResultInfo(ri, iter, true); - AppSearchPlugin::m_mutex.lock(); - if (uniqueSymbol == AppSearchPlugin::uniqueSymbol) { - searchResult->enqueue(ri); - AppSearchPlugin::m_mutex.unlock(); - continue; - } else { - AppSearchPlugin::m_mutex.unlock(); - return; - } - } - - if(iter.value().at(3) == ""){ - continue; - } - QStringList pinyinlist; - pinyinlist = FileUtils::findMultiToneWords(iter.value().at(3)); - - bool matched = false; - for(int i = 0; i < pinyinlist.size() / 2; i++) { - QString shouzimu = pinyinlist.at(2 * i + 1); // 中文转首字母 - if(shouzimu.contains(keyWord, Qt::CaseInsensitive)) { - SearchPluginIface::ResultInfo ri; - creatResultInfo(ri, iter, true); - AppSearchPlugin::m_mutex.lock(); - if (uniqueSymbol == AppSearchPlugin::uniqueSymbol) { - searchResult->enqueue(ri); - AppSearchPlugin::m_mutex.unlock(); - matched = true; - break; - } else { - AppSearchPlugin::m_mutex.unlock(); - return; - } - } - if(keyWord.size() < 2) - break; - QString pinyin = pinyinlist.at(2 * i); // 中文转拼音 - if(pinyin.contains(keyWord, Qt::CaseInsensitive)) { - SearchPluginIface::ResultInfo ri; - AppSearchPlugin::m_mutex.lock(); - creatResultInfo(ri, iter, true); - if (uniqueSymbol == AppSearchPlugin::uniqueSymbol) { - searchResult->enqueue(ri); - AppSearchPlugin::m_mutex.unlock(); - matched = true; - break; - } else { - AppSearchPlugin::m_mutex.unlock(); - return; - } - } - } - if(matched) { - continue; - } - QStringList tmpList; - tmpList << iter.value().at(2) << iter.value().at(3); - for(QString s : tmpList) { - if(s.contains(keyWord, Qt::CaseInsensitive)) { - SearchPluginIface::ResultInfo ri; - AppSearchPlugin::m_mutex.lock(); - creatResultInfo(ri, iter, true); - if (uniqueSymbol == AppSearchPlugin::uniqueSymbol) { - searchResult->enqueue(ri); - AppSearchPlugin::m_mutex.unlock(); - break; - } else { - AppSearchPlugin::m_mutex.unlock(); - return; - } - } - } - }*/ -} - -void AppMatch::slotDBusCallFinished(QString keyWord, size_t uniqueSymbol, DataQueue *searchResult) { - QDBusReply>> reply = m_interFace->call("get_search_result", keyWord); //阻塞,直到远程方法调用完成。 - if(reply.isValid()) { - parseSoftWareCenterReturn(reply.value(), uniqueSymbol, searchResult); - } else { - qWarning() << "SoftWareCenter dbus called failed!"; - } -} - -void AppMatch::parseSoftWareCenterReturn(QList> list, size_t uniqueSymbol, DataQueue *searchResult) { - qDebug() << "Begin parseSoftWareCenterReturn"; - QLocale locale; - for(int i = 0; i < list.size(); i++) { - SearchPluginIface::ResultInfo ri; - if(locale.language() == QLocale::Chinese) { - ri.name = list.at(i).value("displayname_cn"); - } else { - ri.name = list.at(i).value("appname"); - } - ri.icon = !(QIcon(list.at(i).value("icon")).isNull()) ? QIcon(list.at(i).value("icon")) : QIcon(":/res/icons/desktop.png"); - SearchPluginIface::DescriptionInfo di; - di.key = QString(tr("Application Description:")); - di.value = list.at(i).value("discription"); - ri.description.append(di); - ri.actionKey = list.at(i).value("appname"); - ri.type = 1; //1 means not installed apps. - AppSearchPlugin::m_mutex.lock(); - if (uniqueSymbol == AppSearchPlugin::uniqueSymbol) { - searchResult->enqueue(ri); - AppSearchPlugin::m_mutex.unlock(); - } else { - AppSearchPlugin::m_mutex.unlock(); - break; - } - } -} - -//void AppMatch::creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator &iter, bool isInstalled) -//{ -//// ri.icon = QIcon::fromTheme(iter.value().at(1), QIcon(":/res/icons/desktop.png")); -// ri.icon = XdgIcon::fromTheme(iter.value().at(1), QIcon(":/res/icons/desktop.png")); -// ri.name = iter.key().app_name; -// ri.actionKey = iter.value().at(0); -// ri.type = 0; //0 means installed apps. -//} - -void AppMatch::run() { - qDebug() << "App map init.."; - - qDebug() << "App map init finished.."; -} diff --git a/libsearch/appsearch/app-match.h b/libsearch/appsearch/app-match.h deleted file mode 100644 index 08cfbf7..0000000 --- a/libsearch/appsearch/app-match.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2020, KylinSoft Co., Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Authors: sunfengsheng - * - */ -#ifndef APPMATCH_H -#define APPMATCH_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include "search-plugin-iface.h" -#include "../appdata/app-info-table.h" - -namespace UkuiSearch { -class AppMatch : public QThread { - Q_OBJECT -public: - static AppMatch *getAppMatch(); - void startMatchApp(QString input, size_t uniqueSymbol, DataQueue *searchResult); - -protected: - void run() override; - -private: - explicit AppMatch(QObject *parent = nullptr); - ~AppMatch(); - void getAllDesktopFilePath(QString path); - void appNameMatch(QString keyWord, size_t uniqueSymbol, DataQueue *searchResult); - void parseSoftWareCenterReturn(QList> list, size_t uniqueSymbol, DataQueue *searchResult); - //void creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator &iter, bool isInstalled = true); - - AppInfoTable *m_appInfoTable = nullptr; - QString m_sourceText; - size_t m_uniqueSymbol; - DataQueue *m_search_result = nullptr; - QDBusInterface *m_interFace = nullptr; - -private Q_SLOTS: - void slotDBusCallFinished(QString keyWord, size_t uniqueSymbol, DataQueue *searchResult); -}; -} - -#endif // APPMATCH_H diff --git a/libsearch/appsearch/app-search-plugin.cpp b/libsearch/appsearch/app-search-plugin.cpp index 70ff3ff..b10ba5d 100644 --- a/libsearch/appsearch/app-search-plugin.cpp +++ b/libsearch/appsearch/app-search-plugin.cpp @@ -1,7 +1,27 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "app-search-plugin.h" #include #include #include +#include #include "file-utils.h" using namespace UkuiSearch; @@ -16,29 +36,21 @@ AppSearchPlugin::AppSearchPlugin(QObject *parent) : QThread(parent), m_appSearch // m_pool.setMaxThreadCount(1); // m_pool.setExpiryTimeout(1000); initDetailPage(); - - m_timer = new QTimer; - m_timer->setInterval(3000); - m_timer->moveToThread(this); - m_appSearchResults = m_appSearchTask->init(); - m_appSearchTask->initSearchPlugin(SearchType::Application); + m_appSearchTask->initSearchPlugin(SearchProperty::SearchType::Application); m_appSearchTask->setSearchOnlineApps(true); - m_appSearchTask->setResultDataType(SearchType::Application, UkuiSearch::ApplicationDesktopPath | - UkuiSearch::ApplicationLocalName | - UkuiSearch::ApplicationIconName | - UkuiSearch::ApplicationDescription | - UkuiSearch::IsOnlineApplication); + m_appSearchTask->setResultProperties(SearchProperty::SearchType::Application, + SearchResultProperties{SearchProperty::SearchResultProperty::ApplicationDesktopPath, + SearchProperty::SearchResultProperty::ApplicationLocalName, + SearchProperty::SearchResultProperty::ApplicationIconName, + SearchProperty::SearchResultProperty::ApplicationDescription, + SearchProperty::SearchResultProperty::IsOnlineApplication, + SearchProperty::SearchResultProperty::ApplicationPkgName}); } AppSearchPlugin::~AppSearchPlugin() { this->wait(); - - if (m_timer) { - delete m_timer; - m_timer = nullptr; - } } const QString AppSearchPlugin::name() @@ -64,7 +76,7 @@ void AppSearchPlugin::KeywordSearch(QString keyword, DataQueueclearKeyWords(); m_appSearchTask->addKeyword(keyword); - m_appSearchTask->startSearch(SearchType::Application); + m_appSearchTask->startSearch(SearchProperty::SearchType::Application); // AppSearch *appsearch = new AppSearch(searchResult, m_appSearchResults, m_appSearchTask, keyword, uniqueSymbol); // m_pool.start(appsearch); @@ -73,6 +85,8 @@ void AppSearchPlugin::KeywordSearch(QString keyword, DataQueuestop(); + this->requestInterruption(); + this->wait(); } QList AppSearchPlugin::getActioninfo(int type) @@ -160,37 +174,37 @@ QWidget *AppSearchPlugin::detailPage(const ResultInfo &ri) void AppSearchPlugin::run() { + QDeadlineTimer deadline(25000); while(!isInterruptionRequested()) { ResultItem oneResult = m_appSearchResults->tryDequeue(); - if(oneResult.getSearchId() == 0 && oneResult.getItemKey().isEmpty() && oneResult.getExtral().isEmpty()) { - if(!m_timer->isActive()) { - m_timer->start(); - } - msleep(100); - } else { - m_timer->stop(); - SearchPluginIface::ResultInfo ri; - ri.actionKey = oneResult.getExtral().at(0).toString(); - ri.name = oneResult.getExtral().at(1).toString(); - QIcon icon = oneResult.getExtral().at(2).value(); - - if(icon.isNull()) { - ri.icon = QIcon(":/res/icons/unknown.svg"); + SearchResultPropertyMap data = oneResult.getAllValue(); + if(oneResult.getSearchId() == 0 && oneResult.getItemKey().isEmpty() && data.isEmpty()) { + if(deadline.remainingTime()) { + msleep(100); } else { - ri.icon = icon; + this->requestInterruption(); } + + } else { + deadline.setRemainingTime(25000); + SearchPluginIface::ResultInfo ri; + + ri.name = data.value(SearchProperty::SearchResultProperty::ApplicationLocalName).toString(); + ri.icon = IconLoader::loadIconQt(data.value(SearchProperty::SearchResultProperty::ApplicationIconName).toString(), QIcon(":/res/icons/unknown.svg")); SearchPluginIface::DescriptionInfo description; description.key = QString(tr("Application Description:")); - description.value = oneResult.getExtral().at(3).toString(); + description.value = data.value(SearchProperty::SearchResultProperty::ApplicationDescription).toString(); ri.description.append(description); - ri.type = oneResult.getExtral().at(4).toInt(); + ri.type = data.value(SearchProperty::SearchResultProperty::IsOnlineApplication).toInt(); + if (ri.type == 1) { + ri.actionKey = data.value(SearchProperty::SearchResultProperty::ApplicationPkgName).toString(); + } else { + ri.actionKey = data.value(SearchProperty::SearchResultProperty::ApplicationDesktopPath).toString(); + } m_searchResult->enqueue(ri); } - - if(m_timer->isActive() && m_timer->remainingTime() < 0.01 && m_appSearchResults->isEmpty()) { - this->requestInterruption(); - } } + m_appSearchResults->clear(); } void AppSearchPlugin::initDetailPage() @@ -284,7 +298,7 @@ bool AppSearchPlugin::launch(const QString &path) if(reply.isValid()) { res = reply; } else { - qWarning() << "SoftWareCenter dbus called failed!"; + qWarning() << "AppManager dbus called failed!"; res = false; } } @@ -327,8 +341,7 @@ bool AppSearchPlugin::addDesktopShortcut(const QString& path) { QString newName = QString(dirpath + "/" + desktopfn); bool ret = file.copy(QString(dirpath + "/" + desktopfn)); if(ret) { - QProcess process; - process.startDetached(QString("chmod a+x %1").arg(newName)); + QProcess::startDetached("chmod", {"a+x", newName}); return true; } return false; @@ -369,8 +382,7 @@ bool AppSearchPlugin::installAppAction(const QString & name) { } appLaunchInterface = nullptr; if (!res) { - QProcess process; - res = process.startDetached(QString("kylin-software-center -find %1").arg(name)); + res = QProcess::startDetached("kylin-software-center", {"-find", name}); } } if(interface) { diff --git a/libsearch/appsearch/app-search-plugin.h b/libsearch/appsearch/app-search-plugin.h index 9b91490..3dcf047 100644 --- a/libsearch/appsearch/app-search-plugin.h +++ b/libsearch/appsearch/app-search-plugin.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef APPSEARCHPLUGIN_H #define APPSEARCHPLUGIN_H @@ -16,11 +35,12 @@ #include "separation-line.h" #include "libsearch_global.h" #include "ukui-search-task.h" +#include "icon-loader.h" + namespace UkuiSearch { class LIBSEARCH_EXPORT AppSearchPlugin : public QThread, public SearchPluginIface { friend class AppSearch; - friend class AppMatch; Q_OBJECT public: AppSearchPlugin(QObject *parent = nullptr); @@ -28,7 +48,7 @@ public: PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); - const QIcon icon() {return QIcon::fromTheme("appsearch");} + const QIcon icon() {return IconLoader::loadIconQt("appsearch");} void setEnable(bool enable) {m_enable = enable;} bool isEnable() {return m_enable;} QString getPluginName(); @@ -40,7 +60,7 @@ public: // bool isPreviewEnable(QString key, int type); // QWidget *previewPage(QString key, int type, QWidget *parent); QWidget *detailPage(const ResultInfo &ri); - void run() override; + void run(); private: void initDetailPage(); bool launch(const QString &path); @@ -50,8 +70,6 @@ private: bool m_enable = true; QList m_actionInfo_installed; QList m_actionInfo_not_installed; -// QThreadPool m_pool; - QTimer *m_timer; UkuiSearchTask *m_appSearchTask = nullptr; DataQueue* m_appSearchResults = nullptr; diff --git a/libsearch/appsearch/appsearch.pri b/libsearch/appsearch/appsearch.pri deleted file mode 100644 index 9f39bab..0000000 --- a/libsearch/appsearch/appsearch.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/app-search-plugin.h - -SOURCES += \ - $$PWD/app-search-plugin.cpp diff --git a/libsearch/common.h b/libsearch/common.h index 2a1638f..fea6b31 100644 --- a/libsearch/common.h +++ b/libsearch/common.h @@ -8,7 +8,7 @@ namespace UkuiSearch { #define CONTENT_DATABASE_PATH_SLOT 1 #define CONTENT_DATABASE_SUFFIX_SLOT 2 -static const int LABEL_MAX_WIDTH = 300; +static const int LABEL_MAX_WIDTH = 320; static const QString HOME_PATH = QDir::homePath(); static const QString INDEX_PATH = HOME_PATH + QStringLiteral("/.config/org.ukui/ukui-search/index_data"); @@ -19,8 +19,14 @@ static const QString INDEX_SEM = QStringLiteral("ukui-search-index-sem"); static const int OCR_MIN_SIZE = 200; static const QByteArray UKUI_SEARCH_SCHEMAS = QByteArrayLiteral("org.ukui.search.settings"); static const QString SEARCH_METHOD_KEY = QStringLiteral("fileIndexEnable"); -static const QString INDEX_DATABASE_VERSION = QStringLiteral("1.0.0"); -static const QString CONTENT_DATABASE_VERSION = QStringLiteral("1.0.0"); +/** + * changelog 1.0.1 修复部分中文字符在term中被截断的问题 + */ +static const QString INDEX_DATABASE_VERSION = QStringLiteral("1.0.1"); +/** + * changelog 1.1.0 增加文件修改时间value + */ +static const QString CONTENT_DATABASE_VERSION = QStringLiteral("1.1.0"); diff --git a/libsearch/development-files/header-files/UkuiSearchAppInfoTable b/libsearch/development-files/header-files/UkuiSearchAppInfoTable deleted file mode 100644 index 046c057..0000000 --- a/libsearch/development-files/header-files/UkuiSearchAppInfoTable +++ /dev/null @@ -1 +0,0 @@ -#include "app-info-table.h" diff --git a/libsearch/development-files/header-files/UkuiSearchController b/libsearch/development-files/header-files/UkuiSearchController deleted file mode 100644 index 6d87eca..0000000 --- a/libsearch/development-files/header-files/UkuiSearchController +++ /dev/null @@ -1 +0,0 @@ -#include "search-controller.h" diff --git a/libsearch/development-files/header-files/UkuiSearchPluginIface b/libsearch/development-files/header-files/UkuiSearchPluginIface index 94d4d98..63cd47e 100644 --- a/libsearch/development-files/header-files/UkuiSearchPluginIface +++ b/libsearch/development-files/header-files/UkuiSearchPluginIface @@ -1,6 +1,7 @@ #include "action-label.h" -#include "common-defines.h" +#include "action-transmiter.h" #include "plugin-iface.h" #include "data-queue.h" #include "search-plugin-iface.h" #include "search-task-plugin-iface.h" +#include "separation-line.h" diff --git a/libsearch/dirwatcher/dir-watcher.cpp b/libsearch/dirwatcher/dir-watcher.cpp index af6fe43..4f0442b 100644 --- a/libsearch/dirwatcher/dir-watcher.cpp +++ b/libsearch/dirwatcher/dir-watcher.cpp @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #include "dir-watcher.h" #include @@ -81,6 +99,16 @@ QStringList DirWatcher::blackListOfDir(const QString &dirPath) return reply.value(); } +QStringList DirWatcher::getBlockDirsOfUser() +{ + QDBusReply reply = m_dbusInterface->call("blockDirsForUser"); + if (!reply.isValid()) { + qCritical() << "blockDirsForUser call filed!"; + return QStringList(); + } + return reply.value(); +} + QStringList DirWatcher::currentSearchableDir() { QDBusReply reply = m_dbusInterface->call("currentSearchableDir"); @@ -101,9 +129,25 @@ QStringList DirWatcher::searchableDirForSearchApplication() return reply.value(); } +void DirWatcher::appendSearchDir(const QString &path) +{ + QDBusReply reply = m_dbusInterface->call("appendSearchDir", path); + if (!reply.isValid()) { + qCritical() << "appendSearchDir call filed!"; + } +} + +void DirWatcher::removeSearchDir(const QString &path) +{ + QDBusReply reply = m_dbusInterface->call("removeSearchDir", path); + if (!reply.isValid()) { + qCritical() << "removeSearchDir call filed!"; + } +} + void DirWatcher::appendIndexableListItem(const QString &path) { - QDBusReply reply = m_dbusInterface->call("appendIndexableListItem", path); + QDBusReply reply = m_dbusInterface->call("appendIndexableListItem", path); if (!reply.isValid()) { qCritical() << "appendIndexableListItem call filed!"; } diff --git a/libsearch/dirwatcher/dir-watcher.h b/libsearch/dirwatcher/dir-watcher.h index 9536c33..7a5b3b1 100644 --- a/libsearch/dirwatcher/dir-watcher.h +++ b/libsearch/dirwatcher/dir-watcher.h @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #ifndef MOUNTDISKLISTENER_H #define MOUNTDISKLISTENER_H @@ -21,6 +39,10 @@ public Q_SLOTS: QStringList searchableDirForSearchApplication(); QStringList blackListOfDir(const QString &dirPath); + QStringList getBlockDirsOfUser(); + + void appendSearchDir(const QString &path); + void removeSearchDir(const QString &path); void appendIndexableListItem(const QString &path); void removeIndexableListItem(const QString &path); void sendAppendSignal(const QString &path, const QStringList &blockList); diff --git a/libsearch/dirwatcher/dirwatcher.pri b/libsearch/dirwatcher/dirwatcher.pri deleted file mode 100644 index 4558940..0000000 --- a/libsearch/dirwatcher/dirwatcher.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/dir-watcher.h - -SOURCES += \ - $$PWD/dir-watcher.cpp diff --git a/libsearch/file-utils.cpp b/libsearch/file-utils.cpp index 89ccb03..4a9a45b 100644 --- a/libsearch/file-utils.cpp +++ b/libsearch/file-utils.cpp @@ -28,14 +28,181 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "gobject-template.h" #include "hanzi-to-pinyin.h" +#include "common.h" +#include "icon-loader.h" using namespace UkuiSearch; -size_t FileUtils::maxIndexCount = 0; -unsigned short FileUtils::indexStatus = 0; -QMap FileUtils::map_chinese2pinyin = QMap(); -static QMutex iconMutex; + +#define MAX_CONTENT_LENGTH 20480000 +/** + * @brief 查找elem的子节点 + * @param elem 起始节点 + * @param names 名称链 + * @param nodes 查找到的全部结果 + */ +void findNodes(const QDomElement &elem, QQueue &names, QList &nodes) +{ + QString targetName = names.dequeue(); + QDomNode node = elem.firstChild(); + while (!node.isNull()) { + QDomElement e = node.toElement(); + if (!e.isNull() && e.tagName() == targetName) { + if (names.empty()) { + nodes.append(e); + + } else { + findNodes(e, names, nodes); + break; + } + } + node = node.nextSibling(); + } +} + +void findNodesByAttr(const QDomElement &elem, QQueue &names, QList &nodes, const QString &attr, const QStringList &values) +{ + findNodes(elem, names, nodes); + + QList::iterator it = nodes.begin(); + while (it != nodes.end()) { + if ((*it).hasAttribute(attr) && values.contains((*it).attribute(attr))) { + it++; + } else { + it = nodes.erase(it); + } + } +} + +bool findNodeText(const QDomElement &elem, QQueue &names, QString &content) +{ + QList nodes; + findNodes(elem, names, nodes); + + for (const auto &node : nodes) { + content.append(node.text()); + if (content.length() >= MAX_CONTENT_LENGTH / 3) { + return true; + } + } + return false; +} + +void findNodeAttr(const QDomElement &elem, QQueue &names, const QString &attr, QStringList &attrs) +{ + QList nodes; + findNodes(elem, names, nodes); + + for (const auto &node : nodes) { + if (node.hasAttribute(attr)) { + attrs.append(node.attribute(attr)); + } + } +} + +void processUOFPPT(const QDomDocument &doc, QString &content) +{ + QDomElement rootElem = doc.documentElement(); + QList nodes; + QQueue names; //每个节点的名称 + names << "uof:演示文稿" << "演:主体" << "演:幻灯片集" << "演:幻灯片"; + + findNodes(rootElem, names, nodes); + + if (nodes.empty()) { + //TODO 在uof-ppt不存在锚点节点时,直接查找文本节点? + return; + } + + QStringList objs; + //每一个 演:幻灯片 -> 锚点 + for (const auto &node : nodes) { + names.clear(); + names << "uof:锚点"; + findNodeAttr(node, names, "uof:图形引用", objs); + } + + nodes.clear(); + names.clear(); + names << "uof:对象集" << "图:图形"; + findNodesByAttr(rootElem, names, nodes, "图:标识符", objs); + + if (nodes.empty()) { + return; + } + + QList paraNodes; //全部段落节点 + for (const auto &node : nodes) { + names.clear(); + names << "图:文本内容" << "字:段落"; + findNodes(node, names, paraNodes); + } + + nodes.clear(); + for (const auto &node : paraNodes) { + names.clear(); + names << "字:句"; + findNodes(node, names, nodes); //全部段落下的全部句节点 + } + + for (const auto &node : nodes) { + names.clear(); + names << "字:文本串"; + if (findNodeText(node, names, content)) { + break; + } + } +} + +bool loadZipFileToDoc(QuaZip &zipFile, QDomDocument &doc, const QString &fileName) +{ + if (!zipFile.isOpen() && !zipFile.open(QuaZip::mdUnzip)) { + return false; + } + + if (!zipFile.setCurrentFile(fileName)) { + return false; + } + + QuaZipFile file(&zipFile); + if (!file.open(QIODevice::ReadOnly)) { + return false; + } + + doc.clear(); + if (!doc.setContent(&file)) { + file.close(); + return false; + } + file.close(); + + return true; +} FileUtils::FileUtils() { } @@ -51,7 +218,7 @@ std::string FileUtils::makeDocUterm(QString path) { * @return */ QIcon FileUtils::getFileIcon(const QString &uri, bool checkValid) { - QMutexLocker locker(&iconMutex); + Q_UNUSED(checkValid) auto file = wrapGFile(g_file_new_for_uri(uri.toUtf8().constData())); auto info = wrapGFileInfo(g_file_query_info(file.get()->get(), G_FILE_ATTRIBUTE_STANDARD_ICON, @@ -59,7 +226,8 @@ QIcon FileUtils::getFileIcon(const QString &uri, bool checkValid) { nullptr, nullptr)); if(!G_IS_FILE_INFO(info.get()->get())) - return QIcon::fromTheme("unknown",QIcon(":/res/icons/unknown.svg")); + return IconLoader::loadIconQt("unknown",QIcon(":/res/icons/unknown.svg")); + GIcon *g_icon = g_file_info_get_icon(info.get()->get()); //do not unref the GIcon from info. @@ -68,7 +236,7 @@ QIcon FileUtils::getFileIcon(const QString &uri, bool checkValid) { if(icon_names) { auto p = icon_names; while(*p) { - QIcon icon = QIcon::fromTheme(*p); + QIcon icon = IconLoader::loadIconQt(*p); if(!icon.isNull()) { return icon; } else { @@ -77,63 +245,12 @@ QIcon FileUtils::getFileIcon(const QString &uri, bool checkValid) { } } } - return QIcon::fromTheme("unknown",QIcon(":/res/icons/unknown.svg")); -} - -/** - * @brief FileUtils::getAppIcon 获取应用图标 - * @param path .desktop文件的完整路径 - * @return - */ -QIcon FileUtils::getAppIcon(const QString &path) { - QByteArray ba; - ba = path.toUtf8(); - GKeyFile * keyfile; - keyfile = g_key_file_new(); - if(!g_key_file_load_from_file(keyfile, ba.data(), G_KEY_FILE_NONE, NULL)) { - g_key_file_free(keyfile); - return QIcon::fromTheme("unknown",QIcon(":/res/icons/unknown.svg")); - } - QString icon = QString(g_key_file_get_locale_string(keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL)); - g_key_file_free(keyfile); - if(QIcon::fromTheme(icon).isNull()) { - return QIcon(":/res/icons/desktop.png"); - } - return QIcon::fromTheme(icon); -} - -/** - * @brief FileUtils::getSettingIcon 获取设置图标 - * @param setting 设置项传入参数,格式为 About/About->Properties - * @param is_white 选择是否返回白色图标 - * @return - */ -QIcon FileUtils::getSettingIcon(const QString &setting, const bool is_white) { - QString name = setting.left(setting.indexOf("/")); - if(! name.isEmpty()) { - name.replace(QString(name.at(0)), QString(name.at(0).toUpper())); - } - QString path; - if(is_white) { - path = QString("/usr/share/ukui-control-center/shell/res/secondaryleftmenu/%1White.svg").arg(name); - } else { - path = QString("/usr/share/ukui-control-center/shell/res/secondaryleftmenu/%1.svg").arg(name); - } - QFile file(path); - if(file.exists()) { - return QIcon(path); - } else { - return QIcon::fromTheme("ukui-control-center", QIcon(":/res/icons/ukui-control-center.svg")); //无插件图标时,返回控制面板应用图标 -// if (is_white) { -// return QIcon(QString("/usr/share/ukui-control-center/shell/res/secondaryleftmenu/%1White.svg").arg("About")); -// } else { -// return QIcon(QString("/usr/share/ukui-control-center/shell/res/secondaryleftmenu/%1.svg").arg("About")); -// } - } + return IconLoader::loadIconQt("unknown", QIcon(":/res/icons/unknown.svg")); } QIcon FileUtils::getSettingIcon() { - return QIcon::fromTheme("ukui-control-center", QIcon(":/res/icons/ukui-control-center.svg")); //返回控制面板应用图标 + return IconLoader::loadIconQt("ukui-control-center", QIcon(":/res/icons/ukui-control-center.svg")); //返回控制面板应用图标 +// 返回控制面板应用图标 } /** @@ -185,10 +302,9 @@ QString FileUtils::getSettingName(const QString &setting) { bool FileUtils::isOrUnder(QString pathA, QString pathB) { - if(pathA[0] != "/") - pathA.prepend("/"); - if(pathB[0] != "/") - pathB.prepend("/"); + if (pathB == "/") { + return true; + } if(pathA.length() < pathB.length()) return false; @@ -199,24 +315,6 @@ bool FileUtils::isOrUnder(QString pathA, QString pathB) return false; } - -void FileUtils::loadHanziTable(const QString &fileName) { - QFile file(fileName); - if(!file.open(QFile::ReadOnly | QFile::Text)) { - qDebug("File: '%s' open failed!", file.fileName().toStdString().c_str()); - return; - } - - /* 读取汉字对照表文件并转换为QMap存储 */ - while(!file.atEnd()) { - QString content = QString::fromUtf8(file.readLine()); - FileUtils::map_chinese2pinyin[content.split(" ").last().trimmed()] = content.split(" ").first().split(","); - } - file.close(); - - return; -} - QMimeType FileUtils::getMimetype(const QString &path) { QMimeDatabase mdb; QMimeType type = mdb.mimeTypeForFile(path, QMimeDatabase::MatchContent); @@ -224,261 +322,8 @@ QMimeType FileUtils::getMimetype(const QString &path) { return type; } -//aborted -QString FileUtils::find(const QString &hanzi) { - // static QMap map = loadHanziTable("://index/pinyinWithoutTone.txt"); - // static QMap map; - QString output; - QStringList stringList = hanzi.split(""); - - /* 遍历查找汉字-拼音对照表的内容并将汉字替换为拼音 */ - for(const QString &str : stringList) { - if(FileUtils::map_chinese2pinyin.contains(str)) - output += FileUtils::map_chinese2pinyin[str].first(); - else - output += str; - } - - return output; -} - -//DFS多音字太多直接GG -void stitchMultiToneWordsDFS(const QString &hanzi, const QString &resultAllPinYin, const QString &resultFirst, QStringList &resultList) { - if(hanzi.size() == 0) { - resultList.append(resultAllPinYin); - resultList.append(resultFirst); - return; - } - if(FileUtils::map_chinese2pinyin.contains(hanzi.at(0))) { - for(auto i : FileUtils::map_chinese2pinyin[hanzi.at(0)]) { - stitchMultiToneWordsDFS(hanzi.right(hanzi.size() - 1), resultAllPinYin + i, resultFirst + i.at(0), resultList); - } - } else { - stitchMultiToneWordsDFS(hanzi.right(hanzi.size() - 1), resultAllPinYin + hanzi.at(0), resultFirst + hanzi.at(0), resultList); - } -} - -//BFS+Stack多音字太多会爆栈 -void stitchMultiToneWordsBFSStack(const QString &hanzi, QStringList &resultList) { - QString tempHanzi, resultAllPinYin, resultFirst; - QQueue tempQueue; - tempHanzi = hanzi; - int tempQueueSize = 0; - if(FileUtils::map_chinese2pinyin.contains(tempHanzi.at(0))) { - for(auto i : FileUtils::map_chinese2pinyin[tempHanzi.at(0)]) { - tempQueue.enqueue(i); - } - } else { - tempQueue.enqueue(tempHanzi.at(0)); - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - while(tempHanzi.size() != 0) { - tempQueueSize = tempQueue.size(); - if(FileUtils::map_chinese2pinyin.contains(tempHanzi.at(0))) { - for(int j = 0; j < tempQueueSize; ++j) { - for(auto i : FileUtils::map_chinese2pinyin[tempHanzi.at(0)]) { - tempQueue.enqueue(tempQueue.head() + i); - } - tempQueue.dequeue(); - } - } else { - for(int j = 0; j < tempQueueSize; ++j) { - tempQueue.enqueue(tempQueue.head() + tempHanzi.at(0)); - tempQueue.dequeue(); - } - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - } - while(!tempQueue.empty()) { - resultList.append(tempQueue.dequeue()); - } -} -//BFS+Heap,多音字太多会耗尽内存 -void stitchMultiToneWordsBFSHeap(const QString &hanzi, QStringList &resultList) { - QString tempHanzi, resultAllPinYin, resultFirst; - QQueue* tempQueue = new QQueue; - tempHanzi = hanzi; - int tempQueueSize = 0; - if(FileUtils::map_chinese2pinyin.contains(tempHanzi.at(0))) { - for(auto i : FileUtils::map_chinese2pinyin[tempHanzi.at(0)]) { - tempQueue->enqueue(i); - } - } else { - tempQueue->enqueue(tempHanzi.at(0)); - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - while(tempHanzi.size() != 0) { - tempQueueSize = tempQueue->size(); - if(FileUtils::map_chinese2pinyin.contains(tempHanzi.at(0))) { - for(int j = 0; j < tempQueueSize; ++j) { - for(auto i : FileUtils::map_chinese2pinyin[tempHanzi.at(0)]) { - tempQueue->enqueue(tempQueue->head() + i); - } - tempQueue->dequeue(); - } - } else { - for(int j = 0; j < tempQueueSize; ++j) { - tempQueue->enqueue(tempQueue->head() + tempHanzi.at(0)); - tempQueue->dequeue(); - } - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - } - while(!tempQueue->empty()) { - resultList.append(tempQueue->dequeue()); - } - delete tempQueue; - tempQueue = nullptr; -} - -//BFS+Heap+超过3个多音字只建一个索引,比较折中的方案 -void stitchMultiToneWordsBFSHeapLess3(const QString &hanzi, QStringList &resultList) { - QString tempHanzi, resultAllPinYin, resultFirst; - QQueue* tempQueue = new QQueue; - QQueue* tempQueueFirst = new QQueue; - tempHanzi = hanzi; - int tempQueueSize = 0; - int multiToneWordNum = 0; - for(auto i : hanzi) { - if(FileUtils::map_chinese2pinyin.contains(i)) { - if(FileUtils::map_chinese2pinyin[i].size() > 1) { - ++multiToneWordNum; - } - } - } - if(multiToneWordNum > 3) { - QString oneResult, oneResultFirst; - for(auto i : hanzi) { - if(FileUtils::map_chinese2pinyin.contains(i)) { - oneResult += FileUtils::map_chinese2pinyin[i].first(); - oneResultFirst += FileUtils::map_chinese2pinyin[i].first().at(0); - } else { - oneResult += i; - oneResultFirst += i; - } - } - resultList.append(oneResult); - resultList.append(oneResultFirst); - return; - } - - if(FileUtils::map_chinese2pinyin.contains(tempHanzi.at(0))) { - for(auto i : FileUtils::map_chinese2pinyin[tempHanzi.at(0)]) { - tempQueue->enqueue(i); - tempQueueFirst->enqueue(i.at(0)); - } - } else { - tempQueue->enqueue(tempHanzi.at(0)); - tempQueueFirst->enqueue(tempHanzi.at(0)); - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - while(tempHanzi.size() != 0) { - tempQueueSize = tempQueue->size(); - if(FileUtils::map_chinese2pinyin.contains(tempHanzi.at(0))) { - for(int j = 0; j < tempQueueSize; ++j) { - for(auto i : FileUtils::map_chinese2pinyin[tempHanzi.at(0)]) { - tempQueue->enqueue(tempQueue->head() + i); - tempQueueFirst->enqueue(tempQueueFirst->head() + i.at(0)); - } - tempQueue->dequeue(); - tempQueueFirst->dequeue(); - } - } else { - for(int j = 0; j < tempQueueSize; ++j) { - tempQueue->enqueue(tempQueue->head() + tempHanzi.at(0)); - tempQueueFirst->enqueue(tempQueueFirst->head() + tempHanzi.at(0)); - tempQueue->dequeue(); - tempQueueFirst->dequeue(); - } - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - } - while(!tempQueue->empty()) { - resultList.append(tempQueue->dequeue()); - resultList.append(tempQueueFirst->dequeue()); - } - delete tempQueue; - delete tempQueueFirst; - tempQueue = nullptr; - tempQueueFirst = nullptr; - return; -} - -//BFS+Stack+超过3个多音字只建一个索引,比较折中的方案 -void stitchMultiToneWordsBFSStackLess3(const QString &hanzi, QStringList &resultList) { - QString tempHanzi; - QQueue tempQueue; - QQueue tempQueueFirst; - tempHanzi = hanzi; - int tempQueueSize = 0; - int multiToneWordNum = 0; - - for (auto i:hanzi) { - if (HanZiToPinYin::getInstance()->isMultiTone(QString(i).toStdString())) - ++multiToneWordNum; - } - if(multiToneWordNum > 3) { - QString oneResult, oneResultFirst; - for(auto i : hanzi) { - QStringList results; - HanZiToPinYin::getInstance()->getResults(QString(i).toStdString(), results); - if(results.size()) { - oneResult += results.first(); - oneResultFirst += results.first().at(0); - } else { - oneResult += i; - oneResultFirst += i; - } - } - resultList.append(oneResult); - resultList.append(oneResultFirst); - return; - } - - QStringList results; - HanZiToPinYin::getInstance()->getResults(QString(tempHanzi.at(0)).toStdString(), results); - if(results.size()) { - for(auto i : results) { - tempQueue.enqueue(i); - tempQueueFirst.enqueue(i.at(0)); - } - } else { - tempQueue.enqueue(tempHanzi.at(0)); - tempQueueFirst.enqueue(tempHanzi.at(0)); - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - while(tempHanzi.size() != 0) { - HanZiToPinYin::getInstance()->getResults(QString(tempHanzi.at(0)).toStdString(), results); - tempQueueSize = tempQueue.size(); - if(results.size()) { - for(int j = 0; j < tempQueueSize; ++j) { - for(auto i : results) { - tempQueue.enqueue(tempQueue.head() + i); - tempQueueFirst.enqueue(tempQueueFirst.head() + i.at(0)); - } - tempQueue.dequeue(); - tempQueueFirst.dequeue(); - } - } else { - for(int j = 0; j < tempQueueSize; ++j) { - tempQueue.enqueue(tempQueue.head() + tempHanzi.at(0)); - tempQueueFirst.enqueue(tempQueueFirst.head() + tempHanzi.at(0)); - tempQueue.dequeue(); - tempQueueFirst.dequeue(); - } - } - tempHanzi = tempHanzi.right(tempHanzi.size() - 1); - } - while(!tempQueue.empty()) { - resultList.append(tempQueue.dequeue()); - resultList.append(tempQueueFirst.dequeue()); - } - return; -} - QStringList FileUtils::findMultiToneWords(const QString &hanzi) { QStringList output, results; - //stitchMultiToneWordsBFSStackLess3(hanzi, output); HanZiToPinYin::getInstance()->getResults(hanzi.toStdString(), results); QString oneResult(results.join("")); QString firstLetter; @@ -765,8 +610,10 @@ void FileUtils::getTxtContent(const QString &path, QString &textcontent) { uchardet_data_end(chardet); const char *codec = uchardet_get_charset(chardet); - if(QTextCodec::codecForName(codec) == 0) + if(QTextCodec::codecForName(codec) == nullptr) { qWarning() << "Unsupported Text encoding format" << path << QString::fromLocal8Bit(codec); + return; + } QTextStream stream(encodedString, QIODevice::ReadOnly); stream.setCodec(codec); @@ -887,62 +734,192 @@ QString FileUtils::escapeHtml(const QString &str) return temp; } -QString FileUtils::chineseSubString(const std::string &myStr, int start, int length) +QString FileUtils::getSnippet(const std::string &myStr, uint start, const QString &keyword) { - std::string afterSub = ""; - //越界保护 - if(start < 0 || length < 0){ - return " "; - } + QFont boldFont(qApp->font().family()); + boldFont.setPointSizeF(qApp->font().pointSizeF() + 2); + boldFont.setWeight(QFont::Bold); + QFontMetricsF boldMetricsF(boldFont); - QString sub = QString::fromStdString(myStr); - QFont ft(QApplication::font().family(),QApplication::font().pointSize()); - QFontMetrics fm (ft); + uint strLength = 240; + bool elideLeft(false); + std::string sub = myStr.substr(start, strLength); + QString content = QString::fromStdString(sub); - if (length >= myStr.length()) { - afterSub = myStr.substr(start,length); //截取; - if (fm.width(QString::fromStdString(afterSub)) >= 2*LABEL_MAX_WIDTH) { - sub = fm.elidedText(sub, Qt::ElideRight, 2*LABEL_MAX_WIDTH); //超过两行则省略 + //不够截往前补 + if (start + strLength > myStr.length()) { + //新的起始位置 + int newStart = myStr.length() - strLength; + + if (myStr.length() < strLength) { + newStart = 0; + sub = myStr; } else { - sub = fm.elidedText(sub, Qt::ElideLeft, 2*LABEL_MAX_WIDTH); //超过两行则省略 + sub = myStr.substr(newStart, strLength); } - return sub; - } - if (start + length <= myStr.length()) { - afterSub = myStr.substr(start,length); //截取 - sub = QString::fromStdString(afterSub); //转QString - if(start + length < myStr.length()){ - sub.replace(sub.length()-3,3,"…"); //替换后三位 - } else{ - sub.append("…"); //直接加 - } - sub = fm.elidedText(sub, Qt::ElideRight, 2*LABEL_MAX_WIDTH); //超过两行则省略 - } else { - int newStart = myStr.length()-length; //更新截取位置 - - afterSub = myStr.substr(newStart, length); - sub=QString::fromStdString(afterSub); - if (fm.width(QString::fromStdString(myStr.substr(newStart, start))) >= 2*LABEL_MAX_WIDTH) { - sub = fm.elidedText(sub, Qt::ElideLeft, 2*LABEL_MAX_WIDTH); - } else { - if (newStart + 3 < start) { - sub.replace(0,3,"…").append("…"); + if (horizontalAdvanceContainsKeyword(QString::fromStdString(myStr.substr(newStart, start)) + boldMetricsF.horizontalAdvance(keyword), keyword) > 2 * LABEL_MAX_WIDTH) { + if (horizontalAdvanceContainsKeyword(QString::fromStdString(myStr.substr(start)), keyword) <= 2 * LABEL_MAX_WIDTH) { + elideLeft = true; } else { - afterSub = myStr.substr(start, length); - sub = "…" + QString::fromStdString(afterSub); - sub.append("…"); + sub = myStr.substr(start); } - sub = fm.elidedText(sub, Qt::ElideRight, 2*LABEL_MAX_WIDTH); + } + content = QString::fromStdString(sub); + } + + QFont font(qApp->font().family()); + font.setPointSizeF(qApp->font().pointSizeF()); + QFontMetricsF fontMetricsF(font); + + qreal blockLength = 0; + qreal total = 0; + int lineCount = 0; + int normalLength = 0; + int boldLength = 0; + + QString snippet; + int boundaryStart = 0; + int boundaryEnd = 0; + QTextBoundaryFinder fm(QTextBoundaryFinder::Grapheme, content); + + if (!elideLeft) { + for (;fm.position() != -1;fm.toNextBoundary()) { + boundaryEnd = fm.position(); + QString word = content.mid(boundaryStart, boundaryEnd - boundaryStart); + if (boundaryStart == boundaryEnd) { + continue; + } + + if (keyword.toUpper().contains(word.toUpper())) { + if (normalLength) { + total += fontMetricsF.horizontalAdvance(content.mid(boundaryStart - normalLength, normalLength)); + normalLength = 0; + blockLength = 0; + } + boldLength += (boundaryEnd - boundaryStart); + blockLength = boldMetricsF.horizontalAdvance(content.mid(boundaryEnd - boldLength, boldLength)); + } else { + if (boldLength) { + total += boldMetricsF.horizontalAdvance(content.mid(boundaryStart - boldLength, boldLength)); + boldLength = 0; + blockLength = 0; + } + normalLength += (boundaryEnd - boundaryStart); + blockLength = fontMetricsF.horizontalAdvance(content.mid(boundaryEnd - normalLength, normalLength)); + + } + + if (total + blockLength >= LABEL_MAX_WIDTH && lineCount == 0) { + if (total + blockLength > LABEL_MAX_WIDTH) { + fm.toPreviousBoundary(); + snippet.append("\n"); + } else { + snippet.append(word).append("\n"); + boundaryStart = boundaryEnd; + } + normalLength = 0; + boldLength = 0; + lineCount++; + total = 0; + blockLength = 0; + continue; + } else if (total + blockLength >= LABEL_MAX_WIDTH && lineCount == 1) { + qreal distance = 0; + qreal wordSize = 0; + if (total + blockLength > LABEL_MAX_WIDTH) { + boundaryEnd = boundaryStart; + fm.toPreviousBoundary(); + } else { + snippet.append(word); + } + while (wordSize < fontMetricsF.horizontalAdvance("…")) { + boundaryStart = fm.position(); + + wordSize += keyword.toUpper().contains(content.mid(boundaryStart, boundaryEnd - boundaryStart).toUpper()) ? + boldMetricsF.horizontalAdvance(content.mid(boundaryStart, boundaryEnd - boundaryStart)) + : fontMetricsF.horizontalAdvance(content.mid(boundaryStart, boundaryEnd - boundaryStart)); + distance += (boundaryEnd - boundaryStart); + boundaryEnd = boundaryStart; + fm.toPreviousBoundary(); + } + snippet = snippet.left(snippet.size() - distance); + snippet.append("…"); + break; + } + snippet.append(word); + boundaryStart = boundaryEnd; + } + } else { + boundaryEnd = content.size(); + for (fm.toEnd(); fm.position() != -1; fm.toPreviousBoundary()) { + boundaryStart = fm.position(); + if (boundaryEnd == boundaryStart) { + continue; + } + + QString word = content.mid(boundaryStart, boundaryEnd - boundaryStart); + if (keyword.toUpper().contains(word.toUpper())) { + if (normalLength) { + total += fontMetricsF.horizontalAdvance(content.mid(boundaryEnd, normalLength)); + normalLength = 0; + blockLength = 0; + } + boldLength += (boundaryEnd - boundaryStart); + blockLength = boldMetricsF.horizontalAdvance(content.mid(boundaryStart, boldLength)); + } else { + if (boldLength) { + total += boldMetricsF.horizontalAdvance(content.mid(boundaryEnd, boldLength)); + boldLength = 0; + blockLength = 0; + } + normalLength += (boundaryEnd - boundaryStart); + blockLength = fontMetricsF.horizontalAdvance(content.mid(boundaryStart, normalLength)); + + } + + if (total + blockLength >= LABEL_MAX_WIDTH && lineCount == 0) { + if (total + blockLength > LABEL_MAX_WIDTH) { + fm.toNextBoundary(); + snippet.prepend("\n"); + } else { + snippet.prepend(word).prepend("\n"); + boundaryStart = boundaryEnd; + } + normalLength = 0; + boldLength = 0; + lineCount++; + total = 0; + blockLength = 0; + continue; + } else if (total + blockLength >= LABEL_MAX_WIDTH && lineCount == 1) { + qreal distance = 0; + qreal wordSize = 0; + if (total + blockLength > LABEL_MAX_WIDTH) { + boundaryStart = boundaryEnd; + fm.toNextBoundary(); + } else { + snippet.prepend(word); + } + while (wordSize < fontMetricsF.horizontalAdvance("…")) { + boundaryEnd = fm.position(); + QString firstLetter = content.mid(boundaryStart, boundaryEnd - boundaryStart); + wordSize += keyword.toUpper().contains(firstLetter.toUpper()) ? + boldMetricsF.horizontalAdvance(firstLetter) : fontMetricsF.horizontalAdvance(firstLetter); + distance += (boundaryEnd - boundaryStart); + boundaryStart = boundaryEnd; + fm.toNextBoundary(); + } + snippet = snippet.right(snippet.size() - distance); + snippet.prepend("…"); + break; + } + snippet.prepend(word); + boundaryEnd = boundaryStart; } } - return sub; -} -QIcon FileUtils::iconFromTheme(const QString &name, const QIcon &iconDefault) -{ - QMutexLocker locker(&iconMutex); - return QIcon::fromTheme(name, iconDefault); + return snippet; } bool FileUtils::isOpenXMLFileEncrypted(const QString &path) @@ -956,7 +933,7 @@ bool FileUtils::isOpenXMLFileEncrypted(const QString &path) return true; } //比较前四位是否为对应值来判断OpenXML类型文件是否加密 - if (encrypt[0] == 0x50 && encrypt[1] == 0x4b && encrypt[2] == 0x03 && encrypt[3] == 0x04) { + if ((encrypt[0] & 0x50) && (encrypt[1] & 0x4b) && (encrypt[2] & 0x03) && (encrypt[3] & 0x04)) { return false; } else { qDebug() << "Encrypt!" << path; @@ -1039,23 +1016,37 @@ bool FileUtils::isOcrSupportSize(QString path) QString FileUtils::getHtmlText(const QString &text, const QString &keyword) { - QString htmlString; + QString htmlString = QString("").arg(qApp->font().pointSizeF() + 2); bool boldOpenned = false; - for(int i = 0; i < text.length(); i++) { - if((keyword.toUpper()).contains(QString(text.at(i)).toUpper())) { + + QTextBoundaryFinder bf(QTextBoundaryFinder::Grapheme, text); + int start = 0; + for (;bf.position() != -1; bf.toNextBoundary()) { + int end = bf.position(); + if (end == start) { + continue; + } + if (keyword.toUpper().contains(text.mid(start, end - start).toUpper())) { if(! boldOpenned) { boldOpenned = true; - htmlString.append(QString("")); + htmlString.append(QString("")); } - htmlString.append(FileUtils::escapeHtml(QString(text.at(i)))); + htmlString.append(FileUtils::escapeHtml(text.mid(start, end - start))); } else { if(boldOpenned) { boldOpenned = false; - htmlString.append(QString("")); + htmlString.append(QString("")); } - htmlString.append(FileUtils::escapeHtml(QString(text.at(i)))); + htmlString.append(FileUtils::escapeHtml(text.mid(start, end - start))); } + start = end; } + htmlString.replace("\n", "
");//替换换行符 return "
" + htmlString + "
"; } @@ -1070,7 +1061,7 @@ QString FileUtils::wrapData(QLabel *p_label, const QString &text) QString wrapText = text; QFontMetrics fontMetrics = p_label->fontMetrics(); - int textSize = fontMetrics.width(wrapText); + int textSize = fontMetrics.horizontalAdvance(wrapText); if(textSize > LABEL_MAX_WIDTH){ int lastIndex = 0; @@ -1078,11 +1069,11 @@ QString FileUtils::wrapData(QLabel *p_label, const QString &text) for(int i = lastIndex; i < wrapText.length(); i++) { - if(fontMetrics.width(wrapText.mid(lastIndex, i - lastIndex)) == LABEL_MAX_WIDTH) { + if(fontMetrics.horizontalAdvance(wrapText.mid(lastIndex, i - lastIndex)) == LABEL_MAX_WIDTH) { lastIndex = i; wrapText.insert(i, '\n'); count++; - } else if(fontMetrics.width(wrapText.mid(lastIndex, i - lastIndex)) > LABEL_MAX_WIDTH) { + } else if(fontMetrics.horizontalAdvance(wrapText.mid(lastIndex, i - lastIndex)) > LABEL_MAX_WIDTH) { lastIndex = i; wrapText.insert(i - 1, '\n'); count++; @@ -1095,10 +1086,59 @@ QString FileUtils::wrapData(QLabel *p_label, const QString &text) } } } -// p_label->setText(wrapText); return wrapText; } +qreal FileUtils::horizontalAdvanceContainsKeyword(const QString &content, const QString &keyword) +{ + QFont boldFont(qApp->font().family()); + boldFont.setPointSizeF(qApp->font().pointSizeF() + 2); + boldFont.setWeight(QFont::Bold); + QFontMetricsF boldMetricsF(boldFont); + + QFont font(qApp->font().family()); + font.setPointSizeF(qApp->font().pointSizeF()); + QFontMetricsF fontMetricsF(font); + + QTextBoundaryFinder fm(QTextBoundaryFinder::Grapheme, content); + int start = 0; + + qreal contentSize = 0; + int boldLength = 0; + int normalLength = 0; + + for (;fm.position() != -1;fm.toNextBoundary()) { + int end = fm.position(); + if (end == start) { + continue; + } + QString letter = content.mid(start, end - start); + + if (keyword.toUpper().contains(letter.toUpper())) { + if (normalLength) { + contentSize += fontMetricsF.horizontalAdvance(content.mid(start - normalLength, normalLength)); + normalLength = 0; + } + boldLength += (end - start); + } else { + if (boldLength) { + contentSize += boldMetricsF.horizontalAdvance(content.mid(start - boldLength, boldLength)); + boldLength = 0; + } + normalLength += (end - start); + } + start = end; + } + + if (boldLength) { + contentSize += boldMetricsF.horizontalAdvance(content.right(boldLength)); + } + if (normalLength) { + contentSize += fontMetricsF.horizontalAdvance(content.right(normalLength)); + } + return contentSize; +} + /** * uof1.0解析 * 参考规范:GB/T 20916-2007 @@ -1163,124 +1203,9 @@ void FileUtils::getUOFTextContent(const QString &path, QString &textContent) file.close(); } -void FileUtils::processUOFPPT(const QDomDocument &doc, QString &content) -{ - QDomElement rootElem = doc.documentElement(); - QList nodes; - QQueue names; //每个节点的名称 - names << "uof:演示文稿" << "演:主体" << "演:幻灯片集" << "演:幻灯片"; - findNodes(rootElem, names, nodes); - if (nodes.empty()) { - //TODO 在uof-ppt不存在锚点节点时,直接查找文本节点? - return; - } - QStringList objs; - //每一个 演:幻灯片 -> 锚点 - for (const auto &node : nodes) { - names.clear(); - names << "uof:锚点"; - findNodeAttr(node, names, "uof:图形引用", objs); - } - - nodes.clear(); - names.clear(); - names << "uof:对象集" << "图:图形"; - findNodesByAttr(rootElem, names, nodes, "图:标识符", objs); - - if (nodes.empty()) { - return; - } - - QList paraNodes; //全部段落节点 - for (const auto &node : nodes) { - names.clear(); - names << "图:文本内容" << "字:段落"; - findNodes(node, names, paraNodes); - } - - nodes.clear(); - for (const auto &node : paraNodes) { - names.clear(); - names << "字:句"; - findNodes(node, names, nodes); //全部段落下的全部句节点 - } - - for (const auto &node : nodes) { - names.clear(); - names << "字:文本串"; - if (findNodeText(node, names, content)) { - break; - } - } -} - -/** - * @brief 查找elem的子节点 - * @param elem 起始节点 - * @param names 名称链 - * @param nodes 查找到的全部结果 - */ -void FileUtils::findNodes(const QDomElement &elem, QQueue &names, QList &nodes) -{ - QString targetName = names.dequeue(); - QDomNode node = elem.firstChild(); - while (!node.isNull()) { - QDomElement e = node.toElement(); - if (!e.isNull() && e.tagName() == targetName) { - if (names.empty()) { - nodes.append(e); - - } else { - findNodes(e, names, nodes); - break; - } - } - node = node.nextSibling(); - } -} - -inline void FileUtils::findNodesByAttr(const QDomElement &elem, QQueue &names, QList &nodes, const QString &attr, const QStringList &values) -{ - findNodes(elem, names, nodes); - - QList::iterator it = nodes.begin(); - while (it != nodes.end()) { - if ((*it).hasAttribute(attr) && values.contains((*it).attribute(attr))) { - it++; - } else { - it = nodes.erase(it); - } - } -} - -inline bool FileUtils::findNodeText(const QDomElement &elem, QQueue &names, QString &content) -{ - QList nodes; - findNodes(elem, names, nodes); - - for (const auto &node : nodes) { - content.append(node.text()); - if (content.length() >= MAX_CONTENT_LENGTH / 3) { - return true; - } - } - return false; -} - -inline void FileUtils::findNodeAttr(const QDomElement &elem, QQueue &names, const QString &attr, QStringList &attrs) -{ - QList nodes; - findNodes(elem, names, nodes); - - for (const auto &node : nodes) { - if (node.hasAttribute(attr)) { - attrs.append(node.attribute(attr)); - } - } -} /** * uof2.0解析 @@ -1389,30 +1314,6 @@ void FileUtils::getUOF2PPTContent(const QString &path, QString &textContent) } } -inline bool FileUtils::loadZipFileToDoc(QuaZip &zipFile, QDomDocument &doc, const QString &fileName) -{ - if (!zipFile.isOpen() && !zipFile.open(QuaZip::mdUnzip)) { - return false; - } - - if (!zipFile.setCurrentFile(fileName)) { - return false; - } - - QuaZipFile file(&zipFile); - if (!file.open(QIODevice::ReadOnly)) { - return false; - } - - doc.clear(); - if (!doc.setContent(&file)) { - file.close(); - return false; - } - file.close(); - - return true; -} /** * OFD文件解析 diff --git a/libsearch/file-utils.h b/libsearch/file-utils.h index 5fa5bc2..fdca51e 100644 --- a/libsearch/file-utils.h +++ b/libsearch/file-utils.h @@ -22,54 +22,21 @@ #ifndef FILEUTILS_H #define FILEUTILS_H #include -#include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include - #include "libsearch_global.h" -#include "common.h" -#include -//#define INITIAL_STATE 0 -//#define CREATING_INDEX 1 -//#define FINISH_CREATING_INDEX 2 -#define MAX_CONTENT_LENGTH 20480000 namespace UkuiSearch { class LIBSEARCH_EXPORT FileUtils { public: static QString getHtmlText(const QString &text, const QString &keyword); static QString setAllTextBold(const QString &name); static QString wrapData(QLabel *p_label, const QString &text); + static qreal horizontalAdvanceContainsKeyword(const QString &content, const QString &keyword); static std::string makeDocUterm(QString path); static QIcon getFileIcon(const QString &uri, bool checkValid = true); - static QIcon getAppIcon(const QString &path); - static QIcon getSettingIcon(const QString &setting, const bool is_white); static QIcon getSettingIcon(); static QString getFileName(const QString &uri); @@ -77,12 +44,7 @@ public: static QString getSettingName(const QString &setting); //A is or under B static bool isOrUnder(QString pathA, QString pathB); - - //chinese character to pinyin - static QMap map_chinese2pinyin; - static QString find(const QString &hanzi); static QStringList findMultiToneWords(const QString &hanzi); - static void loadHanziTable(const QString &fileName); //parse text,docx..... static QMimeType getMimetype(const QString &path); @@ -99,8 +61,7 @@ public: static int openFile(QString &path, bool openInDir = false); static bool copyPath(QString &path); static QString escapeHtml(const QString &str); - static QString chineseSubString(const std::string &myStr,int start,int length); - static QIcon iconFromTheme(const QString &name, const QIcon &iconDefault); + static QString getSnippet(const std::string &myStr, uint start, const QString &keyword); static bool isOpenXMLFileEncrypted(const QString &path); /** * @brief isEncrypedOrUnsupport @@ -110,16 +71,6 @@ public: */ static bool isEncrypedOrUnsupport(const QString &path, const QString &suffix); static bool isOcrSupportSize(QString path); - static size_t maxIndexCount; - static unsigned short indexStatus; - -private: - static void findNodes(const QDomElement &elem, QQueue &names, QList &nodes); - static inline void findNodesByAttr(const QDomElement&, QQueue&, QList&, const QString &, const QStringList&); - static inline bool findNodeText(const QDomElement &elem, QQueue &names, QString &content); - static inline void findNodeAttr(const QDomElement &elem, QQueue &names, const QString &attr, QStringList &attrs); - static void processUOFPPT(const QDomDocument &doc, QString &content); - static inline bool loadZipFileToDoc(QuaZip &zipFile, QDomDocument &doc, const QString &fileName); private: FileUtils(); diff --git a/libsearch/filesystemwatcher/file-system-watcher-private.h b/libsearch/filesystemwatcher/file-system-watcher-private.h index 9345270..dc5a169 100644 --- a/libsearch/filesystemwatcher/file-system-watcher-private.h +++ b/libsearch/filesystemwatcher/file-system-watcher-private.h @@ -37,7 +37,6 @@ public: FileSystemWatcherPrivate(FileSystemWatcher *parent); ~FileSystemWatcherPrivate(); - void addWatch(const QStringList &pathList); void addWatchWithBlackList(const QStringList &pathList, const QStringList &blackList); QStringList removeWatch(const QString &path); QString removeWatch(int wd); @@ -45,7 +44,6 @@ public: private: void init(); - void traverse(QStringList pathList); void addWatch(const QString &path); FileSystemWatcher::WatchEvents m_watchEvents; @@ -55,6 +53,7 @@ private: QSocketNotifier* m_notifier = nullptr; // wd -> url QHash m_watchPathHash; + QStringList m_watchedRootPaths; FileSystemWatcher *q = nullptr; bool m_recursive = true; diff --git a/libsearch/filesystemwatcher/file-system-watcher.cpp b/libsearch/filesystemwatcher/file-system-watcher.cpp index d55dd47..08c196b 100644 --- a/libsearch/filesystemwatcher/file-system-watcher.cpp +++ b/libsearch/filesystemwatcher/file-system-watcher.cpp @@ -21,6 +21,7 @@ #include "file-system-watcher-private.h" #include #include +#include #include #include #include @@ -30,7 +31,6 @@ #include "ukui-search-qdbus.h" #include "file-utils.h" using namespace UkuiSearch; - FileSystemWatcherPrivate::FileSystemWatcherPrivate(FileSystemWatcher *parent) : q(parent) { qDebug() << "setInotifyMaxUserWatches start"; @@ -50,31 +50,6 @@ FileSystemWatcherPrivate::~FileSystemWatcherPrivate() } } -void FileSystemWatcherPrivate::traverse(QStringList pathList) -{ - QQueue queue; - for(QString path : pathList) { - addWatch(path); - queue.enqueue(path); - } - if(!m_recursive) { - return; - } - QFileInfoList list; - QDir dir; - dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); - while(!queue.empty()) { - dir.setPath(queue.dequeue()); - list = dir.entryInfoList(); - for(auto i : list) { - if(!(i.isSymLink())) { - queue.enqueue(i.absoluteFilePath()); - addWatch(i.absoluteFilePath()); - } - } - } -} - void FileSystemWatcherPrivate::addWatch(const QString &path) { int wd = inotify_add_watch(m_inotifyFd, path.toStdString().c_str(), m_watchEvents | m_watchFlags); @@ -88,11 +63,6 @@ void FileSystemWatcherPrivate::addWatch(const QString &path) } } -void FileSystemWatcherPrivate::addWatch(const QStringList &pathList) -{ - traverse(pathList); -} - void FileSystemWatcherPrivate::addWatchWithBlackList(const QStringList &pathList, const QStringList &blackList) { QQueue bfs; @@ -105,10 +75,15 @@ void FileSystemWatcherPrivate::addWatchWithBlackList(const QStringList &pathList } } for(QString path : tmpPathList) { - addWatch(path); - bfs.enqueue(path); + if(!m_watchedRootPaths.contains(path)) { + addWatch(path); + bfs.enqueue(path); + m_watchedRootPaths.append(path); + } + } + if(!m_recursive) { + return; } - QFileInfoList list; QDir dir; QStringList tmpList = blackList; @@ -170,6 +145,7 @@ void FileSystemWatcherPrivate::clearAll() m_notifier = nullptr; } m_watchPathHash.clear(); + m_watchedRootPaths.clear(); init(); } @@ -219,12 +195,12 @@ FileSystemWatcher::~FileSystemWatcher() void FileSystemWatcher::addWatch(const QStringList &pathList) { - d->addWatch(pathList); + d->addWatchWithBlackList(pathList, QStringList()); } void FileSystemWatcher::addWatch(const QString &path) { - d->addWatch(QStringList(path)); + d->addWatchWithBlackList(QStringList(path), QStringList()); } void FileSystemWatcher::addWatchWithBlackList(const QStringList &pathList, const QStringList &blackList) @@ -234,6 +210,11 @@ void FileSystemWatcher::addWatchWithBlackList(const QStringList &pathList, const QStringList FileSystemWatcher::removeWatch(const QString &path) { + for(QString watchedPath : d->m_watchedRootPaths) { + if(FileUtils::isOrUnder(watchedPath, path)) { + d->m_watchedRootPaths.removeAll(watchedPath); + } + } return d->removeWatch(path); } @@ -274,57 +255,92 @@ void FileSystemWatcher::eventProcess(int socket) return; } -// qDebug() << "event mask:" << event->mask; +// qDebug() << "event mask:" << event->mask +// << "isDir:" << (event->mask & IN_ISDIR) +// << "event->wd:" << event->wd +// << "event->name" << QString(QByteArray::fromRawData(event->name, qstrnlen(event->name, event->len))) +// << "event->len" << event->len +// << "event->cookie" << event->cookie +// << "path:" << d->m_watchPathHash.value(event->wd); QString path; - if (event->mask & (EventDeleteSelf | EventMoveSelf)) { + if (event->mask & (EventDeleteSelf | EventMoveSelf | EventUnmount)) { path = d->m_watchPathHash.value(event->wd); + if(path.isEmpty()) { + i += sizeof(struct inotify_event) + event->len; + continue; + } } else { - path = d->m_watchPathHash[event->wd] + '/' + event->name; + QByteArray name = QByteArray::fromRawData(event->name, qstrnlen(event->name, event->len)); + path = d->m_watchPathHash[event->wd]; + if(name.isEmpty() || path.isEmpty()) { + i += sizeof(struct inotify_event) + event->len; + continue; + } + path.append("/").append(name); } if(event->mask & EventCreate) { // qDebug() << path << "--EventCreate"; Q_EMIT created(path, event->mask & IN_ISDIR); - if(event->mask & IN_ISDIR && d->m_recursive) { - if(!QFileInfo(path).isSymLink()){ - addWatch(QStringList(path)); + if(event->mask & IN_ISDIR) { + for(const QString &createdPath : traverse(path)) { + Q_EMIT created(createdPath, QFileInfo(createdPath).isDir()); } } } if (event->mask & EventDeleteSelf) { // qDebug() << path << "--EventDeleteSelf"; - if(event->mask & IN_ISDIR) { - d->removeWatch(event->wd); + if(d->m_watchedRootPaths.contains(path)) { +// qDebug() << "EventDeleteSelf send" << path; + //All folders under this one should be deleted. + for(const QString &removedPath : d->removeWatch(path)) { + Q_EMIT deleted(removedPath, true); + } + d->m_watchedRootPaths.removeAll(path); } - Q_EMIT deleted(path, event->mask & IN_ISDIR); } if (event->mask & EventDelete) { // qDebug() << path << "--EventDelete"; - // we watch all folders recursively. Thus, folder removing is reported in DeleteSelf. - if (!(event->mask & IN_ISDIR)) { + if (event->mask & IN_ISDIR) { + for(const QString &removedPath : d->removeWatch(path)) { + Q_EMIT deleted(removedPath, true); + } + } else { Q_EMIT deleted(path, false); } } if (event->mask & EventModify) { // qDebug() << path << "--EventModify"; - Q_EMIT modified(path); + if(!(event->mask & IN_ISDIR)) { + Q_EMIT modified(path); + } } if (event->mask & EventMoveSelf) { - //Problematic if the parent is not watched, otherwise - // handled by MoveFrom/MoveTo from the parent -// qDebug() << path << "--EventMoveSelf"; +// qDebug() << path << "--EventMoveSelf"; + if(d->m_watchedRootPaths.contains(path)) { + for(const QString &removedPath : d->removeWatch(path)) { + Q_EMIT moved(removedPath, true); + } + d->m_watchedRootPaths.removeAll(path); + } } if (event->mask & EventMoveFrom) { // qDebug() << path << "--EventMoveFrom"; - Q_EMIT moved(path, event->mask & IN_ISDIR); + if (event->mask & IN_ISDIR) { + for(const QString &removedPath : d->removeWatch(path)) { + Q_EMIT moved(removedPath, true); + } + } else { + Q_EMIT moved(path, false); + } } if (event->mask & EventMoveTo) { // qDebug() << path << "--EventMoveTo"; - Q_EMIT created(path, event->mask & IN_ISDIR); - if (event->mask & IN_ISDIR && d->m_recursive) { - if(!QFileInfo(path).isSymLink()){ - addWatch(QStringList(path)); + Q_EMIT moveTo(path, event->mask & IN_ISDIR); + if (event->mask & IN_ISDIR) { + for(const QString &createdPath : traverse(path)) { + Q_EMIT moveTo(createdPath, QFileInfo(createdPath).isDir()); } } } @@ -334,14 +350,12 @@ void FileSystemWatcher::eventProcess(int socket) } if (event->mask & EventUnmount) { // qDebug() << path << "--EventUnmount"; - if (event->mask & IN_ISDIR) { - d->removeWatch(event->wd); - } // This is present because a unmount event is sent by inotify after unmounting, by // which time the watches have already been removed. if (path != "/") { Q_EMIT unmounted(path, event->mask & IN_ISDIR); } + d->m_watchedRootPaths.removeAll(path); } if (event->mask & EventAttributeChange) { // qDebug() << path << "--EventAttributeChange"; @@ -370,3 +384,30 @@ void FileSystemWatcher::eventProcess(int socket) free(buf); } +QStringList FileSystemWatcher::traverse(QString &path) +{ + QStringList paths; + d->addWatch(path); + if(!d->m_recursive || QFileInfo(path).isSymLink()) { + return paths; + } + QQueue queue; + queue.enqueue(path); + + QFileInfoList list; + QDir dir; + dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + dir.setSorting(QDir::DirsFirst); + while(!queue.empty()) { + dir.setPath(queue.dequeue()); + list = dir.entryInfoList(); + for(auto i : list) { + if(i.isDir() && !(i.isSymLink())) { + queue.enqueue(i.absoluteFilePath()); + d->addWatch(i.absoluteFilePath()); + } + paths.append(i.absoluteFilePath()); + } + } + return paths; +} diff --git a/libsearch/filesystemwatcher/file-system-watcher.h b/libsearch/filesystemwatcher/file-system-watcher.h index e63826a..2b35768 100644 --- a/libsearch/filesystemwatcher/file-system-watcher.h +++ b/libsearch/filesystemwatcher/file-system-watcher.h @@ -153,8 +153,16 @@ Q_SIGNALS: */ void unmounted(const QString& path, bool isDir); + /** + * Emitted if a file is moved to one of the watched folders. + * Note:if the new file moved here overwrited a file already existed, there will not be a 'deleted' signal. + */ + void moveTo(const QString& path, bool isDir); + private Q_SLOTS: void eventProcess(int socket); + QStringList traverse(QString &path); + private: FileSystemWatcherPrivate* d = nullptr; diff --git a/libsearch/filesystemwatcher/file-system-watcher.pri b/libsearch/filesystemwatcher/file-system-watcher.pri deleted file mode 100644 index 6db39b6..0000000 --- a/libsearch/filesystemwatcher/file-system-watcher.pri +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/file-system-watcher-private.h \ - $$PWD/file-system-watcher.h - -SOURCES += \ - $$PWD/file-system-watcher.cpp - diff --git a/libsearch/global-settings-private.h b/libsearch/global-settings-private.h new file mode 100644 index 0000000..8050e12 --- /dev/null +++ b/libsearch/global-settings-private.h @@ -0,0 +1,32 @@ +#ifndef GLOBALSETTINGSPRIVATE_H +#define GLOBALSETTINGSPRIVATE_H + +#include "global-settings.h" +#include +#include +#include + +namespace UkuiSearch { +class GlobalSettingsPrivate : public QObject +{ + Q_OBJECT +public: + explicit GlobalSettingsPrivate(QObject *parent = nullptr); + const QVariant getValue(const QString&); + +Q_SIGNALS: + void valueChanged(const QString& key, QVariant value); + +private: + void setValue(const QString& key, const QVariant& value); + + QMutex m_mutex; + + QGSettings *m_transGsettings = nullptr; + QGSettings *m_themeGsettings = nullptr; + QMap m_cache; +}; +} + + +#endif // GLOBALSETTINGSPRIVATE_H diff --git a/libsearch/global-settings.cpp b/libsearch/global-settings.cpp index 44cb0ff..c60710f 100644 --- a/libsearch/global-settings.cpp +++ b/libsearch/global-settings.cpp @@ -18,47 +18,21 @@ * Modified by: zhangpengfei * */ -#include -#include + #include "global-settings.h" +#include "global-settings-private.h" +#include +#include +#include +#include + +#define CONTROL_CENTER_PERSONALISE_GSETTINGS_ID "org.ukui.control-center.personalise" +#define THEME_GSETTINGS_ID "org.ukui.style" using namespace UkuiSearch; -static GlobalSettings *globalInstance = nullptr; -GlobalSettings *GlobalSettings::getInstance() { - if(!globalInstance) { - globalInstance = new GlobalSettings; - } - return globalInstance; -} - -GlobalSettings::GlobalSettings(QObject *parent) : QObject(parent) +GlobalSettingsPrivate::GlobalSettingsPrivate(QObject *parent) : QObject(parent) { - //搜索黑名单过滤 - m_blockDirsSettings = new QSettings(BLOCK_DIRS, QSettings::IniFormat, this); - m_blockDirsSettings->setIniCodec(QTextCodec::codecForName("UTF-8")); - m_blockDirsSettings->setValue("These_are_block_dirs_conf_for_ukui_search","0"); - m_blockDirsSettings->sync(); - - m_confWatcher = new QFileSystemWatcher(this); - m_confWatcher->addPath(BLOCK_DIRS); - connect(m_confWatcher, &QFileSystemWatcher::fileChanged, this, [ & ]() { - m_blockDirsSettings->sync(); - m_confWatcher->addPath(BLOCK_DIRS); - }); - //搜索历史记录 - m_searchRecordSettings = new QSettings(SEARCH_HISTORY, QSettings::IniFormat, this); - m_searchRecordSettings->setIniCodec(QTextCodec::codecForName("UTF-8")); - for(QString i : m_searchRecordSettings->allKeys()) { - m_history.append(QUrl::fromPercentEncoding(i.toLocal8Bit())); - } - if(!QDBusConnection::sessionBus().connect("org.kylinssoclient.dbus", - "/org/kylinssoclient/path", - "org.freedesktop.kylinssoclient.interface", - "keyChanged", - this, SLOT(updateSearchHistory(QString)))) - qWarning() << "Kylinssoclient Dbus connect fail!"; - //全局页面透明度 //the default number of transparency for mainwindow is 0.7 setValue(TRANSPARENCY_KEY, 0.7); @@ -66,9 +40,10 @@ GlobalSettings::GlobalSettings(QObject *parent) : QObject(parent) m_transGsettings = new QGSettings(CONTROL_CENTER_PERSONALISE_GSETTINGS_ID, QByteArray(), this); connect(m_transGsettings, &QGSettings::changed, this, [ = ](const QString & key) { if(key == TRANSPARENCY_KEY) { - setValue(TRANSPARENCY_KEY, m_transGsettings->get(TRANSPARENCY_KEY).toDouble()); + double transparency = m_transGsettings->get(TRANSPARENCY_KEY).toDouble(); + setValue(TRANSPARENCY_KEY, transparency); qApp->paletteChanged(qApp->palette()); - Q_EMIT this->transparencyChanged(m_transGsettings->get(TRANSPARENCY_KEY).toDouble()); + Q_EMIT this->valueChanged(TRANSPARENCY_KEY, transparency); } }); if(m_transGsettings->keys().contains(TRANSPARENCY_KEY)) { @@ -86,7 +61,7 @@ GlobalSettings::GlobalSettings(QObject *parent) : QObject(parent) //当前主题改变时也发出paletteChanged信号,通知主界面刷新 setValue(STYLE_NAME_KEY, m_themeGsettings->get(STYLE_NAME_KEY).toString()); qApp->paletteChanged(qApp->palette()); - Q_EMIT this->styleChanged(m_themeGsettings->get(STYLE_NAME_KEY).toString()); + Q_EMIT this->valueChanged(STYLE_NAME_KEY, m_themeGsettings->get(STYLE_NAME_KEY).toString()); } else if(key == FONT_SIZE_KEY) { setValue(FONT_SIZE_KEY, m_themeGsettings->get(FONT_SIZE_KEY).toDouble()); qApp->paletteChanged(qApp->palette()); @@ -101,41 +76,9 @@ GlobalSettings::GlobalSettings(QObject *parent) : QObject(parent) setValue(FONT_SIZE_KEY, m_themeGsettings->get(FONT_SIZE_KEY).toDouble()); } } - - //文件索引与搜索插件相关设置 - setValue(FILE_INDEX_ENABLE_KEY, false); - setValue(WEB_ENGINE_KEY, "baidu"); - setValue(CONTENT_FUZZY_SEARCH_KEY, false); - if(QGSettings::isSchemaInstalled(UKUI_SEARCH_SCHEMAS)) { - m_searchGsettings = new QGSettings(UKUI_SEARCH_SCHEMAS, QByteArray(), this); - connect(m_searchGsettings, &QGSettings::changed, this, [ = ](const QString & key) { - if(key == FILE_INDEX_ENABLE_KEY) { - bool fileSearchEnable = m_searchGsettings->get(FILE_INDEX_ENABLE_KEY).toBool(); - setValue(FILE_INDEX_ENABLE_KEY, fileSearchEnable); - Q_EMIT fileSearchEnableChanged(fileSearchEnable); - } else if(key == WEB_ENGINE_KEY) { - QString webSearchEngine = m_searchGsettings->get(WEB_ENGINE_KEY).toString(); - setValue(WEB_ENGINE_KEY, webSearchEngine); - Q_EMIT webSearchEngineChanged(webSearchEngine); - } else if (key == CONTENT_FUZZY_SEARCH_KEY) { - bool contentFuzzySearch = m_searchGsettings->get(CONTENT_FUZZY_SEARCH_KEY).toBool(); - setValue(CONTENT_FUZZY_SEARCH_KEY, contentFuzzySearch); - Q_EMIT contentFuzzySearchEnableChanged(contentFuzzySearch); - } - }); - if(m_searchGsettings->keys().contains(FILE_INDEX_ENABLE_KEY)) { - setValue(FILE_INDEX_ENABLE_KEY, m_searchGsettings->get(FILE_INDEX_ENABLE_KEY).toBool()); - } - if(m_searchGsettings->keys().contains(WEB_ENGINE_KEY)) { - setValue(WEB_ENGINE_KEY, m_searchGsettings->get(WEB_ENGINE_KEY).toString()); - } - if(m_searchGsettings->keys().contains(CONTENT_FUZZY_SEARCH_KEY)) { - setValue(CONTENT_FUZZY_SEARCH_KEY, m_searchGsettings->get(CONTENT_FUZZY_SEARCH_KEY).toBool()); - } - } } -const QVariant GlobalSettings::getValue(const QString &key) { +const QVariant GlobalSettingsPrivate::getValue(const QString &key) { m_mutex.lock(); QVariant value = m_cache.value(key); @@ -143,70 +86,24 @@ const QVariant GlobalSettings::getValue(const QString &key) { return value; } -bool GlobalSettings::setBlockDirs(const QString &path, int &returnCode, bool remove) { - if(remove) { - if(path.isEmpty()) { - returnCode = PATH_EMPTY; - return false; - } - - m_blockDirsSettings->remove(path); - return true; - } - - //why QSetting's key can't start with "/"?? - QString pathKey = path.right(path.length() - 1); - - if (pathKey.endsWith(QLatin1Char('/'))) { - pathKey = pathKey.mid(0, pathKey.length() - 1); - } - - QStringList blockDirs = m_blockDirsSettings->allKeys(); - for(QString i : blockDirs) { - if(FileUtils::isOrUnder(pathKey, i)) { -// returnCode = QString(tr("My parent folder has been blocked!")); - returnCode = PATH_PARENT_BLOCKED; - return false; - } - - if(FileUtils::isOrUnder(i, pathKey)) - m_blockDirsSettings->remove(i); - } - m_blockDirsSettings->setValue(pathKey, "0"); - return true; -} - -QStringList GlobalSettings::getBlockDirs() { - return m_blockDirsSettings->allKeys(); -} - -void GlobalSettings::setSearchRecord(const QString &word, const QDateTime &time) { - QStringList keys = m_searchRecordSettings->allKeys(); - if(keys.contains(QString(QUrl::toPercentEncoding(word)))) - m_history.removeOne(word); - m_searchRecordSettings->setValue(QString(QUrl::toPercentEncoding(word)), time.toString("yyyy-MM-dd hh:mm:ss")); - if(keys.size() >= 20) - m_searchRecordSettings->remove(QString(QUrl::toPercentEncoding(m_history.takeFirst()))); - m_history.append(word); -} - -QStringList GlobalSettings::getSearchRecord() { - return m_history; -} - //this method is designed for main process settings only!! -void GlobalSettings::setValue(const QString &key, const QVariant &value) { +void GlobalSettingsPrivate::setValue(const QString &key, const QVariant &value) { m_mutex.lock(); m_cache.insert(key, value); m_mutex.unlock(); } -void GlobalSettings::updateSearchHistory(QString key) { - if(key == "search") { - m_searchRecordSettings->sync(); - m_history.clear(); - for(QString i : m_searchRecordSettings->allKeys()) { - m_history.append(QUrl::fromPercentEncoding(i.toLocal8Bit())); - } - } +GlobalSettings &GlobalSettings::getInstance() { + static GlobalSettings instance; + return instance; +} + +const QVariant GlobalSettings::getValue(const QString& key) +{ + return d->getValue(key); +} + +GlobalSettings::GlobalSettings(QObject *parent) : QObject(parent), d(new GlobalSettingsPrivate(this)) +{ + connect(d, &GlobalSettingsPrivate::valueChanged, this, &GlobalSettings::valueChanged); } diff --git a/libsearch/global-settings.h b/libsearch/global-settings.h index 806ec73..17bea52 100644 --- a/libsearch/global-settings.h +++ b/libsearch/global-settings.h @@ -22,45 +22,18 @@ #define GLOBALSETTINGS_H #include -#include -#include -#include -#include -#include -//#include -//If use pkg_config, it wont build succes,why????????? -//My demo can build access yet. -//MouseZhangZh -#include -#include -#include -#include +#include +#include #include "libsearch_global.h" -#include "file-utils.h" - -#define CONTROL_CENTER_PERSONALISE_GSETTINGS_ID "org.ukui.control-center.personalise" -#define TRANSPARENCY_KEY "transparency" -#define THEME_GSETTINGS_ID "org.ukui.style" -#define STYLE_NAME_KEY "styleName" -#define FONT_SIZE_KEY "systemFontSize" -#define ICON_THEME_KEY "iconThemeName" - -#define UKUI_SEARCH_SCHEMAS "org.ukui.search.settings" -#define FILE_INDEX_ENABLE_KEY "fileIndexEnable" -#define WEB_ENGINE_KEY "webEngine" -#define CONTENT_FUZZY_SEARCH_KEY "contentFuzzySearch" - -#define WEB_ENGINE "web_engine" -#define PATH_EMPTY 1; -#define PATH_NOT_IN_HOME 2; -#define PATH_PARENT_BLOCKED 3; - -#define BLOCK_DIRS QDir::homePath() + "/.config/org.ukui/ukui-search/ukui-search-block-dirs.conf" -#define SEARCH_HISTORY QDir::homePath() + "/.config/org.ukui/ukui-search/ukui-search-history.conf" -//#define CLOUD_HISTORY "history" -//#define CLOUD_APPLICATIONS "applications" namespace UkuiSearch { + +const static QString TRANSPARENCY_KEY = "transparency"; +const static QString STYLE_NAME_KEY = "styleName"; +const static QString FONT_SIZE_KEY = "systemFontSize"; +const static QString ICON_THEME_KEY = "iconThemeName"; + +class GlobalSettingsPrivate; /** * @brief The GlobalSettings class * 用于同步搜索应用的全局设置 @@ -69,48 +42,18 @@ namespace UkuiSearch { class LIBSEARCH_EXPORT GlobalSettings : public QObject { Q_OBJECT public: - static GlobalSettings *getInstance(); - const QVariant getValue(const QString&); - /** - * @brief setBlockDirs - * set path for blacklist,return true if success,otherwise return false. - * @param path path to be blocked - * @param returnMessage this message will be set when return false. - * @param true to remove blocking,false to set blocking,default set false. - * @return - */ - bool setBlockDirs(const QString& path, int &returnCode, bool remove = false); - QStringList getBlockDirs(); - void setSearchRecord(const QString &word, const QDateTime &time); - QStringList getSearchRecord(); - void updateSearchHistory(QString key); + static GlobalSettings& getInstance(); + const QVariant getValue(const QString& key); Q_SIGNALS: - void valueChanged(const QString&); - void transparencyChanged(const double&); - void styleChanged(const QString&); - void fileSearchEnableChanged(bool); - void webSearchEngineChanged(const QString&); - void contentFuzzySearchEnableChanged(bool); + void valueChanged(const QString& key, QVariant value); private: explicit GlobalSettings(QObject *parent = nullptr); - ~GlobalSettings() = default; - void setValue(const QString&, const QVariant&); - - QGSettings *m_transGsettings; - QGSettings *m_themeGsettings; - QGSettings *m_searchGsettings; - QSettings *m_blockDirsSettings; - QSettings *m_searchRecordSettings; - QMap m_cache; - QStringList m_history; - QFileSystemWatcher *m_confWatcher; - - QMutex m_mutex; -// size_t test = 0; - + GlobalSettings(const GlobalSettings&) = delete; + GlobalSettings& operator =(const GlobalSettings&) = delete; + GlobalSettingsPrivate *d; }; } diff --git a/libsearch/icon-loader.cpp b/libsearch/icon-loader.cpp new file mode 100644 index 0000000..2e0e8a4 --- /dev/null +++ b/libsearch/icon-loader.cpp @@ -0,0 +1,23 @@ +// +// Created by zpf on 2023/9/1. +// + +#include "icon-loader.h" +#include +#include +#include +namespace UkuiSearch { +static QMutex qtIconMutex; +static QMutex xdgIconMutex; +QIcon IconLoader::loadIconQt(const QString &name, const QIcon &fallback) +{ + QMutexLocker locker(&qtIconMutex); + return QIcon::fromTheme(name,fallback); +} + +QIcon IconLoader::loadIconXdg(const QString &name, const QIcon &fallback) +{ + QMutexLocker locker(&xdgIconMutex); + return XdgIcon::fromTheme("name",fallback); +} +} // UkuiSearch \ No newline at end of file diff --git a/libsearch/icon-loader.h b/libsearch/icon-loader.h new file mode 100644 index 0000000..d160196 --- /dev/null +++ b/libsearch/icon-loader.h @@ -0,0 +1,19 @@ +// +// Created by zpf on 2023/9/1. +// + +#ifndef UKUI_SEARCH_ICON_LOADER_H +#define UKUI_SEARCH_ICON_LOADER_H +#include +namespace UkuiSearch { + +class IconLoader +{ +public: + static QIcon loadIconQt(const QString &name, const QIcon &fallback = {}); + static QIcon loadIconXdg(const QString &name, const QIcon &fallback = {}); +}; + +} // UkuiSearch + +#endif //UKUI_SEARCH_ICON_LOADER_H diff --git a/libsearch/index/basic-indexer.cpp b/libsearch/index/basic-indexer.cpp index 87796c4..e96b0b6 100644 --- a/libsearch/index/basic-indexer.cpp +++ b/libsearch/index/basic-indexer.cpp @@ -18,9 +18,11 @@ * */ #include "basic-indexer.h" -#include "file-utils.h" +#include #include #include +#include +#include "file-utils.h" using namespace UkuiSearch; BasicIndexer::BasicIndexer(const QString& filePath): m_filePath(filePath) { @@ -47,14 +49,19 @@ bool BasicIndexer::index() QString indexName = info.fileName().toLower(); QStringList pinyinTextList = FileUtils::findMultiToneWords(info.fileName()); - int i = 0; int postingCount = 1; //terms post of Xapian document is started from 1! - while(postingCount <= indexName.size()) { - m_document.addPosting(QUrl::toPercentEncoding(indexName.at(i)).toStdString(), postingCount); - ++postingCount; - ++i; + int start = 0; + QTextBoundaryFinder bf(QTextBoundaryFinder::Grapheme, indexName); + for(; bf.position() != -1; bf.toNextBoundary()) { + int end = bf.position(); + if(bf.boundaryReasons() & QTextBoundaryFinder::EndOfItem) { + m_document.addPosting(QUrl::toPercentEncoding(indexName.mid(start, end - start)).toStdString(), postingCount); + ++postingCount; + } + start = end; } + for(QString& s : pinyinTextList) { i = 0; while(i < s.size()) { diff --git a/libsearch/index/batch-indexer.cpp b/libsearch/index/batch-indexer.cpp index 6ced291..470e2d5 100644 --- a/libsearch/index/batch-indexer.cpp +++ b/libsearch/index/batch-indexer.cpp @@ -19,8 +19,11 @@ */ #include "batch-indexer.h" #include -#include +#include +#include #include +#include +#include #include "file-utils.h" #include "basic-indexer.h" @@ -29,10 +32,11 @@ #include "writable-database.h" #include "compatible-define.h" using namespace UkuiSearch; -BatchIndexer::BatchIndexer(const QStringList &folders, const QStringList &blackList, QAtomicInt& stop, WorkMode mode, Targets target) +BatchIndexer::BatchIndexer(const QStringList &folders, const QStringList &blackList, QAtomicInt& indexStop, QAtomicInt &contentIndexStop, WorkMode mode, Targets target) : m_folders(folders), m_blackList(blackList), - m_stop(&stop), + m_indexStop(&indexStop), + m_contentIndexStop(&contentIndexStop), m_mode(mode), m_target(target) { @@ -40,23 +44,26 @@ BatchIndexer::BatchIndexer(const QStringList &folders, const QStringList &blackL void BatchIndexer::run() { - QTime t = QTime::currentTime(); - if(m_target == Target::None || m_stop->LOAD) { - Q_EMIT done(m_mode); + QElapsedTimer timer; + timer.start(); + if(m_target == Target::None || (m_indexStop->LOAD && m_contentIndexStop->LOAD)) { + Q_EMIT done(m_mode, m_target); return; } fetch(); if(m_target & Target::Basic) { basicIndex(); + Q_EMIT basicIndexDone(m_mode); } if(m_target & Target::Content) { contentIndex(); + Q_EMIT contentIndexDone(m_mode); } m_cache.clear(); malloc_trim(0); - qDebug() << "FirstRunIndexer: time :" << t.elapsed(); - Q_EMIT done(m_mode); + qDebug() << "FirstRunIndexer: time :" << timer.elapsed() << "milliseconds"; + Q_EMIT done(m_mode, m_target); } void BatchIndexer::fetch() @@ -160,7 +167,7 @@ void BatchIndexer::basicIndex() basicDb.commit(); Q_EMIT progress(IndexType::Basic, allSize, finishNum); //文件名索引很快 - if(m_stop->LOAD) { + if(m_indexStop->LOAD) { qDebug() << "Index stopped, abort basic index."; filesNeedIndex.clear(); return; @@ -171,7 +178,6 @@ void BatchIndexer::basicIndex() //TODO:xapian默认10000条自动commit一次,需要根据内存占用情况调整。 basicDb.commit(); Q_EMIT progress(IndexType::Basic, allSize, finishNum); - Q_EMIT basicIndexDone(finishNum); filesNeedIndex.clear(); qDebug() << "Finish basic index"; } @@ -179,7 +185,7 @@ void BatchIndexer::basicIndex() void BatchIndexer::contentIndex() { qDebug() << "Begin content index"; - if(m_stop->LOAD) { + if(m_contentIndexStop->LOAD) { qDebug() << "Index stopped, abort content index."; return; } @@ -196,7 +202,7 @@ void BatchIndexer::contentIndex() // bool ocrEnable = FileIndexerConfig::getInstance()->isOCREnable(); if(FileIndexerConfig::getInstance()->isOCREnable()) { qDebug() << "OCR enabled."; - suffixMap.unite(targetPhotographTypeMap); + suffixMap.INSERT(targetPhotographTypeMap); } if(m_mode == WorkMode::Rebuild) { contentDb.rebuild(); @@ -246,7 +252,7 @@ void BatchIndexer::contentIndex() uint batchSize = 0; uint finishNum = 0; for (QString path : filesNeedIndex) { - if(m_stop->LOAD) { + if(m_contentIndexStop->LOAD) { qDebug() << "Index stopped, interrupt content index."; filesNeedIndex.clear(); filesNeedOCRIndex.clear(); @@ -284,7 +290,7 @@ void BatchIndexer::contentIndex() batchSize = 0; int ocrFinishNum = 0; for(QString path : filesNeedOCRIndex) { - if(m_stop->LOAD) { + if(m_contentIndexStop->LOAD) { qDebug() << "Index stopped, interrupt content index."; filesNeedOCRIndex.clear(); return; @@ -310,6 +316,5 @@ void BatchIndexer::contentIndex() Q_EMIT progress(IndexType::Contents, allSize, finishNum + ocrFinishNum); filesNeedOCRIndex.clear(); qDebug() << "Finish OCR index."; - Q_EMIT contentIndexDone(finishNum + ocrFinishNum); qDebug() << "Finish content index"; } diff --git a/libsearch/index/batch-indexer.h b/libsearch/index/batch-indexer.h index 56361ab..eef2912 100644 --- a/libsearch/index/batch-indexer.h +++ b/libsearch/index/batch-indexer.h @@ -57,14 +57,19 @@ public: }; Q_DECLARE_FLAGS(Targets, Target) - BatchIndexer(const QStringList& folders, const QStringList& blackList, QAtomicInt& stop, WorkMode mode = WorkMode::Update, Targets target = Target::All); + BatchIndexer(const QStringList& folders, + const QStringList& blackList, + QAtomicInt& indexStop, + QAtomicInt& contentIndexStop, + WorkMode mode = WorkMode::Update, + Targets target = Target::All); void run() override; Q_SIGNALS: void progress(IndexType type, uint all, uint finished); - void basicIndexDone(int size); - void contentIndexDone(int size); - void done(WorkMode); + void basicIndexDone(WorkMode); + void contentIndexDone(WorkMode); + void done(WorkMode, Targets); private: void fetch(); @@ -73,7 +78,8 @@ private: QStringList m_folders; QStringList m_blackList; - QAtomicInt *m_stop = nullptr; + QAtomicInt *m_indexStop = nullptr; + QAtomicInt *m_contentIndexStop = nullptr; WorkMode m_mode; Targets m_target; QStringList m_cache; diff --git a/libsearch/index/compatible-define.h b/libsearch/index/compatible-define.h index bf23100..6b74515 100644 --- a/libsearch/index/compatible-define.h +++ b/libsearch/index/compatible-define.h @@ -1,12 +1,37 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef COMPATIBLEDEFINE_H #define COMPATIBLEDEFINE_H +#include #endif // COMPATIBLEDEFINE_H #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) //T QAtomicInteger::load() const #define LOAD load() + +//QMap &QMap::unite(const QMap &other) +#define INSERT(T) unite(T) #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) //T QAtomicInteger::loadRelaxed() const #define LOAD loadRelaxed() +//void QMap::insert(const QMap &map) +#define INSERT(T) insert(T) #endif diff --git a/libsearch/index/data-queue.cpp b/libsearch/index/data-queue.cpp deleted file mode 100644 index b06cd4f..0000000 --- a/libsearch/index/data-queue.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "data-queue.h" - -DataQueue::DataQueue() -{ - -} diff --git a/libsearch/index/data-queue.h b/libsearch/index/data-queue.h deleted file mode 100644 index 2af8741..0000000 --- a/libsearch/index/data-queue.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef DATAQUEUE_H -#define DATAQUEUE_H - - -class DataQueue -{ -public: - DataQueue(); -}; - -#endif // DATAQUEUE_H diff --git a/libsearch/index/database.cpp b/libsearch/index/database.cpp index dbb3b46..901d10e 100644 --- a/libsearch/index/database.cpp +++ b/libsearch/index/database.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "database.h" using namespace UkuiSearch; diff --git a/libsearch/index/database.h b/libsearch/index/database.h index bd7497b..7bbe648 100644 --- a/libsearch/index/database.h +++ b/libsearch/index/database.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef DATABASE_H #define DATABASE_H #include diff --git a/libsearch/index/file-content-indexer.cpp b/libsearch/index/file-content-indexer.cpp index 5dd23ee..585d8f9 100644 --- a/libsearch/index/file-content-indexer.cpp +++ b/libsearch/index/file-content-indexer.cpp @@ -18,6 +18,7 @@ * */ #include "file-content-indexer.h" +#include #include "file-reader.h" #include "file-utils.h" #include "chinese-segmentation.h" @@ -41,9 +42,7 @@ bool fileContentIndexer::index() } m_document.setData(content); - //'\xEF\xBC\x8C' is "," "\xE3\x80\x82" is "。" use three " " to replace ,to ensure the offset info. - content = content.replace("\t", " ").replace("\xEF\xBC\x8C", " ").replace("\xE3\x80\x82", " "); - std::vector term = ChineseSegmentation::getInstance()->callSegment(content.left(20480000).toStdString()); + std::vector term = ChineseSegmentation::getInstance()->callSegment(content); content.clear(); content.squeeze(); @@ -57,7 +56,10 @@ bool fileContentIndexer::index() m_document.addTerm("PARENTTERM" + FileUtils::makeDocUterm(m_filePath.section("/", 0, -2, QString::SectionIncludeLeadingSep))); m_document.addValue(1, m_filePath); m_document.addValue(2, suffix); - m_document.setIndexTime(info.lastModified().toString("yyyyMMddHHmmsszzz")); + + QString time = info.lastModified().toString("yyyyMMddHHmmsszzz"); + m_document.addSortableSerialiseValue(3, time); + m_document.setIndexTime(time); return true; } diff --git a/libsearch/index/file-indexer-config.cpp b/libsearch/index/file-indexer-config.cpp index 6db2a01..9cc0c1d 100644 --- a/libsearch/index/file-indexer-config.cpp +++ b/libsearch/index/file-indexer-config.cpp @@ -23,12 +23,14 @@ #include #include #define INDEX_SETTINGS QDir::homePath() + "/.config/org.ukui/ukui-search/ukui-search-service.conf" - +static const QString CONFIG_VERSION = QStringLiteral("1.0"); static const QByteArray UKUI_SEARCH_SCHEMAS = QByteArrayLiteral("org.ukui.search.settings"); static const QString FILE_INDEX_ENABLE_KEY = QStringLiteral("fileIndexEnable"); static const QString CONTENT_INDEX_ENABLE_KEY = QStringLiteral("contentIndexEnable"); +static const QString CONTENT_FUZZY_SEARCH_KEY = QStringLiteral("contentFuzzySearch"); static const QString OCR_ENABLE_KEY = QStringLiteral("ocrEnable"); static const QString META_DATA_INDEX_ENABLE_KEY = QStringLiteral("metaDataIndexEnable"); +static const QString CONFIG_VERSION_KEY = QStringLiteral("version"); static std::once_flag flag; static FileIndexerConfig *global_intance = nullptr; @@ -41,7 +43,7 @@ FileIndexerConfig *FileIndexerConfig::getInstance() return global_intance; } -FileIndexerConfig::FileIndexerConfig(QObject *parent) \ +FileIndexerConfig::FileIndexerConfig(QObject *parent) : QObject(parent), m_dirWatcher(DirWatcher::getDirWatcher()) { @@ -51,9 +53,28 @@ FileIndexerConfig::FileIndexerConfig(QObject *parent) \ const QByteArray id(UKUI_SEARCH_SCHEMAS); if(QGSettings::isSchemaInstalled(id)) { m_gsettings = new QGSettings(id, QByteArray(), this); + //保留旧版本配置 + if(m_gsettings->keys().contains(CONFIG_VERSION_KEY)) { + QString oldVersion = m_gsettings->get(CONFIG_VERSION_KEY).toString(); + if(oldVersion == "0.0") { + bool fileIndexEnable = false; + if(m_gsettings->keys().contains(FILE_INDEX_ENABLE_KEY)) { + fileIndexEnable = m_gsettings->get(FILE_INDEX_ENABLE_KEY).toBool(); + } + if(fileIndexEnable) { + if(m_gsettings->keys().contains(CONTENT_INDEX_ENABLE_KEY)) { + m_gsettings->set(CONTENT_INDEX_ENABLE_KEY, true); + } + } + m_gsettings->set(CONFIG_VERSION_KEY, CONFIG_VERSION); + } + } connect(m_gsettings, &QGSettings::changed, this, [ = ](const QString &key) { if(key == FILE_INDEX_ENABLE_KEY) { Q_EMIT this->fileIndexEnableStatusChanged(m_gsettings->get(FILE_INDEX_ENABLE_KEY).toBool()); + } else if(key == CONTENT_INDEX_ENABLE_KEY) { + Q_EMIT this->contentIndexEnableStatusChanged(m_gsettings->get(CONTENT_INDEX_ENABLE_KEY).toBool()); + } }); } else { @@ -95,7 +116,32 @@ bool FileIndexerConfig::isFileIndexEnable() bool FileIndexerConfig::isContentIndexEnable() { - return m_settings->value(CONTENT_INDEX_ENABLE_KEY, true).toBool(); + if(m_gsettings) { + if(m_gsettings->keys().contains(CONTENT_INDEX_ENABLE_KEY)) { + return m_gsettings->get(CONTENT_INDEX_ENABLE_KEY).toBool(); + } else { + qWarning() << "FileIndexerConfig: Can not find key:" << CONTENT_INDEX_ENABLE_KEY << "in" << UKUI_SEARCH_SCHEMAS; + return false; + } + } else { + qWarning() << "FileIndexerConfig:" << UKUI_SEARCH_SCHEMAS << " is not found!"; + return false; + } +} + +bool FileIndexerConfig::isFuzzySearchEnable() +{ + if(m_gsettings) { + if(m_gsettings->keys().contains(CONTENT_FUZZY_SEARCH_KEY)) { + return m_gsettings->get(CONTENT_FUZZY_SEARCH_KEY).toBool(); + } else { + qWarning() << "FileIndexerConfig: Can not find key:" << CONTENT_FUZZY_SEARCH_KEY << "in" << UKUI_SEARCH_SCHEMAS; + return false; + } + } else { + qWarning() << "FileIndexerConfig:" << UKUI_SEARCH_SCHEMAS << " is not found!"; + return false; + } } bool FileIndexerConfig::isOCREnable() diff --git a/libsearch/index/file-indexer-config.h b/libsearch/index/file-indexer-config.h index 3ba595c..1613015 100644 --- a/libsearch/index/file-indexer-config.h +++ b/libsearch/index/file-indexer-config.h @@ -23,7 +23,6 @@ #include #include #include -#include #include "dir-watcher.h" class FileIndexerConfig : public QObject @@ -51,6 +50,11 @@ public: * @return 是否启动文本内容索引 */ bool isContentIndexEnable(); + /** + * @brief isFuzzySearchEnable + * @return 是否启动模糊搜索 + */ + bool isFuzzySearchEnable(); /** * @brief isOCREnable * @return 是否激活OCR功能(文件内容索引) @@ -78,6 +82,11 @@ Q_SIGNALS: * 文件索引开关(基本索引) */ void fileIndexEnableStatusChanged(bool); + /** + * @brief fileIndexEnableStatusChanged + * 内容索引 + */ + void contentIndexEnableStatusChanged(bool); private: explicit FileIndexerConfig(QObject *parent = nullptr); @@ -86,7 +95,6 @@ private: DirWatcher *m_dirWatcher = nullptr; QGSettings *m_gsettings = nullptr; QSettings *m_settings = nullptr; - QAtomicInt m_stop; }; diff --git a/libsearch/index/file-reader.cpp b/libsearch/index/file-reader.cpp index f462efe..30c62e1 100644 --- a/libsearch/index/file-reader.cpp +++ b/libsearch/index/file-reader.cpp @@ -21,6 +21,7 @@ #include "file-utils.h" #include "binary-parser.h" #include "ocrobject.h" +#include "common.h" using namespace UkuiSearch; FileReader::FileReader(QObject *parent) : QObject(parent) { diff --git a/libsearch/index/file-search-plugin.cpp b/libsearch/index/file-search-plugin.cpp index 558f8e8..774c213 100644 --- a/libsearch/index/file-search-plugin.cpp +++ b/libsearch/index/file-search-plugin.cpp @@ -23,12 +23,13 @@ #include #include #include "search-manager.h" +#include "file-indexer-config.h" #define OCR_ICONLABLE_WITH 352 #define OCR_ICONLABLE_HEIGHT 247 using namespace UkuiSearch; -FileSearchPlugin::FileSearchPlugin(QObject *parent) : QObject(parent),m_settings(GlobalSettings::getInstance()) +FileSearchPlugin::FileSearchPlugin(QObject *parent) : QObject(parent) { SearchPluginIface::Actioninfo open { 0, tr("Open")}; SearchPluginIface::Actioninfo Openpath { 1, tr("Open path")}; @@ -60,7 +61,7 @@ void UkuiSearch::FileSearchPlugin::KeywordSearch(QString keyword, DataQueuegetValue(FILE_INDEX_ENABLE_KEY).toBool()) { + if(FileIndexerConfig::getInstance()->isFileIndexEnable()) { FileSearch *filesearch; filesearch = new FileSearch(searchResult, SearchManager::uniqueSymbolFile, keyword, FILE_SEARCH_VALUE, 1, 0, 5); m_pool.start(filesearch); @@ -80,23 +81,23 @@ void FileSearchPlugin::stopSearch() QList FileSearchPlugin::getActioninfo(int type) { + Q_UNUSED(type) return m_actionInfo; } void FileSearchPlugin::openAction(int actionkey, QString key, int type) { + Q_UNUSED(type) //TODO add some return message here. - qDebug() << "openAction!!!!!!!!"; switch (actionkey) { case 0: if(FileUtils::openFile(key) == -1) { QMessageBox msgBox(m_detailPage); - msgBox.setWindowModality(Qt::WindowModal); - msgBox.setStandardButtons(QMessageBox::Yes); - msgBox.setButtonText(QMessageBox::Yes, tr("Yes")); + msgBox.setModal(true); + msgBox.addButton(tr("OK"), QMessageBox::YesRole); msgBox.setIcon(QMessageBox::Information); msgBox.setText(tr("Can not get a default application for opening %1.").arg(key)); - msgBox.exec(); + msgBox.open(); } break; case 1: @@ -203,12 +204,11 @@ void FileSearchPlugin::initDetailPage() connect(m_actionLabel1, &ActionLabel::actionTriggered, [ & ](){ if(FileUtils::openFile(m_currentActionKey) == -1) { QMessageBox msgBox(m_detailPage); - msgBox.setWindowModality(Qt::WindowModal); - msgBox.setStandardButtons(QMessageBox::Yes); - msgBox.setButtonText(QMessageBox::Yes, tr("Yes")); + msgBox.setModal(true); + msgBox.addButton(tr("OK"), QMessageBox::YesRole); msgBox.setIcon(QMessageBox::Information); msgBox.setText(tr("Can not get a default application for opening %1.").arg(m_currentActionKey)); - msgBox.exec(); + msgBox.open(); } }); connect(m_actionLabel2, &ActionLabel::actionTriggered, [ & ](){ @@ -238,7 +238,7 @@ void FileSearchPlugin::initDetailPage() // return previewPage; //} -DirSearchPlugin::DirSearchPlugin(QObject *parent) : QObject(parent),m_settings(GlobalSettings::getInstance()) +DirSearchPlugin::DirSearchPlugin(QObject *parent) : QObject(parent) { SearchPluginIface::Actioninfo open { 0, tr("Open")}; SearchPluginIface::Actioninfo Openpath { 1, tr("Open path")}; @@ -270,7 +270,7 @@ void UkuiSearch::DirSearchPlugin::KeywordSearch(QString keyword, DataQueuegetValue(FILE_INDEX_ENABLE_KEY).toBool()) { + if(FileIndexerConfig::getInstance()->isFileIndexEnable()) { FileSearch *filesearch; filesearch = new FileSearch(searchResult, SearchManager::uniqueSymbolDir, keyword, DIR_SEARCH_VALUE, 1, 0, 5); m_pool.start(filesearch); @@ -290,11 +290,13 @@ void DirSearchPlugin::stopSearch() QList DirSearchPlugin::getActioninfo(int type) { + Q_UNUSED(type) return m_actionInfo; } void DirSearchPlugin::openAction(int actionkey, QString key, int type) { + Q_UNUSED(type) //TODO add some return message here. switch (actionkey) { case 0: @@ -302,6 +304,7 @@ void DirSearchPlugin::openAction(int actionkey, QString key, int type) break; case 1: FileUtils::openFile(key, true); + break; case 2: FileUtils::copyPath(key); default: @@ -421,17 +424,26 @@ void DirSearchPlugin::initDetailPage() // return nullptr; //} -FileContengSearchPlugin::FileContengSearchPlugin(QObject *parent) : QObject(parent),m_settings(GlobalSettings::getInstance()) +FileContengSearchPlugin::FileContengSearchPlugin(QObject *parent) : QObject(parent) { SearchPluginIface::Actioninfo open { 0, tr("Open")}; SearchPluginIface::Actioninfo Openpath { 1, tr("Open path")}; SearchPluginIface::Actioninfo CopyPath { 2, tr("Copy Path")}; m_actionInfo << open << Openpath << CopyPath; m_pool.setMaxThreadCount(1); + m_thumbnailPool.setMaxThreadCount(1); m_pool.setExpiryTimeout(1000); initDetailPage(); } +FileContengSearchPlugin::~FileContengSearchPlugin() +{ + m_pool.clear(); + m_thumbnailPool.clear(); + m_thumbnailPool.waitForDone(); + m_pool.waitForDone(); +} + const QString FileContengSearchPlugin::name() { return "File Content Search"; @@ -454,9 +466,9 @@ void UkuiSearch::FileContengSearchPlugin::KeywordSearch(QString keyword, DataQue SearchManager::m_mutexContent.unlock(); m_keyWord = keyword; - if(m_settings->getValue(FILE_INDEX_ENABLE_KEY).toBool()) { + if(FileIndexerConfig::getInstance()->isContentIndexEnable()) { FileContentSearch *fileContentSearch; - fileContentSearch = new FileContentSearch(searchResult, SearchManager::uniqueSymbolContent, keyword, m_settings->getValue(CONTENT_FUZZY_SEARCH_KEY).toBool(), 0, 5); + fileContentSearch = new FileContentSearch(searchResult, SearchManager::uniqueSymbolContent, keyword, FileIndexerConfig::getInstance()->isFuzzySearchEnable(), 0, 5); m_pool.start(fileContentSearch); } } @@ -466,15 +478,19 @@ void FileContengSearchPlugin::stopSearch() SearchManager::m_mutexContent.lock(); ++SearchManager::uniqueSymbolContent; SearchManager::m_mutexContent.unlock(); + m_thumbnailPool.clear(); + m_pool.clear(); } QList FileContengSearchPlugin::getActioninfo(int type) { + Q_UNUSED(type) return m_actionInfo; } void FileContengSearchPlugin::openAction(int actionkey, QString key, int type) { + Q_UNUSED(type) //TODO add some return message here. switch (actionkey) { case 0: @@ -482,6 +498,7 @@ void FileContengSearchPlugin::openAction(int actionkey, QString key, int type) break; case 1: FileUtils::openFile(key, true); + break; case 2: FileUtils::copyPath(key); default: @@ -491,23 +508,33 @@ void FileContengSearchPlugin::openAction(int actionkey, QString key, int type) QWidget *FileContengSearchPlugin::detailPage(const ResultInfo &ri) { + if(ri.actionKey == m_currentActionKey) { + return m_detailPage; + } if (1 == ri.type) { - QPixmap pixmap; - if(pixmap.load(ri.actionKey)) { - pixmap = pixmap.scaled(OCR_ICONLABLE_WITH, OCR_ICONLABLE_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation); - m_detailLyt->setContentsMargins(8, (OCR_ICONLABLE_HEIGHT-pixmap.height())/2 + 8, 16, 0); - } else { - pixmap = ri.icon.pixmap(120, 120); - m_detailLyt->setContentsMargins(8, 50, 16, 0); - } + auto creator = new ThumbnailCreator(ri.actionKey); + connect(creator, &ThumbnailCreator::ready, this, [&](QString uri, const QImage &image){ + if(uri != m_currentActionKey) { + return; + } + QPixmap pixmap = QPixmap::fromImage(image); + if(!pixmap.isNull()) { + m_iconLabel->setPixmap(pixmap.scaled(OCR_ICONLABLE_WITH, OCR_ICONLABLE_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_detailLyt->setContentsMargins(8, (OCR_ICONLABLE_HEIGHT-pixmap.height())/2 + 8, 16, 0); + } else { + m_iconLabel->setPixmap(ri.icon.pixmap(120, 120)); + } + }, Qt::QueuedConnection); + m_thumbnailPool.start(creator); - m_iconLabel->setPixmap(pixmap); + m_iconLabel->setPixmap({}); + m_detailLyt->setContentsMargins(8, 50, 16, 0); m_pluginLabel->setText(tr("OCR")); m_snippetLabel->hide(); } else { m_iconLabel->setPixmap(ri.icon.pixmap(120, 120)); m_pluginLabel->setText(tr("File")); - m_snippetLabel->setText(getHtmlText(wrapData(m_snippetLabel,ri.description.at(0).value), m_keyWord)); + m_snippetLabel->setText(ri.description.at(0).value); m_snippetLabel->show(); m_detailLyt->setContentsMargins(8, 50, 16, 0); } @@ -556,18 +583,18 @@ QString FileContengSearchPlugin::wrapData(QLabel *p_label, const QString &text) QString wrapText = text; QFontMetrics fontMetrics = p_label->fontMetrics(); - int textSize = fontMetrics.width(wrapText); + int textSize = fontMetrics.horizontalAdvance(wrapText); if(textSize > LABEL_MAX_WIDTH){ int lastIndex = 0; int count = 0; for(int i = lastIndex; i < wrapText.length(); i++) { - if(fontMetrics.width(wrapText.mid(lastIndex, i - lastIndex)) == LABEL_MAX_WIDTH) { + if(fontMetrics.horizontalAdvance(wrapText.mid(lastIndex, i - lastIndex)) == LABEL_MAX_WIDTH) { lastIndex = i; wrapText.insert(i, '\n'); count++; - } else if(fontMetrics.width(wrapText.mid(lastIndex, i - lastIndex)) > LABEL_MAX_WIDTH) { + } else if(fontMetrics.horizontalAdvance(wrapText.mid(lastIndex, i - lastIndex)) > LABEL_MAX_WIDTH) { lastIndex = i; wrapText.insert(i - 1, '\n'); count++; @@ -680,3 +707,14 @@ void FileContengSearchPlugin::initDetailPage() //{ // return nullptr; //} + +ThumbnailCreator::ThumbnailCreator(QString url, QObject *parent): QObject(parent) +{ + setAutoDelete(true); + m_url = url; +} + +void ThumbnailCreator::run() +{ + Q_EMIT ready(m_url, QImage(m_url)); +} diff --git a/libsearch/index/file-search-plugin.h b/libsearch/index/file-search-plugin.h index b289cee..888ae0a 100644 --- a/libsearch/index/file-search-plugin.h +++ b/libsearch/index/file-search-plugin.h @@ -34,6 +34,7 @@ #include "action-label.h" #include "separation-line.h" #include "global-settings.h" +#include "icon-loader.h" namespace UkuiSearch { //internal plugin @@ -45,7 +46,7 @@ public: PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); - const QIcon icon() {return QIcon::fromTheme("folder");} + const QIcon icon() {return IconLoader::loadIconQt("folder");} void setEnable(bool enable) {m_enable = enable;} bool isEnable() {return m_enable;} QString getPluginName(); @@ -90,7 +91,6 @@ private: bool m_enable = true; QList m_actionInfo; QThreadPool m_pool; - GlobalSettings *m_settings = nullptr; }; class LIBSEARCH_EXPORT DirSearchPlugin : public QObject, public SearchPluginIface @@ -101,7 +101,7 @@ public: PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); - const QIcon icon() {return QIcon::fromTheme("folder");} + const QIcon icon() {return IconLoader::loadIconQt("folder");} void setEnable(bool enable) {m_enable = enable;} bool isEnable() {return m_enable;} QString getPluginName(); @@ -145,7 +145,6 @@ private: bool m_enable = true; QList m_actionInfo; QThreadPool m_pool; - GlobalSettings *m_settings = nullptr; }; class LIBSEARCH_EXPORT FileContengSearchPlugin : public QObject, public SearchPluginIface @@ -153,10 +152,11 @@ class LIBSEARCH_EXPORT FileContengSearchPlugin : public QObject, public SearchPl Q_OBJECT public: FileContengSearchPlugin(QObject *parent = nullptr); + ~FileContengSearchPlugin(); PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); - const QIcon icon() {return QIcon::fromTheme("folder");} + const QIcon icon() {return IconLoader::loadIconQt("folder");} void setEnable(bool enable) {m_enable = enable;} bool isEnable() {return m_enable;} QString getPluginName(); @@ -203,7 +203,22 @@ private: bool m_enable = true; QList m_actionInfo; QThreadPool m_pool; - GlobalSettings *m_settings = nullptr; + QThreadPool m_thumbnailPool; +}; +class ThumbnailCreator : public QObject, public QRunnable +{ + Q_OBJECT +public: + ThumbnailCreator(QString url, QObject *parent = nullptr); + +protected: + void run() override; + +Q_SIGNALS: + void ready(QString url, const QImage &image); + +private: + QString m_url; }; } diff --git a/libsearch/index/file-watcher.cpp b/libsearch/index/file-watcher.cpp index 758ce36..c30e385 100644 --- a/libsearch/index/file-watcher.cpp +++ b/libsearch/index/file-watcher.cpp @@ -26,6 +26,7 @@ FileWatcher::FileWatcher(QObject *parent) : QObject(parent), m_config(FileIndexe m_pendingFileQUeue = PendingFileQueue::getInstance(); connect(m_watcher, &FileSystemWatcher::created, this, &FileWatcher::onFileCreated); + connect(m_watcher, &FileSystemWatcher::moveTo, this, &FileWatcher::onFileMoveTo); connect(m_watcher, &FileSystemWatcher::modified, this, &FileWatcher::onFileModefied); connect(m_watcher, &FileSystemWatcher::deleted, this, &FileWatcher::onFileDeletedOrMoved); connect(m_watcher, &FileSystemWatcher::moved, this, &FileWatcher::onFileDeletedOrMoved); @@ -87,6 +88,14 @@ void FileWatcher::onFileCreated(const QString &path, bool isDir) m_pendingFileQUeue->enqueue(file); } +void FileWatcher::onFileMoveTo(const QString &path, bool isDir) +{ + PendingFile file(path); + file.setIsDir(isDir); + file.setMoveTo(); + m_pendingFileQUeue->enqueue(file); +} + void FileWatcher::onFileModefied(const QString &path) { PendingFile file(path); diff --git a/libsearch/index/file-watcher.h b/libsearch/index/file-watcher.h index 88fefc5..de4b159 100644 --- a/libsearch/index/file-watcher.h +++ b/libsearch/index/file-watcher.h @@ -62,6 +62,7 @@ Q_SIGNALS: private: void onFileCreated(const QString& path, bool isDir); + void onFileMoveTo(const QString& path, bool isDir); void onFileModefied(const QString& path); void onFileDeletedOrMoved(const QString& path, bool isDir); FileSystemWatcher *m_watcher = nullptr; diff --git a/libsearch/index/index-scheduler.cpp b/libsearch/index/index-scheduler.cpp index 6600abe..eba2320 100644 --- a/libsearch/index/index-scheduler.cpp +++ b/libsearch/index/index-scheduler.cpp @@ -27,26 +27,38 @@ IndexScheduler::IndexScheduler(QObject *parent) : m_statusRecorder(IndexStatusRecorder::getInstance()), m_config(FileIndexerConfig::getInstance()), m_state(Startup), - m_stop(0) + m_indexStop(0), + m_contentIndexStop(0) { qRegisterMetaType("IndexerState"); qRegisterMetaType("BatchIndexer::WorkMode"); + qRegisterMetaType("WorkMode"); + qRegisterMetaType("Targets"); m_threadPool.setMaxThreadCount(1); connect(&m_fileWatcher, &FileWatcher::filesUpdate, this, &IndexScheduler::updateIndex); connect(m_config, &FileIndexerConfig::fileIndexEnableStatusChanged, this, &IndexScheduler::fileIndexEnable); + connect(m_config, &FileIndexerConfig::contentIndexEnableStatusChanged, this, &IndexScheduler::contentIndexEnable); + connect(m_config, &FileIndexerConfig::appendIndexDir, this, &IndexScheduler::addNewPath); connect(m_config, &FileIndexerConfig::removeIndexDir, this, &IndexScheduler::removeIndex); m_state = Startup; + BatchIndexer::Targets targets = BatchIndexer::Target::None; if(m_config->isFileIndexEnable()) { - start(); + targets |= BatchIndexer::Target::Basic; } else { - m_stop.fetchAndStoreRelaxed(1); + m_indexStop.fetchAndStoreRelaxed(1); } + if(m_config->isContentIndexEnable()) { + targets |= BatchIndexer::Target::Content; + } else { + m_contentIndexStop.fetchAndStoreRelaxed(1); + } + start(targets); } void IndexScheduler::addNewPath(const QString &folders, const QStringList &blackList) { - if(m_stop.LOAD) { + if(m_indexStop.LOAD && m_contentIndexStop.LOAD) { qDebug() << "Index Scheduler is being stopped, add operation will be executed when started up next time."; return; } @@ -55,9 +67,11 @@ void IndexScheduler::addNewPath(const QString &folders, const QStringList &black BatchIndexer::Targets target = BatchIndexer::Target::None; if(m_config->isFileIndexEnable()) { target |= BatchIndexer::Target::Basic; + m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); } if(m_config->isContentIndexEnable()) { target |= BatchIndexer::Target::Content; + m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); } BatchIndexer::WorkMode mode = BatchIndexer::WorkMode::Add; startIndexJob(QStringList() << folders, blackList, mode, target); @@ -68,52 +82,33 @@ void IndexScheduler::addNewPath(const QString &folders, const QStringList &black void IndexScheduler::removeIndex(const QString &folders) { - if(m_stop.LOAD) { + if(m_indexStop.LOAD && m_contentIndexStop.LOAD) { qDebug() << "Index Scheduler is being stopped, remove operation will be executed when started up next time."; return; } m_fileWatcher.removeWatch(folders, true); } -void IndexScheduler::stop() +void IndexScheduler::stop(BatchIndexer::Targets target) { - m_stop.fetchAndStoreRelaxed(1); - m_fileWatcher.removeWatch(); - m_threadPool.clear(); - m_threadPool.waitForDone(-1); - m_state = Stop; - qDebug() << "Index scheduler has been stopped."; - Q_EMIT stateChange(m_state); -} - -void IndexScheduler::start() -{ - qDebug() << "Index scheduler start."; - if(!m_isFirstRunFinished || !m_isRebuildFinished) { - qDebug() << "Index scheduler running, start operation ignored. FirstRun finished: " << m_isFirstRunFinished << "Rebuild finished: " << m_isRebuildFinished; - return; + if(target & BatchIndexer::Target::Basic) { + m_indexStop.fetchAndStoreRelaxed(1); + m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Off); + qDebug() << "File index has been stopped."; } - m_stop.fetchAndStoreRelaxed(0); - m_state = Running; - Q_EMIT stateChange(m_state); - BatchIndexer::Targets rebuiltTarget = checkAndRebuild(); - - BatchIndexer::WorkMode mode = BatchIndexer::WorkMode::Update; - BatchIndexer::Targets target = BatchIndexer::Target::None; - - //如果数据库被执行过重建,那么跳过增量更新步骤。 - if(m_config->isFileIndexEnable() && !(rebuiltTarget & BatchIndexer::Target::Basic)) { - target |= BatchIndexer::Target::Basic; - m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); + if(target & BatchIndexer::Target::Content) { + m_contentIndexStop.fetchAndStoreRelaxed(1); + m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Off); + qDebug() << "File content index has been stopped."; } - if(m_config->isContentIndexEnable() && !(rebuiltTarget & BatchIndexer::Target::Content)) { - target |= BatchIndexer::Target::Content; - m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); + if(m_indexStop.LOAD && m_contentIndexStop.LOAD) { + m_fileWatcher.removeWatch(); + m_threadPool.clear(); + m_threadPool.waitForDone(-1); + m_state = Stop; + qDebug() << "Index scheduler has been stopped."; + Q_EMIT stateChange(m_state); } - startIndexJob(m_config->currentIndexableDir(), m_config->currentBlackListOfIndex(), mode, target); - - //启动监听 - m_fileWatcher.installWatches(); } IndexScheduler::IndexerState IndexScheduler::getIndexState() @@ -121,27 +116,83 @@ IndexScheduler::IndexerState IndexScheduler::getIndexState() return m_state; } -BatchIndexer::Targets IndexScheduler::checkAndRebuild() +void IndexScheduler::start(BatchIndexer::Targets target) +{ + qDebug() << "Index scheduler start." << target; + //检查是否有任务未完成 + BatchIndexer::Targets tmpTargets = BatchIndexer::Target::None; + if(target & BatchIndexer::Basic) { + if(m_indexFirstRunFinished && m_indexRebuildFinished) { + tmpTargets |= BatchIndexer::Target::Basic; + } + } + if(target & BatchIndexer::Content) { + if(m_contentIndexFirstRunFinished && m_contentIndexRebuildFinished) { + tmpTargets |= BatchIndexer::Target::Content; + } + } + if(tmpTargets == BatchIndexer::Target::None) { + qDebug() << "Index scheduler running, start operation ignored." + << "FirstRun finished: " << m_indexFirstRunFinished + << "Rebuild finished: " << m_indexRebuildFinished + << "Content index firstRun finished: " << m_contentIndexFirstRunFinished + << "Content index rebuild finished: " << m_contentIndexRebuildFinished; + return; + } + + //打开异步控制开关 + if(target & BatchIndexer::Basic) { + m_indexStop.fetchAndStoreRelaxed(0); + } + if(target & BatchIndexer::Content) { + m_contentIndexStop.fetchAndStoreRelaxed(0); + } + //将索引调度器状态设置为运行中 + m_state = Running; + Q_EMIT stateChange(m_state); + + //检查是否有数据库需要重建并且执行重建 + BatchIndexer::Targets rebuiltTarget = checkAndRebuild(tmpTargets); + + BatchIndexer::WorkMode mode = BatchIndexer::WorkMode::Update; + BatchIndexer::Targets startTarget = BatchIndexer::Target::None; + + //如果数据库被执行过重建,那么跳过增量更新步骤。 + if((tmpTargets & BatchIndexer::Target::Basic) && !(rebuiltTarget & BatchIndexer::Target::Basic)) { + startTarget |= BatchIndexer::Target::Basic; + m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); + } + if((tmpTargets & BatchIndexer::Target::Content) && !(rebuiltTarget & BatchIndexer::Target::Content)) { + startTarget |= BatchIndexer::Target::Content; + m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Updating); + } + startIndexJob(m_config->currentIndexableDir(), m_config->currentBlackListOfIndex(), mode, startTarget); + + //启动监听 + m_fileWatcher.installWatches(); +} + +BatchIndexer::Targets IndexScheduler::checkAndRebuild(BatchIndexer::Targets target) { BatchIndexer::WorkMode mode = BatchIndexer::WorkMode::Rebuild; - BatchIndexer::Targets target = BatchIndexer::Target::None; - if((m_statusRecorder->getStatus(INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error - || !m_statusRecorder->versionCheck(INDEX_DATABASE_VERSION_KEY, INDEX_DATABASE_VERSION)) - && m_config->isFileIndexEnable()) { + BatchIndexer::Targets rebuildTarget = BatchIndexer::Target::None; + if((target & BatchIndexer::Target::Basic) && m_config->isFileIndexEnable() && + (m_statusRecorder->getStatus(INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error + || !m_statusRecorder->versionCheck(INDEX_DATABASE_VERSION_KEY, INDEX_DATABASE_VERSION))) { qDebug() << "Basic database need rebuild"; - target |= BatchIndexer::Target::Basic; + rebuildTarget |= BatchIndexer::Target::Basic; m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Initializing); } - if((m_statusRecorder->getStatus(CONTENT_INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error - || !m_statusRecorder->versionCheck(CONTENT_DATABASE_VERSION_KEY, CONTENT_DATABASE_VERSION)) - && m_config->isFileIndexEnable()) { + if((target & BatchIndexer::Target::Content) && m_config->isContentIndexEnable() && + (m_statusRecorder->getStatus(CONTENT_INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error + || !m_statusRecorder->versionCheck(CONTENT_DATABASE_VERSION_KEY, CONTENT_DATABASE_VERSION))) { qDebug() << "Content database need rebuild"; - target |= BatchIndexer::Target::Content; + rebuildTarget |= BatchIndexer::Target::Content; m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Initializing); } - startIndexJob(m_config->currentIndexableDir(), m_config->currentBlackListOfIndex(), mode, target); - return target; + startIndexJob(m_config->currentIndexableDir(), m_config->currentBlackListOfIndex(), mode, rebuildTarget); + return rebuildTarget; } void IndexScheduler::startIndexJob(const QStringList& folders,const QStringList& blackList, BatchIndexer::WorkMode mode, BatchIndexer::Targets target) @@ -149,78 +200,66 @@ void IndexScheduler::startIndexJob(const QStringList& folders,const QStringList& if(BatchIndexer::Target::None != target) { switch (mode) { case BatchIndexer::WorkMode::Add: - m_isAddNewPathFinished = false; + m_addNewPathFinished = false; break; case BatchIndexer::WorkMode::Rebuild: - m_isRebuildFinished = false; + if(target & BatchIndexer::Basic) { + m_indexRebuildFinished = false; + } + if(target & BatchIndexer::Content) { + m_contentIndexRebuildFinished = false; + } break; case BatchIndexer::WorkMode::Update: - m_isFirstRunFinished = false; + if(target & BatchIndexer::Basic) { + m_indexFirstRunFinished = false; + } + if(target & BatchIndexer::Content) { + m_contentIndexFirstRunFinished = false; + } break; default: break; } - BatchIndexer *indexer = new BatchIndexer(folders, blackList, m_stop, mode, target); + BatchIndexer *indexer = new BatchIndexer(folders, blackList, m_indexStop, m_contentIndexStop, mode, target); connect(indexer, &BatchIndexer::done, this, &IndexScheduler::firstRunFinished, Qt::QueuedConnection); - connect(indexer, &BatchIndexer::progress, this, &IndexScheduler::process); - - connect(indexer, &BatchIndexer::basicIndexDone, this, [&](uint size){ - bool success = false; - if(!(m_statusRecorder->getStatus(INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error)) { - m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Ready); - success = true; - } - Q_EMIT basicIndexDone(size, success); - }); - - connect(indexer, &BatchIndexer::contentIndexDone, this, [&](uint size){ - bool success = false; - if(!(m_statusRecorder->getStatus(CONTENT_INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error)) { - m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Ready); - success = true; - } - Q_EMIT contentIndexDone(size, success); - }); - + connect(indexer, &BatchIndexer::progress, this, &IndexScheduler::process, Qt::QueuedConnection); + connect(indexer, &BatchIndexer::basicIndexDone, this, &IndexScheduler::onBasicIndexDone, Qt::QueuedConnection); + connect(indexer, &BatchIndexer::contentIndexDone, this, &IndexScheduler::onContentIndexDone, Qt::QueuedConnection); m_threadPool.start(indexer); } } void IndexScheduler::fileIndexEnable(bool enable) { - //Fix me: 快速反复开关会导致反复执行增量更新操作,可优化。 if(enable) { - start(); + start(BatchIndexer::Basic); } else { - stop(); + stop(BatchIndexer::Basic); + } +} + +void IndexScheduler::contentIndexEnable(bool enable) +{ + if(enable) { + start(BatchIndexer::Content); + } else { + stop(BatchIndexer::Content); } } void IndexScheduler::updateIndex(const QVector &files) { qDebug() << "updateIndex====="; - m_isUpdateFinished = false; + m_updateFinished = false; m_state = Running; - IndexUpdater *updateJob = new IndexUpdater(files, m_stop); + IndexUpdater *updateJob = new IndexUpdater(files, m_indexStop, m_contentIndexStop); connect(updateJob, &IndexUpdater::done, this, &IndexScheduler::updateFinished, Qt::QueuedConnection); m_threadPool.start(updateJob); } -void IndexScheduler::firstRunFinished(BatchIndexer::WorkMode mode) +void IndexScheduler::firstRunFinished() { - switch (mode) { - case BatchIndexer::WorkMode::Add: - m_isAddNewPathFinished = true; - break; - case BatchIndexer::WorkMode::Rebuild: - m_isRebuildFinished = true; - break; - case BatchIndexer::WorkMode::Update: - m_isFirstRunFinished = true; - break; - default: - break; - } if(isIdle()) { m_state = Idle; Q_EMIT stateChange(m_state); @@ -229,7 +268,7 @@ void IndexScheduler::firstRunFinished(BatchIndexer::WorkMode mode) void IndexScheduler::updateFinished() { - m_isUpdateFinished = true; + m_updateFinished = true; if(isIdle()) { m_state = Idle; Q_EMIT stateChange(m_state); @@ -238,5 +277,55 @@ void IndexScheduler::updateFinished() bool IndexScheduler::isIdle() { - return m_isFirstRunFinished && m_isAddNewPathFinished && m_isUpdateFinished && m_isRebuildFinished; + return m_indexFirstRunFinished && m_contentIndexFirstRunFinished + && m_addNewPathFinished + && m_updateFinished + && m_indexRebuildFinished && m_contentIndexRebuildFinished; +} + +void IndexScheduler::onBasicIndexDone(BatchIndexer::WorkMode mode) +{ + switch (mode) { + case BatchIndexer::WorkMode::Add: + m_addNewPathFinished = true; + break; + case BatchIndexer::WorkMode::Rebuild: + m_indexRebuildFinished = true; + break; + case BatchIndexer::WorkMode::Update: + m_indexFirstRunFinished = true; + break; + default: + break; + } + + bool success = false; + if(!(m_statusRecorder->getStatus(INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error)) { + m_statusRecorder->setStatus(INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Ready); + success = true; + } + Q_EMIT basicIndexDone(success); +} + +void IndexScheduler::onContentIndexDone(BatchIndexer::WorkMode mode) +{ + switch (mode) { + case BatchIndexer::WorkMode::Add: + m_addNewPathFinished = true; + break; + case BatchIndexer::WorkMode::Rebuild: + m_contentIndexRebuildFinished = true; + break; + case BatchIndexer::WorkMode::Update: + m_contentIndexFirstRunFinished = true; + break; + default: + break; + } + bool success = false; + if(!(m_statusRecorder->getStatus(CONTENT_INDEX_DATABASE_STATE_KEY).toInt() == IndexStatusRecorder::State::Error)) { + m_statusRecorder->setStatus(CONTENT_INDEX_DATABASE_STATE_KEY, IndexStatusRecorder::State::Ready); + success = true; + } + Q_EMIT contentIndexDone(success); } diff --git a/libsearch/index/index-scheduler.h b/libsearch/index/index-scheduler.h index 1a074a7..7e64400 100644 --- a/libsearch/index/index-scheduler.h +++ b/libsearch/index/index-scheduler.h @@ -54,23 +54,27 @@ public: * @param folders 要移除索引的目录 */ Q_SCRIPTABLE void removeIndex(const QString& folders); - Q_SCRIPTABLE void stop(); - Q_SCRIPTABLE void start(); + Q_SCRIPTABLE IndexerState getIndexState(); Q_SIGNALS: void stateChange(IndexerState); void process(IndexType type, uint all, uint finished); - void basicIndexDone(uint size, bool success); - void contentIndexDone(uint size, bool success); + void basicIndexDone(bool success); + void contentIndexDone(bool success); void done(); private Q_SLOTS: + void start(BatchIndexer::Targets target); + void stop(BatchIndexer::Targets target); void fileIndexEnable(bool enable); + void contentIndexEnable(bool enable); void updateIndex(const QVector& files); - void firstRunFinished(BatchIndexer::WorkMode mode); + void firstRunFinished(); void updateFinished(); bool isIdle(); + void onBasicIndexDone(BatchIndexer::WorkMode mode); + void onContentIndexDone(BatchIndexer::WorkMode mode); private: /** @@ -78,19 +82,24 @@ private: * 检查数据库状态,数据库状态处于 IndexStatusRecorder::State::Error 时,开始重建任务。 * @return 返回需要重建的数据库 */ - BatchIndexer::Targets checkAndRebuild(); + BatchIndexer::Targets checkAndRebuild(BatchIndexer::Targets target = BatchIndexer::All); void startIndexJob(const QStringList &folders, const QStringList &blackList, BatchIndexer::WorkMode mode, BatchIndexer::Targets target); FileWatcher m_fileWatcher; IndexStatusRecorder *m_statusRecorder = nullptr; FileIndexerConfig *m_config = nullptr; IndexerState m_state; - QAtomicInt m_stop; + QAtomicInt m_indexStop; + QAtomicInt m_contentIndexStop; QThreadPool m_threadPool; - bool m_isFirstRunFinished = true; - bool m_isRebuildFinished = true; - bool m_isUpdateFinished = true; - bool m_isAddNewPathFinished = true; + bool m_indexFirstRunFinished = true; + bool m_contentIndexFirstRunFinished = true; + + bool m_indexRebuildFinished = true; + bool m_contentIndexRebuildFinished = true; + + bool m_updateFinished = true; + bool m_addNewPathFinished = true; }; } #endif // INDEXSCHEDULER_H diff --git a/libsearch/index/index-status-recorder.h b/libsearch/index/index-status-recorder.h index 157bc15..72a83b9 100644 --- a/libsearch/index/index-status-recorder.h +++ b/libsearch/index/index-status-recorder.h @@ -39,7 +39,8 @@ public: Initializing = 0, Error = 1, Ready = 2, - Updating = 3 + Updating = 3, + Off = 4 }; Q_ENUM(State) diff --git a/libsearch/index/index-updater.cpp b/libsearch/index/index-updater.cpp index 7c05611..5d73fac 100644 --- a/libsearch/index/index-updater.cpp +++ b/libsearch/index/index-updater.cpp @@ -25,17 +25,19 @@ #include "file-content-indexer.h" #include "common.h" #include "file-utils.h" +#include "compatible-define.h" using namespace UkuiSearch; -IndexUpdater::IndexUpdater(const QVector& files, QAtomicInt &stop) - : m_cache(files), - m_stop(&stop) +IndexUpdater::IndexUpdater(const QVector& files, QAtomicInt& indexstop, QAtomicInt& contentIndexstop) + : m_cache(files), + m_indexStop(&indexstop), + m_contentIndexStop(&contentIndexstop) { } -void IndexUpdater::UpdateIndex() +void IndexUpdater::updateIndex() { //fix me: How should I delete metadata of files below a folder - //that has been deleted(When a file watcher signal comes which only contains folder info)? - if(FileIndexerConfig::getInstance()->isFileIndexEnable()) { + //which has been deleted(When a file watcher signal comes which only contains folder info)? + if(FileIndexerConfig::getInstance()->isFileIndexEnable() && !m_indexStop->LOAD) { WritableDatabase basicDb(DataBaseType::Basic); if(!basicDb.open()) { qWarning() << "Basic db open failed, fail to update index"; @@ -61,11 +63,7 @@ void IndexUpdater::UpdateIndex() basicDb.commit(); qDebug() << "===finish update basic index==="; } - if(FileIndexerConfig::getInstance()->isContentIndexEnable()) { - if(m_stop->load()) { - qDebug() << "Index stopped, abort update content index."; - return; - } + if(FileIndexerConfig::getInstance()->isContentIndexEnable() && !m_contentIndexStop->LOAD) { WritableDatabase contentDb(DataBaseType::Content); if(!contentDb.open()) { qWarning() << "Content db open failed, fail to update index"; @@ -75,7 +73,7 @@ void IndexUpdater::UpdateIndex() QMap suffixMap = targetFileTypeMap; //ocr if(FileIndexerConfig::getInstance()->isOCREnable()) { - suffixMap.unite(targetPhotographTypeMap); + suffixMap.INSERT(targetPhotographTypeMap); } qDebug() << "===update content index==="; int size = 0; @@ -89,8 +87,10 @@ void IndexUpdater::UpdateIndex() contentDb.removeDocument(file.path()); } } else if(true == suffixMap[suffix] && !file.isDir()) { - if(FileUtils::isEncrypedOrUnsupport(file.path(), suffix) && file.isModified()) { - contentDb.removeDocument(file.path()); + if(FileUtils::isEncrypedOrUnsupport(file.path(), suffix)) { + if(file.isModified() || file.isMoveTo()) { + contentDb.removeDocument(file.path()); + } continue; } qDebug() << "| index:" <load()) { + if(m_contentIndexStop->LOAD) { qDebug() << "Index stopped, content index update interrupted"; m_cache.clear(); m_cache.shrink_to_fit(); @@ -126,5 +127,5 @@ void IndexUpdater::UpdateIndex() void IndexUpdater::run() { - UpdateIndex(); + updateIndex(); } diff --git a/libsearch/index/index-updater.h b/libsearch/index/index-updater.h index 1c14819..cedd1f8 100644 --- a/libsearch/index/index-updater.h +++ b/libsearch/index/index-updater.h @@ -31,17 +31,18 @@ class IndexUpdater : public QObject, public QRunnable { Q_OBJECT public: - explicit IndexUpdater(const QVector& files, QAtomicInt& stop); + explicit IndexUpdater(const QVector& files, QAtomicInt& indexstop, QAtomicInt& contentIndexstop); void run() override; Q_SIGNALS: void done(); private: - void UpdateIndex(); + void updateIndex(); QVector m_cache; - QAtomicInt *m_stop = nullptr; + QAtomicInt *m_contentIndexStop = nullptr; + QAtomicInt *m_indexStop = nullptr; }; } #endif // INDEXUPDATER_H diff --git a/libsearch/index/index.pri b/libsearch/index/index.pri deleted file mode 100644 index 601c063..0000000 --- a/libsearch/index/index.pri +++ /dev/null @@ -1,46 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/basic-indexer.h \ - $$PWD/batch-indexer.h \ - $$PWD/compatible-define.h \ - $$PWD/database.h \ - $$PWD/document.h \ -# $$PWD/file-iterator.h \ - $$PWD/file-content-indexer.h \ - $$PWD/file-reader.h \ - $$PWD/file-search-plugin.h \ - $$PWD/index-scheduler.h \ - $$PWD/index-status-recorder.h \ - $$PWD/monitor.h \ - $$PWD/ocrobject.h \ - $$PWD/pending-file-queue.h \ - $$PWD/pending-file.h \ - $$PWD/search-manager.h \ - $$PWD/ukui-search-qdbus.h \ - $$PWD/file-indexer-config.h \ - $$PWD/file-watcher.h \ - $$PWD/index-updater.h \ - $$PWD/writable-database.h - -SOURCES += \ - $$PWD/basic-indexer.cpp \ - $$PWD/batch-indexer.cpp \ - $$PWD/database.cpp \ - $$PWD/document.cpp \ - $$PWD/file-content-indexer.cpp \ - $$PWD/file-reader.cpp \ - $$PWD/file-search-plugin.cpp \ - $$PWD/index-scheduler.cpp \ - $$PWD/index-status-recorder.cpp \ - $$PWD/monitor.cpp \ - $$PWD/ocrobject.cpp \ - $$PWD/pending-file-queue.cpp \ - $$PWD/pending-file.cpp \ - $$PWD/search-manager.cpp \ - $$PWD/ukui-search-qdbus.cpp \ - $$PWD/file-indexer-config.cpp \ - $$PWD/file-watcher.cpp \ - $$PWD/index-updater.cpp \ - $$PWD/writable-database.cpp - diff --git a/libsearch/index/ocrobject.cpp b/libsearch/index/ocrobject.cpp index b2766e3..ab4cd9a 100644 --- a/libsearch/index/ocrobject.cpp +++ b/libsearch/index/ocrobject.cpp @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #include "ocrobject.h" OcrObject *OcrObject::m_instance = nullptr; diff --git a/libsearch/index/ocrobject.h b/libsearch/index/ocrobject.h index 2a20536..bf9cf29 100644 --- a/libsearch/index/ocrobject.h +++ b/libsearch/index/ocrobject.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef OCROBJECT_H #define OCROBJECT_H diff --git a/libsearch/index/pending-file.h b/libsearch/index/pending-file.h index 9de7cce..c5bb9c6 100644 --- a/libsearch/index/pending-file.h +++ b/libsearch/index/pending-file.h @@ -42,6 +42,8 @@ public: bool isModified() { return m_modified; } void setCreated() { m_created = true; } + void setMoveTo() { m_moveTo = true;} + bool isMoveTo() { return m_moveTo;} void setDeleted() { m_deleted = true; } @@ -66,6 +68,7 @@ private: QString m_path; bool m_created : 1; + bool m_moveTo : 1; bool m_deleted : 1; bool m_modified : 1; bool m_isDir : 1; diff --git a/libsearch/index/search-manager.cpp b/libsearch/index/search-manager.cpp index dd3aff9..fa60f12 100644 --- a/libsearch/index/search-manager.cpp +++ b/libsearch/index/search-manager.cpp @@ -47,7 +47,7 @@ int SearchManager::getCurrentIndexCount() { } bool SearchManager::isBlocked(QString &path) { - QStringList blockList = GlobalSettings::getInstance()->getBlockDirs(); + QStringList blockList = DirWatcher::getDirWatcher()->getBlockDirsOfUser(); for(QString i : blockList) { if(FileUtils::isOrUnder(path, i)) return true; @@ -128,7 +128,7 @@ int FileSearch::keywordSearchfile() { try { qDebug() << "--keywordSearchfile start--"; Xapian::Database db(INDEX_PATH); - Xapian::Query query = creatQueryForFileSearch(db); + Xapian::Query query = creatQueryForFileSearch(); Xapian::Enquire enquire(db); Xapian::Query queryFile; @@ -162,12 +162,17 @@ int FileSearch::keywordSearchfile() { } } -Xapian::Query FileSearch::creatQueryForFileSearch(Xapian::Database &db) { +Xapian::Query FileSearch::creatQueryForFileSearch() { auto userInput = m_keyword.toLower(); std::vector v; - for(int i = 0; i < userInput.size(); i++) { - v.push_back(Xapian::Query(QUrl::toPercentEncoding(userInput.at(i)).toStdString())); - // qDebug()< sKeyWord = ChineseSegmentation::getInstance()->callSegment(m_keyword.toStdString()); //Creat a query std::string words; - for(int i = 0; i < sKeyWord.size(); i++) { + for(size_t i = 0; i < sKeyWord.size(); i++) { words.append(sKeyWord.at(i).word).append(" "); } std::vector v; - for(int i=0; igetBlockDirs(); + QStringList blockList = DirWatcher::getDirWatcher()->getBlockDirsOfUser(); QStringList searchPath = DirWatcher::getDirWatcher()->currentIndexableDir(); QQueue bfs; for (const QString &path : searchPath) { - if (blockList.contains(path)) { - continue; + bool underBlock(false); + for (const QString &blockDir : blockList) { + if (FileUtils::isOrUnder(path, blockDir)) { + underBlock = true; + break; + } + } + if (!underBlock) { + blockList.append(DirWatcher::getDirWatcher()->blackListOfDir(path)); + bfs.enqueue(path); + match(QFileInfo(path)); } - blockList.append(DirWatcher::getDirWatcher()->blackListOfDir(path)); - bfs.enqueue(path); } if (bfs.isEmpty()) { return; @@ -534,35 +546,25 @@ void DirectSearch::run() { } bfs.enqueue(i.absoluteFilePath()); } - if(i.fileName().contains(m_keyword, Qt::CaseInsensitive)) { -// qWarning() << i.fileName() << m_keyword; -// if(m_searchResult->length() > 49) -// return; - if((i.isDir() && m_value == DIR_SEARCH_VALUE)) { - SearchPluginIface::ResultInfo ri; - if(SearchManager::creatResultInfo(ri,i.absoluteFilePath())) { - SearchManager::m_mutexDir.lock(); - if(m_uniqueSymbol == SearchManager::uniqueSymbolDir) { - m_searchResult->enqueue(ri); - SearchManager::m_mutexDir.unlock(); - } else { - SearchManager::m_mutexDir.unlock(); - return; - } - } - } else if (i.isFile() && m_value == FILE_SEARCH_VALUE) { - SearchPluginIface::ResultInfo ri; - if(SearchManager::creatResultInfo(ri,i.absoluteFilePath())) { - SearchManager::m_mutexFile.lock(); - if(m_uniqueSymbol == SearchManager::uniqueSymbolFile) { - m_searchResult->enqueue(ri); - SearchManager::m_mutexFile.unlock(); - } else { - SearchManager::m_mutexFile.unlock(); - return; - } - } - } + SearchManager::m_mutexDir.lock(); + if(m_uniqueSymbol == SearchManager::uniqueSymbolDir) { + match(i); + SearchManager::m_mutexDir.unlock(); + } else { + SearchManager::m_mutexDir.unlock(); + return; + } + } + } +} + +void DirectSearch::match(const QFileInfo &info) +{ + if(info.fileName().contains(m_keyword, Qt::CaseInsensitive)) { + if((info.isDir() && m_value == DIR_SEARCH_VALUE) || (info.isFile() && m_value == FILE_SEARCH_VALUE)) { + SearchPluginIface::ResultInfo ri; + if(SearchManager::creatResultInfo(ri,info.absoluteFilePath())) { + m_searchResult->enqueue(ri); } } } diff --git a/libsearch/index/search-manager.h b/libsearch/index/search-manager.h index 1c263ce..06207c7 100644 --- a/libsearch/index/search-manager.h +++ b/libsearch/index/search-manager.h @@ -105,7 +105,7 @@ protected: void run(); private: int keywordSearchfile(); - Xapian::Query creatQueryForFileSearch(Xapian::Database &db); + Xapian::Query creatQueryForFileSearch(); int getResult(Xapian::MSet &result); DataQueue *m_search_result = nullptr; @@ -161,6 +161,7 @@ public: protected: void run(); private: + void match(const QFileInfo& info); QString m_keyword; DataQueue* m_searchResult = nullptr; size_t m_uniqueSymbol; diff --git a/libsearch/index/writable-database.cpp b/libsearch/index/writable-database.cpp index 3cd6b96..4e1901d 100644 --- a/libsearch/index/writable-database.cpp +++ b/libsearch/index/writable-database.cpp @@ -1,4 +1,3 @@ - /* * Copyright (C) 2022, KylinSoft Co., Ltd. * diff --git a/libsearch/libsearch.h b/libsearch/libsearch.h index 544338d..08bf752 100644 --- a/libsearch/libsearch.h +++ b/libsearch/libsearch.h @@ -21,7 +21,6 @@ #define LIBSEARCH_H #include "libsearch_global.h" -#include "appsearch/app-match.h" #include "file-utils.h" #include "global-settings.h" diff --git a/libsearch/libsearch.pro b/libsearch/libsearch.pro deleted file mode 100644 index 4ffdf0e..0000000 --- a/libsearch/libsearch.pro +++ /dev/null @@ -1,122 +0,0 @@ -QT += core xml widgets dbus concurrent sql KWindowSystem -VERSION = 2.3.0 -DEFINES += VERSION='\\"$${VERSION}\\"' - -TARGET = ukui-search -TEMPLATE = lib -DEFINES += LIBSEARCH_LIBRARY -CONFIG += create_pc create_prl no_install_prl - -PKGCONFIG += gio-2.0 glib-2.0 gio-unix-2.0 gsettings-qt poppler-qt5 kysdk-qtwidgets - -CONFIG += c++11 link_pkgconfig no_keywords lrelease -QMAKE_CXXFLAGS += -Werror=return-type -Werror=return-local-addr -Werror=uninitialized - - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -PLUGIN_INSTALL_DIRS = $$[QT_INSTALL_LIBS]/ukui-search-plugins -DEFINES += PLUGIN_INSTALL_DIRS='\\"$${PLUGIN_INSTALL_DIRS}\\"' -QMAKE_CXXFLAGS += -execution-charset:utf-8 - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 -include(filesystemwatcher/file-system-watcher.pri) -include(pluginmanage/plugin-manager.pri) -include(plugininterface/plugin-interface.pri) -include(index/index.pri) -include(parser/parser.pri) -include(appsearch/appsearch.pri) -include(appdata/appdata.pri) -include(notesearch/notesearch.pri) -include(settingsearch/settingsearch.pri) -include(websearch/websearch.pri) -include(searchinterface/search-interface.pri) -include(dirwatcher/dirwatcher.pri) -include(mailsearch/mailsearch.pri) -include(search-app-widget-plugin/search-app-widget-plugin.pri) - -LIBS += -L$$OUT_PWD/../libchinese-segmentation/ -lchinese-segmentation -LIBS += -lxapian -luchardet -lQt5Xdg -lquazip5 -ltesseract #-L/usr/local/lib/libjemalloc -ljemalloc -LIBS += -lukui-appwidget-manager -lukui-appwidget-provider - -SOURCES += \ - file-utils.cpp \ - global-settings.cpp \ - gobject-template.cpp \ - libsearch.cpp - -HEADERS += \ - app-db-common.h \ - app-info-dbus-argument.h \ - common.h \ - file-utils.h \ - global-settings.h \ - gobject-template.h \ - libsearch_global.h \ - libsearch.h - -RESOURCES += \ - resource1.qrc \ - search-app-widget-plugin/provider/src.qrc - -TRANSLATIONS += \ - ../translations/libukui-search/libukui-search_zh_CN.ts \ - ../translations/libukui-search/libukui-search_bo_CN.ts - -qm_files.path = /usr/share/ukui-search/translations/ -qm_files.files = $$OUT_PWD/.qm/*.qm - -qml.files += search-app-widget-plugin/provider/data/search.qml -qml.path = /usr/share/appwidget/qml/ - -appwidgetconf.files += search-app-widget-plugin/provider/data/search.conf -appwidgetconf.path = /usr/share/appwidget/config/ - -service.files += search-app-widget-plugin/provider/org.ukui.appwidget.provider.search.service -service.path += /usr/share/dbus-1/services/ - -preview.files += search-app-widget-plugin/provider/data/search.png -preview.path = /usr/share/appwidget/search/ - -svg.files += search-app-widget-plugin/provider/data/ukui-search.svg -svg.path = /usr/share/appwidget/search/ - -INSTALLS += qml qm_files appwidgetconf service preview svg - - -# Default rules for deployment. -unix { - target.path = $$[QT_INSTALL_LIBS] - QMAKE_PKGCONFIG_NAME = ukui-search - QMAKE_PKGCONFIG_DESCRIPTION = Ukui-search Header files - QMAKE_PKGCONFIG_VERSION = $$VERSION - QMAKE_PKGCONFIG_LIBDIR = $$target.path - QMAKE_PKGCONFIG_DESTDIR = pkgconfig - QMAKE_PKGCONFIG_INCDIR = /usr/include/ukui-search - QMAKE_PKGCONFIG_CFLAGS += -I/usr/include/ukui-search - - INSTALLS += target - - header.path = /usr/include/ukui-search - header.files += *.h index/*.h appsearch/*.h settingsearch/*.h plugininterface/*.h websearch/*.h search-app-widget-plugin/*.h \ - searchinterface/ukui-search-task.h \ - appdata/app-info-table.h \ - searchinterface/search-controller.h \ - searchinterface/result-item.h \ - filesystemwatcher/file-system-watcher.h - header.files += development-files/header-files/* - - INSTALLS += header -} -INCLUDEPATH += $$PWD/../libchinese-segmentation -DEPENDPATH += $$PWD/../libchinese-segmentation - -#DISTFILES += \ -# ../translations/libsearch/libukui-search_zh_CN.ts diff --git a/libsearch/log-utils.cpp b/libsearch/log-utils.cpp new file mode 100644 index 0000000..c5854d1 --- /dev/null +++ b/libsearch/log-utils.cpp @@ -0,0 +1,118 @@ +#include "log-utils.h" +#include +#include +#include +#include +#include + +#define LOG_FILE_COUNT 2 +#define MAX_LOG_FILE_SIZE 4194304 +#define MAX_LOG_CHECK_INTERVAL 43200000 + +quint64 LogUtils::m_startUpTime = 0; +int LogUtils::m_logFileId = -1; +QString LogUtils::m_logFileName; +QString LogUtils::m_currentLogFile; +static QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.log/ukui-search/"; + +void LogUtils::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + checkLogFile(); + + QByteArray localMsg = msg.toLocal8Bit(); + QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit(); + const char *file = context.file ? context.file : ""; + const char *function = context.function ? context.function : ""; + + FILE *log_file = fopen(m_currentLogFile.toLocal8Bit().constData(), "a+"); + + switch (type) { + case QtDebugMsg: + if (!log_file) { + break; + } + fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtInfoMsg: + fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtWarningMsg: + fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtCriticalMsg: + fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtFatalMsg: + fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); + break; + } + + if (log_file) { + fclose(log_file); + } +} + +void LogUtils::initLogFile(const QString &fileName) +{ + QDir dir; + if (!dir.exists(logFilePath)) { + if (!dir.mkpath(logFilePath)) { + qWarning() << "Unable to create" << logFilePath; + return; + } + } + m_logFileName = logFilePath + fileName + "-%1.log"; + + for (int i = 0; i < LOG_FILE_COUNT; ++i) { + m_currentLogFile = m_logFileName.arg(i); + if (QFile::exists(m_currentLogFile)) { + if (checkFileSize(m_currentLogFile)) { + m_logFileId = i; + break; + } + } else { + QFile file(m_currentLogFile); + file.open(QIODevice::WriteOnly); + file.close(); + } + } + + + if (m_logFileId < 0) { + m_logFileId = 0; + m_currentLogFile = m_logFileName.arg(m_logFileId); + clearFile(m_currentLogFile); + } + + qInfo() << "Current log file:" << m_currentLogFile; +} + +void LogUtils::checkLogFile() +{ + quint64 logTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); + quint64 spacing = std::max(logTime, m_startUpTime) - std::min(logTime, m_startUpTime); + + if (spacing <= MAX_LOG_CHECK_INTERVAL || checkFileSize(m_currentLogFile)) { + return; + } + + m_logFileId = ((m_logFileId + 1) % LOG_FILE_COUNT); + m_currentLogFile = m_logFileName.arg(m_logFileId); + if (!checkFileSize(m_currentLogFile)) { + clearFile(m_currentLogFile); + } +} + +bool LogUtils::checkFileSize(const QString &fileName) +{ + return QFile(fileName).size() < MAX_LOG_FILE_SIZE; +} + +void LogUtils::clearFile(const QString &fileName) +{ + QFile file(fileName); + file.open(QIODevice::WriteOnly); + file.write(""); + file.flush(); + file.close(); +} diff --git a/libsearch/log-utils.h b/libsearch/log-utils.h new file mode 100644 index 0000000..a1c465f --- /dev/null +++ b/libsearch/log-utils.h @@ -0,0 +1,21 @@ +#ifndef LOGUTILS_H +#define LOGUTILS_H +#include + +class LogUtils +{ +public: + static void initLogFile(const QString &fileName); + static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); + +private: + static void checkLogFile(); + static bool checkFileSize(const QString &fileName); + static void clearFile(const QString &fileName); + static quint64 m_startUpTime; + static int m_logFileId; + static QString m_logFileName; + static QString m_currentLogFile; +}; + +#endif // LOGUTILS_H diff --git a/libsearch/mailsearch/mail-search-plugin.cpp b/libsearch/mailsearch/mail-search-plugin.cpp index 3e494ec..9408a5c 100644 --- a/libsearch/mailsearch/mail-search-plugin.cpp +++ b/libsearch/mailsearch/mail-search-plugin.cpp @@ -1,4 +1,24 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #include "mail-search-plugin.h" +#include #include "file-utils.h" #include "chinese-segmentation.h" using namespace UkuiSearch; diff --git a/libsearch/mailsearch/mail-search-plugin.h b/libsearch/mailsearch/mail-search-plugin.h index dad6f84..a0c7510 100644 --- a/libsearch/mailsearch/mail-search-plugin.h +++ b/libsearch/mailsearch/mail-search-plugin.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef MAILSEARCHPLUGIN_H #define MAILSEARCHPLUGIN_H diff --git a/libsearch/mailsearch/mailsearch.pri b/libsearch/mailsearch/mailsearch.pri deleted file mode 100644 index 103b9f6..0000000 --- a/libsearch/mailsearch/mailsearch.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/mail-search-plugin.h - -SOURCES += \ - $$PWD/mail-search-plugin.cpp diff --git a/libsearch/notesearch/note-search-plugin.cpp b/libsearch/notesearch/note-search-plugin.cpp index 274441b..edd310e 100644 --- a/libsearch/notesearch/note-search-plugin.cpp +++ b/libsearch/notesearch/note-search-plugin.cpp @@ -1,13 +1,33 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #include "note-search-plugin.h" #include #include -#include +#include #include "file-utils.h" #include "chinese-segmentation.h" using namespace UkuiSearch; NoteSearchPlugin::NoteSearchPlugin(QObject *parent) { + Q_UNUSED(parent) g_uniqueSymbol = 0; SearchPluginIface::Actioninfo open { 0, tr("Open")}; m_actionInfo << open; @@ -50,11 +70,13 @@ void NoteSearchPlugin::stopSearch() QList NoteSearchPlugin::getActioninfo(int type) { + Q_UNUSED(type) return m_actionInfo; } void NoteSearchPlugin::openAction(int actionkey, QString key, int type) { + Q_UNUSED(type) switch (actionkey) { case 0: { @@ -83,7 +105,7 @@ void NoteSearchPlugin::openAction(int actionkey, QString key, int type) if (res) break; QProcess process; - process.startDetached(QString("ukui-notebook --show %1").arg(key.toInt())); + process.startDetached("ukui-notebook", {"--show", key}); break; } default: @@ -209,15 +231,15 @@ void NoteSearch::run() { } dbusArgs.endArray(); qDebug() << str; - SearchPluginIface::ResultInfo ri = { - icon : XdgIcon::fromTheme("kylin-notebook", QIcon(":/res/icons/desktop.png")), - name : str.at(1), - description : QVector() << SearchPluginIface::DescriptionInfo { - key : QString(tr("Note Description:")), - value : str.at(0) - }, - actionKey : it.first - }; + SearchPluginIface::ResultInfo ri( + IconLoader::loadIconQt("kylin-notebook", QIcon(":/res/icons/desktop.png")), + str.at(1), + QVector() << SearchPluginIface::DescriptionInfo { + key : QString(tr("Note Description:")), + value : str.at(0) + }, + it.first + ); if (m_uniqueSymbol ^ g_uniqueSymbol) { qDebug() << m_uniqueSymbol << g_uniqueSymbol; return; diff --git a/libsearch/notesearch/note-search-plugin.h b/libsearch/notesearch/note-search-plugin.h index f057436..07e4881 100644 --- a/libsearch/notesearch/note-search-plugin.h +++ b/libsearch/notesearch/note-search-plugin.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef NOTESEARCHPLUGIN_H #define NOTESEARCHPLUGIN_H @@ -17,6 +36,8 @@ #include "action-label.h" #include "separation-line.h" #include "libsearch_global.h" +#include "icon-loader.h" + namespace UkuiSearch { static size_t g_uniqueSymbol; @@ -33,7 +54,7 @@ public: PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); - const QIcon icon() {return QIcon::fromTheme("folder");} + const QIcon icon() {return IconLoader::loadIconQt("folder");} void setEnable(bool enable) {m_enable = enable;} bool isEnable() {return m_enable;} QString getPluginName(); diff --git a/libsearch/notesearch/notesearch.pri b/libsearch/notesearch/notesearch.pri deleted file mode 100644 index 62dc971..0000000 --- a/libsearch/notesearch/notesearch.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/note-search-plugin.h - -SOURCES += \ - $$PWD/note-search-plugin.cpp diff --git a/libsearch/parser/binary-parser.cpp b/libsearch/parser/binary-parser.cpp index 53133da..d2aca65 100644 --- a/libsearch/parser/binary-parser.cpp +++ b/libsearch/parser/binary-parser.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "binary-parser.h" #include #include @@ -4543,19 +4562,26 @@ static void vName2String(char *szName, const UCHAR *aucBytes, size_t tNameSize) } /* end of vName2String */ -void vAdd2PropModList(const UCHAR *aucPropMod) { +bool vAdd2PropModList(const UCHAR *aucPropMod) { size_t tSize, tLen; if(tNextFree >= tMaxElements) { tMaxElements += ELEMENTS_TO_ADD; tSize = tMaxElements * sizeof(UCHAR **); - ppAnchor = (UCHAR**)xrealloc(ppAnchor, tSize); + void *pvTmp; + pvTmp = realloc(ppAnchor, tSize); + if(pvTmp) { + ppAnchor = (UCHAR**)pvTmp; + } else { + return false; + } } tLen = 2 + (size_t)usGetWord(0, aucPropMod); ppAnchor[tNextFree] = (UCHAR*)xmalloc(tLen); memcpy(ppAnchor[tNextFree], aucPropMod, tLen); tNextFree++; + return true; } /* end of vAdd2PropModList */ static void vComputePPSlevels(ppsEntryType *atPPSlist, ppsEntryType *pNode, @@ -4921,7 +4947,9 @@ bool KBinaryParser::read8DocText(FILE *pFile, const ppsInfoType *pPPS, } if(iType == 1) { iLen = (int)usGetWord(lOff, aucBuffer); - vAdd2PropModList(aucBuffer + lOff); + if(!vAdd2PropModList(aucBuffer + lOff)) { + return false; + } lOff += (long)iLen + 2; continue; } diff --git a/libsearch/parser/binary-parser.h b/libsearch/parser/binary-parser.h index 793eb3e..f588bd3 100644 --- a/libsearch/parser/binary-parser.h +++ b/libsearch/parser/binary-parser.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef SEARCHHELPER_H #define SEARCHHELPER_H #include diff --git a/libsearch/parser/common.h b/libsearch/parser/common.h index 101755c..8c6bc36 100644 --- a/libsearch/parser/common.h +++ b/libsearch/parser/common.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef COMMON_H #define COMMON_H #include diff --git a/libsearch/parser/parser.pri b/libsearch/parser/parser.pri deleted file mode 100644 index c24be85..0000000 --- a/libsearch/parser/parser.pri +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/common.h \ - $$PWD/binary-parser.h - - -SOURCES += \ - $$PWD/binary-parser.cpp diff --git a/libsearch/plugininterface/action-transmiter.cpp b/libsearch/plugininterface/action-transmiter.cpp index 80dc758..93ebc0a 100644 --- a/libsearch/plugininterface/action-transmiter.cpp +++ b/libsearch/plugininterface/action-transmiter.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "action-transmiter.h" #include using namespace UkuiSearch; diff --git a/libsearch/plugininterface/action-transmiter.h b/libsearch/plugininterface/action-transmiter.h index 94d768c..fe61d99 100644 --- a/libsearch/plugininterface/action-transmiter.h +++ b/libsearch/plugininterface/action-transmiter.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef ACTIONTRANSMITER_H #define ACTIONTRANSMITER_H diff --git a/libsearch/plugininterface/common-defines.h b/libsearch/plugininterface/common-defines.h deleted file mode 100644 index 422fc77..0000000 --- a/libsearch/plugininterface/common-defines.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef COMMONDEFINES_H -#define COMMONDEFINES_H -#include -namespace UkuiSearch { -/** - * @brief The SearchType enum - * - */ -enum class SearchType -{ - File = 1u << 0, - FileContent = 1u << 1, - Application = 1u << 2, - Setting = 1u << 3, - Note = 1u << 4, - Mail = 1u << 5, - Custom = 1u << 6 -}; - -/** - * @brief The ResultDataType enum - * - */ -enum ResultDataType -{ - FilePath = 1u << 0, - FileIconName = 1u << 1, - FileName = 1u << 2, - ModifiedTime = 1u << 3, - ApplicationDesktopPath = 1u << 4, - ApplicationLocalName = 1u << 5, - ApplicationIconName = 1u << 6, - ApplicationDescription = 1u << 7, - IsOnlineApplication = 1u << 8 - //add more... - -}; -Q_DECLARE_FLAGS(ResultDataTypes, ResultDataType) - -} - -Q_DECLARE_OPERATORS_FOR_FLAGS(UkuiSearch::ResultDataTypes) - -#endif // COMMONDEFINES_H diff --git a/libsearch/plugininterface/data-queue.h b/libsearch/plugininterface/data-queue.h index 452af7e..ade8cb6 100644 --- a/libsearch/plugininterface/data-queue.h +++ b/libsearch/plugininterface/data-queue.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef DATAQUEUE_H #define DATAQUEUE_H #include @@ -21,7 +40,7 @@ public: inline void clear() { QMutexLocker locker(&m_mutex); QList::clear(); - return; + QList::reserve(QList::size()); } inline bool isEmpty() { QMutexLocker locker(&m_mutex); diff --git a/libsearch/plugininterface/plugin-iface.h b/libsearch/plugininterface/plugin-iface.h index eb25e51..9ca223a 100644 --- a/libsearch/plugininterface/plugin-iface.h +++ b/libsearch/plugininterface/plugin-iface.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef PLUGININTERFACE_H #define PLUGININTERFACE_H diff --git a/libsearch/plugininterface/plugin-interface.pri b/libsearch/plugininterface/plugin-interface.pri deleted file mode 100644 index 0c2a73b..0000000 --- a/libsearch/plugininterface/plugin-interface.pri +++ /dev/null @@ -1,18 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/action-transmiter.h \ - $$PWD/action-label.h \ - $$PWD/common-defines.h \ - $$PWD/plugin-iface.h \ - $$PWD/search-plugin-iface.h \ - $$PWD/search-task-plugin-iface.h \ - $$PWD/data-queue.h \ - $$PWD/separation-line.h - -SOURCES += \ - $$PWD/action-transmiter.cpp \ - $$PWD/action-label.cpp \ - $$PWD/separation-line.cpp \ - $$PWD/search-plugin-iface.cpp - diff --git a/libsearch/plugininterface/search-plugin-iface.cpp b/libsearch/plugininterface/search-plugin-iface.cpp index 628f12d..8475cc8 100644 --- a/libsearch/plugininterface/search-plugin-iface.cpp +++ b/libsearch/plugininterface/search-plugin-iface.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "action-transmiter.h" #include "search-plugin-iface.h" diff --git a/libsearch/plugininterface/search-plugin-iface.h b/libsearch/plugininterface/search-plugin-iface.h index 1eb1a13..cb30d01 100644 --- a/libsearch/plugininterface/search-plugin-iface.h +++ b/libsearch/plugininterface/search-plugin-iface.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef SEARCHPLUGINIFACE_H #define SEARCHPLUGINIFACE_H #define SearchPluginIface_iid "org.ukui.ukui-search.plugin-iface.SearchPluginInterface" @@ -42,6 +61,19 @@ public: QVector description; QString actionKey; int type; + ResultInfo(const QIcon &iconToSet = QIcon(), const QString &nameToSet = QString(), + const QVector &descriptionToSet = QVector(), + const QString &actionKeyToSet = QString(), const int &typeToSet = 0) { + icon = iconToSet; + name = nameToSet; + description = descriptionToSet; + actionKey = actionKeyToSet; + type = typeToSet; + } + ~ResultInfo() { + description.clear(); + description.squeeze(); + } }; virtual ~SearchPluginIface() {} diff --git a/libsearch/plugininterface/search-task-plugin-iface.h b/libsearch/plugininterface/search-task-plugin-iface.h index 13d9dc3..237240c 100644 --- a/libsearch/plugininterface/search-task-plugin-iface.h +++ b/libsearch/plugininterface/search-task-plugin-iface.h @@ -1,12 +1,31 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef SEARCHTASKPLUGINIFACE_H #define SEARCHTASKPLUGINIFACE_H #define SearchTaskPluginIface_iid "org.ukui.ukui-search.plugin-iface.SearchTaskPluginIface" -#define SEARCH_TASK_PLUGIN_IFACE_VERSION "1.0.0" +#define SEARCH_TASK_PLUGIN_IFACE_VERSION "1.1.0" #include #include #include "plugin-iface.h" -#include "common-defines.h" +#include "search-result-property.h" #include "search-controller.h" @@ -15,14 +34,17 @@ class SearchTaskPluginIface : public QObject, public PluginInterface { Q_OBJECT public: + virtual void setController(const SearchController &searchController) = 0; virtual QString getCustomSearchType() = 0; - virtual SearchType getSearchType() = 0; + virtual SearchProperty::SearchType getSearchType() = 0; //Asynchronous,multithread. - virtual void startSearch(std::shared_ptr searchController) = 0; + virtual void startSearch() = 0; virtual void stop() = 0; + virtual bool isSearching() = 0; Q_SIGNALS: void searchFinished(size_t searchId); void searchError(size_t searchId, QString msg = {}); + void reachInformNum(); }; } Q_DECLARE_INTERFACE(UkuiSearch::SearchTaskPluginIface, SearchTaskPluginIface_iid) diff --git a/libsearch/plugininterface/separation-line.cpp b/libsearch/plugininterface/separation-line.cpp index fc97865..846eb99 100644 --- a/libsearch/plugininterface/separation-line.cpp +++ b/libsearch/plugininterface/separation-line.cpp @@ -1,5 +1,25 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "separation-line.h" #include "global-settings.h" +#include #define NOMORL_LINE_STYLE "QFrame{background: rgba(0,0,0,0.1);}" #define DARK_LINE_STYLE "QFrame{background: rgba(255, 255, 255, 0.16);}" @@ -15,7 +35,7 @@ SeparationLine::SeparationLine(QWidget *parent) : QFrame(parent) void SeparationLine::setLineStyle() { - QString type = GlobalSettings::getInstance()->getValue(STYLE_NAME_KEY).toString(); + QString type = GlobalSettings::getInstance().getValue(STYLE_NAME_KEY).toString(); if (type == "ukui-dark") { this->setStyleSheet(DARK_LINE_STYLE); } else { diff --git a/libsearch/plugininterface/separation-line.h b/libsearch/plugininterface/separation-line.h index 97c0f1d..220909f 100644 --- a/libsearch/plugininterface/separation-line.h +++ b/libsearch/plugininterface/separation-line.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef SEPARATIONLINE_H #define SEPARATIONLINE_H diff --git a/libsearch/pluginmanage/plugin-info.h b/libsearch/pluginmanage/plugin-info.h index cb25368..5b6c755 100644 --- a/libsearch/pluginmanage/plugin-info.h +++ b/libsearch/pluginmanage/plugin-info.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef PLUGININFO_H #define PLUGININFO_H @@ -25,11 +44,11 @@ public: private: QString m_name; - QString m_path; - int m_order; bool m_enable; - bool m_isExternal; + int m_order; bool m_isFixed; + bool m_isExternal; + QString m_path; }; } diff --git a/libsearch/pluginmanage/plugin-manager.cpp b/libsearch/pluginmanage/plugin-manager.cpp index 3053e68..7668293 100644 --- a/libsearch/pluginmanage/plugin-manager.cpp +++ b/libsearch/pluginmanage/plugin-manager.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "plugin-manager.h" #include "search-plugin-manager.h" #include "search-task-plugin-manager.h" @@ -18,11 +37,6 @@ PluginManager *PluginManager::getInstance() return global_instance; } -void PluginManager::setPluginEnableByName(const QString &pluginName, bool enable) -{ - m_hash.value(pluginName)->setEnable(enable); -} - PluginManager::PluginManager(QObject *parent) : QObject(parent) { QDir pluginsDir(PLUGIN_INSTALL_DIRS); @@ -54,19 +68,18 @@ PluginManager::PluginManager(QObject *parent) : QObject(parent) PluginInterface *piface = dynamic_cast(plugin); if (!piface) continue; - m_hash.insert(piface->name(), piface); switch (piface->pluginType()) { case PluginInterface::PluginType::SearchPlugin: { auto p = dynamic_cast(plugin); - if (!SearchPluginManager::getInstance()->registerExternalPlugin(p, pluginsDir.absoluteFilePath(fileName))) { - m_hash.erase(m_hash.find(piface->name())); + if(!SearchPluginManager::getInstance()->registerExternalPlugin(p, pluginsDir.absoluteFilePath(fileName))) { + delete p; } break; } case PluginInterface::PluginType::SearchTaskPlugin: { auto p = dynamic_cast(plugin); - SearchTaskPluginManager::getInstance()->registerPlugin(p); SearchTaskPluginManager::getInstance()->registerPluginPath(p->getCustomSearchType(), pluginsDir.absoluteFilePath(fileName)); + delete p; break; } default: @@ -77,6 +90,4 @@ PluginManager::PluginManager(QObject *parent) : QObject(parent) PluginManager::~PluginManager() { - m_hash.clear(); - SearchPluginManager::getInstance()->close(); } diff --git a/libsearch/pluginmanage/plugin-manager.h b/libsearch/pluginmanage/plugin-manager.h index 6b0f29b..af1958a 100644 --- a/libsearch/pluginmanage/plugin-manager.h +++ b/libsearch/pluginmanage/plugin-manager.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef PLUGINMANAGER_H #define PLUGINMANAGER_H @@ -22,16 +41,11 @@ public: Q_SIGNALS: void pluginStateChanged(const QString &pluginName, bool enable); -public Q_SLOTS: - void setPluginEnableByName(const QString &pluginName, bool enable); - private: explicit PluginManager(QObject *parent = nullptr); ~PluginManager(); - QHash m_hash; - }; } diff --git a/libsearch/pluginmanage/search-plugin-manager.cpp b/libsearch/pluginmanage/search-plugin-manager.cpp index c08aa44..6990591 100644 --- a/libsearch/pluginmanage/search-plugin-manager.cpp +++ b/libsearch/pluginmanage/search-plugin-manager.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include #include "search-plugin-manager.h" #include "file-search-plugin.h" @@ -5,7 +24,6 @@ #include "settings-search-plugin.h" #include "note-search-plugin.h" #include "web-search-plugin.h" -#include "mail-search-plugin.h" #define PLUGIN_ORDER_SETTINGS QDir::homePath() + "/.config/org.ukui/ukui-search/ukui-search-plugin-order.conf" #define PLUGINS_INFO_GROUP "PluginsInfo" @@ -22,6 +40,7 @@ using namespace UkuiSearch; static SearchPluginManager *global_instance = nullptr; SearchPluginManager::SearchPluginManager(QObject *parent) { + Q_UNUSED(parent) initOrderSettings(); registerPlugin(new AppSearchPlugin); registerPlugin(new NoteSearchPlugin); @@ -39,6 +58,10 @@ bool SearchPluginManager::registerPlugin(UkuiSearch::SearchPluginIface *plugin) if (m_map.end() != m_map.find(plugin->name())) { qWarning() << "the plugin:" << plugin->name() << "has been registered."; + if (plugin) { + delete plugin; + plugin = nullptr; + } return res; } @@ -421,11 +444,6 @@ SearchPluginIface *SearchPluginManager::getPlugin(const QString &pluginId) return m_map[pluginId]; } -void SearchPluginManager::close() -{ - this->deleteLater(); -} - SearchPluginManager::~SearchPluginManager() { for (auto iter = m_map.begin(); iter != m_map.end();) { diff --git a/libsearch/pluginmanage/search-plugin-manager.h b/libsearch/pluginmanage/search-plugin-manager.h index 5d76b99..d441ffa 100644 --- a/libsearch/pluginmanage/search-plugin-manager.h +++ b/libsearch/pluginmanage/search-plugin-manager.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef SEARCHPLUGINFACTORY_H #define SEARCHPLUGINFACTORY_H @@ -37,8 +56,6 @@ public: const QList getPluginIds(); SearchPluginIface *getPlugin(const QString &pluginId); - void close(); - private: explicit SearchPluginManager(QObject *parent = nullptr); ~SearchPluginManager(); diff --git a/libsearch/pluginmanage/search-task-plugin-manager.cpp b/libsearch/pluginmanage/search-task-plugin-manager.cpp index 195dcda..f7d7583 100644 --- a/libsearch/pluginmanage/search-task-plugin-manager.cpp +++ b/libsearch/pluginmanage/search-task-plugin-manager.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "search-task-plugin-manager.h" #include #include @@ -16,85 +35,18 @@ SearchTaskPluginManager *SearchTaskPluginManager::getInstance() return global_instance; } -void SearchTaskPluginManager::initPlugins(SearchType searchType) -{ - switch (searchType) { - case SearchType::File: - registerBuildinPlugin(new FileSearchTask(this)); - break; - case SearchType::FileContent: - registerBuildinPlugin(new FileContentSearchTask(this)); - break; - case SearchType::Application: - registerBuildinPlugin(new AppSearchTask(this)); - default: - break; - } -} - -bool SearchTaskPluginManager::registerPlugin(SearchTaskPluginIface *plugin) -{ - //这里把内部插件和外部插件分开写是考虑到异常处理,因为内部插件我们可以保证质量,但外部插件可能有各种各样的问题。 - //但异常处理我没想好怎么加。。 - //by zpf - if(plugin->getCustomSearchType().isEmpty() || m_loadedPlugin.contains(plugin->getCustomSearchType())) { - qWarning() << "search task plugin load failed! plugin type:" << plugin->getCustomSearchType(); - return false; - } - m_loadedPlugin.insert(plugin->getCustomSearchType(), plugin); - connect(plugin, &SearchTaskPluginIface::searchFinished, this, &SearchTaskPluginManager::searchFinished); - connect(plugin, &SearchTaskPluginIface::searchError, this, &SearchTaskPluginManager::searchError); - return true; -} - -bool SearchTaskPluginManager::registerBuildinPlugin(SearchTaskPluginIface *plugin) -{ - m_buildinPlugin.insert(static_cast(plugin->getSearchType()), plugin); - connect(plugin, &SearchTaskPluginIface::searchFinished, this, &SearchTaskPluginManager::searchFinished); - connect(plugin, &SearchTaskPluginIface::searchError, this, &SearchTaskPluginManager::searchError); - return true; -} - SearchTaskPluginManager::SearchTaskPluginManager(QObject *parent) : QObject(parent) { } -void SearchTaskPluginManager::pluginSearch(SearchType searchType, std::shared_ptr searchController) -{ - size_t type = static_cast(searchType); - qDebug() << "search type" << type; - if(m_buildinPlugin.contains(type)) { - if(!m_buildinPlugin.value(type)->isEnable()) { - Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is disabled!").arg(type)); - return; - } - qDebug() << "start search"; - m_buildinPlugin.value(type)->startSearch(searchController); - } else { - Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is not registered!").arg(type)); - } -} - -void SearchTaskPluginManager::pluginSearch(QString customSearchType, std::shared_ptr searchController) -{ - if(m_loadedPlugin.contains(customSearchType)) { - if(!m_loadedPlugin.value(customSearchType)->isEnable()) { - Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is disabled!").arg(customSearchType)); - return; - } - m_loadedPlugin.value(customSearchType)->startSearch(searchController); - } else { - Q_EMIT this->searchError(searchController.get()->getCurrentSearchId(), tr("plugin type: %1, is not registered!").arg(customSearchType)); - } -} - -bool SearchTaskPluginManager::startSearch(const QUuid &uuid, std::shared_ptr searchController, SearchType searchType, const QString &customType) +bool SearchTaskPluginManager::startSearch(const QUuid &uuid, SearchProperty::SearchType searchType, const QString &customType) { + QMutexLocker locker(&m_mutex); if (m_managedPlugins.contains(uuid)) { ManagedPlugin* managedPlugin = m_managedPlugins.value(uuid); SearchTaskPluginIface *plugin = nullptr; - if (searchType == SearchType::Custom) { + if (searchType == SearchProperty::SearchType::Custom) { plugin = managedPlugin->externalPlugin(customType); } else { @@ -102,7 +54,7 @@ bool SearchTaskPluginManager::startSearch(const QUuid &uuid, std::shared_ptrstartSearch(std::move(searchController)); + plugin->startSearch(); return true; } } @@ -110,10 +62,10 @@ bool SearchTaskPluginManager::startSearch(const QUuid &uuid, std::shared_ptrexternalPlugin(customType); + + } else { + plugin = managedPlugin->internalPlugin(searchType); + } + + if (plugin) { + return plugin->isSearching(); + } + } + return false; +} + +SearchTaskPluginIface *SearchTaskPluginManager::initPlugins(const QUuid& uuid, SearchProperty::SearchType searchType, const QString& customType) +{ + QMutexLocker locker(&m_mutex); if (!m_managedPlugins.contains(uuid)) { m_managedPlugins.insert(uuid, new ManagedPlugin(nullptr)); } SearchTaskPluginIface *plugin = getPlugin(searchType, customType); bool succeed = false; - if (searchType == SearchType::Custom) { + if (searchType == SearchProperty::SearchType::Custom) { succeed = m_managedPlugins.value(uuid)->insertExternalPlugin(customType, plugin); - } else { succeed = m_managedPlugins.value(uuid)->insertInternalPlugin(searchType, plugin); } @@ -168,21 +142,19 @@ SearchTaskPluginIface *SearchTaskPluginManager::initPlugins(const QUuid& uuid, S void SearchTaskPluginManager::destroyPlugins(const QUuid &uuid) { - if (m_managedPlugins.contains(uuid)) { - ManagedPlugin *managedPlugin = m_managedPlugins.value(uuid); - m_managedPlugins.remove(uuid); - - delete managedPlugin; - } + QMutexLocker locker(&m_mutex); + delete m_managedPlugins.take(uuid); } ManagedPlugin::~ManagedPlugin() { - + qDeleteAll(m_internalPlugins); + qDeleteAll(m_externalPlugin); } -bool ManagedPlugin::insertInternalPlugin(const SearchType &searchType, SearchTaskPluginIface *plugin) +bool ManagedPlugin::insertInternalPlugin(const SearchProperty::SearchType &searchType, SearchTaskPluginIface *plugin) { + QMutexLocker locker(&m_mutex); if (plugin) { auto type = static_cast(searchType); plugin->setParent(this); @@ -192,14 +164,14 @@ bool ManagedPlugin::insertInternalPlugin(const SearchType &searchType, SearchTas return true; } - plugin->deleteLater(); + delete plugin; } - return false; } bool ManagedPlugin::insertExternalPlugin(const QString &customType, SearchTaskPluginIface *plugin) { + QMutexLocker locker(&m_mutex); if (plugin) { plugin->setParent(this); if (!customType.isEmpty() && !m_externalPlugin.contains(customType)) { @@ -207,14 +179,15 @@ bool ManagedPlugin::insertExternalPlugin(const QString &customType, SearchTaskPl return true; } - plugin->deleteLater(); + delete plugin; } return false; } -inline SearchTaskPluginIface *ManagedPlugin::internalPlugin(const SearchType &searchType) +inline SearchTaskPluginIface *ManagedPlugin::internalPlugin(const SearchProperty::SearchType &searchType) { + QMutexLocker locker(&m_mutex); auto type = static_cast(searchType); if (m_internalPlugins.contains(type)) { return m_internalPlugins.value(type); @@ -224,6 +197,7 @@ inline SearchTaskPluginIface *ManagedPlugin::internalPlugin(const SearchType &se inline SearchTaskPluginIface *ManagedPlugin::externalPlugin(const QString &customType) { + QMutexLocker locker(&m_mutex); if (m_externalPlugin.contains(customType)) { return m_externalPlugin.value(customType); } diff --git a/libsearch/pluginmanage/search-task-plugin-manager.h b/libsearch/pluginmanage/search-task-plugin-manager.h index 811b2ba..e5a9196 100644 --- a/libsearch/pluginmanage/search-task-plugin-manager.h +++ b/libsearch/pluginmanage/search-task-plugin-manager.h @@ -1,9 +1,30 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef SEARCHTASKPLUGINMANAGER_H #define SEARCHTASKPLUGINMANAGER_H #include #include #include +#include +#include #include "search-task-plugin-iface.h" namespace UkuiSearch { @@ -15,13 +36,14 @@ public: explicit ManagedPlugin(QObject *parent) : QObject(parent) {} ~ManagedPlugin() override; - inline SearchTaskPluginIface *internalPlugin(const SearchType& searchType); + inline SearchTaskPluginIface *internalPlugin(const SearchProperty::SearchType& searchType); inline SearchTaskPluginIface *externalPlugin(const QString& customType); - bool insertInternalPlugin(const SearchType& searchType, SearchTaskPluginIface* plugin); + bool insertInternalPlugin(const SearchProperty::SearchType& searchType, SearchTaskPluginIface* plugin); bool insertExternalPlugin(const QString& customType, SearchTaskPluginIface* plugin); private: + QMutex m_mutex; QMap m_internalPlugins; QMap m_externalPlugin; }; @@ -31,30 +53,23 @@ class SearchTaskPluginManager : public QObject Q_OBJECT public: static SearchTaskPluginManager *getInstance(); - void initPlugins(SearchType searchType); - SearchTaskPluginIface *initPlugins(const QUuid&, SearchType, const QString& customType = QString()); - bool registerPlugin(SearchTaskPluginIface *plugin); - bool registerBuildinPlugin(SearchTaskPluginIface *plugin); - void pluginSearch(SearchType searchType, std::shared_ptr searchController); - void pluginSearch(QString customSearchType, std::shared_ptr searchController); - bool startSearch(const QUuid&, std::shared_ptr, SearchType, const QString& customType = QString()); + SearchTaskPluginIface *initPlugins(const QUuid&, SearchProperty::SearchType, const QString& customType = QString()); + bool startSearch(const QUuid&, SearchProperty::SearchType, const QString& customType = QString()); void destroyPlugins(const QUuid& uuid); - - SearchTaskPluginIface *getPlugin(SearchType searchType, const QString& customType = QString()); void registerPluginPath(const QString& customType, const QString& pluginPath); - -Q_SIGNALS: - void searchFinished(size_t searchId); - void searchError(size_t searchId, QString msg); + bool isSearching(const QUuid &uuid, SearchProperty::SearchType searchType, const QString& customType = QString()); private: explicit SearchTaskPluginManager(QObject *parent = nullptr); + SearchTaskPluginIface *getPlugin(SearchProperty::SearchType searchType, const QString& customType = QString()); //这里初衷是把内外部插件分开管理,内部插件可以增加枚举值,外部插件似乎只能用编写者自定义的字符串区分? QHash m_buildinPlugin; QHash m_loadedPlugin; QMap m_loadedPluginPath; QMap m_managedPlugins; + + QMutex m_mutex; }; } diff --git a/libsearch/search-app-widget-plugin/provider/data/search.svg b/libsearch/search-app-widget-plugin/provider/data/search.svg deleted file mode 100644 index e931c1d..0000000 --- a/libsearch/search-app-widget-plugin/provider/data/search.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - ukui-global search-search - - - - - - - - - - - - - \ No newline at end of file diff --git a/libsearch/search-app-widget-plugin/provider/src.qrc b/libsearch/search-app-widget-plugin/provider/src.qrc deleted file mode 100644 index 52b9d51..0000000 --- a/libsearch/search-app-widget-plugin/provider/src.qrc +++ /dev/null @@ -1,9 +0,0 @@ - - - org.ukui.appwidget.provider.search.service - data/search.conf - data/search.qml - data/search.png - data/ukui-search.svg - - diff --git a/libsearch/search-app-widget-plugin/search-app-widget-plugin.pro b/libsearch/search-app-widget-plugin/search-app-widget-plugin.pro deleted file mode 100644 index 3e1c4f4..0000000 --- a/libsearch/search-app-widget-plugin/search-app-widget-plugin.pro +++ /dev/null @@ -1,52 +0,0 @@ -QT += dbus widgets - -TEMPLATE = lib -DEFINES += SEARCHAPPWIDGETPLUGIN_LIBRARY - -CONFIG += c++11 link_pkgconfig - -PKGCONFIG += gsettings-qt - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -TRANSLATIONS += translations/zh_CN.ts - -SOURCES += \ - search.cpp - -HEADERS += \ - search-app-widget-plugin_global.h \ - search.h - -LIBS += -lukui-appwidget-manager -lukui-appwidget-provider - -# Default rules for deployment. - -qml.files += provider/data/search.qml -qml.path = /usr/share/appwidget/qml/ - -qm_files.files = translations/* $$OUT_PWD/.qm/*.qm -qm_files.path = /usr/share/appwidget/search/translations/ - -appwidgetconf.files += provider/data/search.conf -appwidgetconf.path = /usr/share/appwidget/config/ - -service.files += provider/org.ukui.appwidget.provider.search.service -service.path += /usr/share/dbus-1/services/ - -preview.files += provider/data/search.png -preview.path = /usr/share/appwidget/search/ - -svg.files += provider/data/ukui-search.svg -svg.path = /usr/share/appwidget/search/ - -INSTALLS += target qml qm_files appwidgetconf service preview svg diff --git a/libsearch/search-app-widget-plugin/search-app-widget-plugin_global.h b/libsearch/search-app-widget-plugin/search-app-widget-plugin_global.h deleted file mode 100644 index 4c83b89..0000000 --- a/libsearch/search-app-widget-plugin/search-app-widget-plugin_global.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SEARCHAPPWIDGETPLUGIN_GLOBAL_H -#define SEARCHAPPWIDGETPLUGIN_GLOBAL_H - -#include - -#if defined(SEARCHAPPWIDGETPLUGIN_LIBRARY) -# define SEARCHAPPWIDGETPLUGIN_EXPORT Q_DECL_EXPORT -#else -# define SEARCHAPPWIDGETPLUGIN_EXPORT Q_DECL_IMPORT -#endif - -#endif // SEARCHAPPWIDGETPLUGIN_GLOBAL_H diff --git a/libsearch/search-app-widget-plugin/search.h b/libsearch/search-app-widget-plugin/search.h deleted file mode 100644 index c6d0bdd..0000000 --- a/libsearch/search-app-widget-plugin/search.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SEARCH_H -#define SEARCH_H - -#include "libsearch_global.h" - -#define signals Q_SIGNALS -#define slots Q_SLOTS - -#include "ukui/kappwidgetprovider.h" -#include "ukui/kappwidgetmanager.h" - -#undef signals -#undef slots - -#include "global-settings.h" -#include - -namespace UkuiSearch { -class LIBSEARCH_EXPORT AppWidgetPlugin : public AppWidget::KAppWidgetProvider - -{ - Q_OBJECT -public: - explicit AppWidgetPlugin(QString providername = "search", QObject *parent = nullptr); - void appWidgetRecevie(const QString &eventname, const QString &widgetname, const QDBusVariant &value); - void appWidgetUpdate(); - -Q_SIGNALS: - void startSearch(QString); - -private: - QDBusInterface* m_interface = nullptr; - AppWidget::KAppWidgetManager* m_manager = nullptr; -}; -} - - - -#endif // SEARCH_H diff --git a/libsearch/searchinterface/result-item.cpp b/libsearch/searchinterface/result-item.cpp index 6fc0542..65e9a6c 100644 --- a/libsearch/searchinterface/result-item.cpp +++ b/libsearch/searchinterface/result-item.cpp @@ -1,81 +1,69 @@ #include "result-item.h" -#include "result-item-private.h" using namespace UkuiSearch; -ResultItemPrivate::ResultItemPrivate::ResultItemPrivate(ResultItem *parent) : q(parent) +namespace UkuiSearch { +class ResultItemPrivate +{ + friend class ResultItem; +private: + size_t m_searchId = 0; + QString m_itemKey; + SearchResultPropertyMap m_data; +}; +} +ResultItem::ResultItem() : d(new ResultItemPrivate()) { } -ResultItemPrivate::~ResultItemPrivate() +ResultItem::ResultItem(const size_t searchId) : d(new ResultItemPrivate()) { + d->m_searchId = searchId; } -void ResultItemPrivate::setSearchId(size_t searchId) +ResultItem::ResultItem(const QString &itemKey) : d(new ResultItemPrivate()) { - m_searchId = searchId; + d->m_itemKey = itemKey; } -void ResultItemPrivate::setItemKey(QString itemKey) +ResultItem::ResultItem(const size_t searchId, const QString &itemKey, const SearchResultPropertyMap &map) : d(new ResultItemPrivate()) { - m_itemKey = itemKey; + d->m_searchId = searchId; + d->m_itemKey = itemKey; + d->m_data = map; } -void ResultItemPrivate::setExtral(QVariantList extral) +void ResultItem::setSearchId(const size_t searchId) { - for (auto &info : extral) { - m_extral.append(info); - } + d->m_searchId = searchId; } -size_t ResultItemPrivate::getSearchId() +void ResultItem::setItemKey(const QString &itemKey) { - return m_searchId; + d->m_itemKey = itemKey; } -QString ResultItemPrivate::getItemKey() -{ - return m_itemKey; -} - -QVariantList ResultItemPrivate::getExtral() -{ - return m_extral; -} - -ResultItem::ResultItem() : d(new ResultItemPrivate(this)) -{ -} - -ResultItem::ResultItem(const size_t searchId) : d(new ResultItemPrivate(this)) -{ - d->setSearchId(searchId); -} - -ResultItem::ResultItem(const QString itemKey) : d(new ResultItemPrivate(this)) -{ - d->setItemKey(itemKey); -} - -ResultItem::ResultItem(const size_t searchId, const QString itemKey, QVariantList extral) : d(new ResultItemPrivate(this)) -{ - d->setSearchId(searchId); - d->setItemKey(itemKey); - d->setExtral(extral); -} - - size_t ResultItem::getSearchId() const { - return d->getSearchId(); + return d->m_searchId; } QString ResultItem::getItemKey() const { - return d->getItemKey(); + return d->m_itemKey; } -QVariantList ResultItem::getExtral() const +void ResultItem::setValue(SearchProperty::SearchResultProperty property, const QVariant &value) { - return d->getExtral(); + d->m_data.insert(property, value); +} + +QVariant ResultItem::getValue(SearchProperty::SearchResultProperty property) const +{ + return d->m_data.value(property); +} + +SearchResultPropertyMap ResultItem::getAllValue() const +{ + return d->m_data; } ResultItem::~ResultItem() @@ -85,9 +73,18 @@ ResultItem::~ResultItem() d = nullptr; } -ResultItem::ResultItem(const ResultItem &item): d(new ResultItemPrivate(this)) +ResultItem::ResultItem(const ResultItem &item): d(new ResultItemPrivate(*item.d)) { - d->setSearchId(item.getSearchId()); - d->setItemKey(item.getItemKey()); - d->setExtral(item.getExtral()); +} + +ResultItem &ResultItem::operator=(const ResultItem &other) +{ + *d = *other.d; + return *this; +} +ResultItem &ResultItem::operator=(ResultItem &&other) Q_DECL_NOEXCEPT +{ + d = other.d; + other.d = nullptr; + return *this; } diff --git a/libsearch/searchinterface/result-item.h b/libsearch/searchinterface/result-item.h index 14e402b..5a38c03 100644 --- a/libsearch/searchinterface/result-item.h +++ b/libsearch/searchinterface/result-item.h @@ -1,8 +1,27 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef RESULTITEM_H #define RESULTITEM_H #include -#include +#include "search-result-property.h" namespace UkuiSearch { class ResultItemPrivate; class ResultItem @@ -11,13 +30,20 @@ public: explicit ResultItem(); virtual ~ResultItem(); - ResultItem(const ResultItem &item); explicit ResultItem(const size_t searchId); - explicit ResultItem(const QString itemKey); - explicit ResultItem(const size_t searchId, const QString itemKey, QVariantList extral = QVariantList()); + explicit ResultItem(const QString &itemKey); + ResultItem(const size_t searchId, const QString &itemKey, const SearchResultPropertyMap &map); + ResultItem(const ResultItem &item); + ResultItem &operator=(const ResultItem &other); + ResultItem &operator=(ResultItem &&other) Q_DECL_NOEXCEPT; + + void setSearchId(const size_t searchId); + void setItemKey(const QString &itemKey); size_t getSearchId() const; QString getItemKey() const; - QVariantList getExtral() const; + void setValue(SearchProperty::SearchResultProperty property, const QVariant &value); + QVariant getValue(SearchProperty::SearchResultProperty property) const; + SearchResultPropertyMap getAllValue() const; private: ResultItemPrivate *d; diff --git a/libsearch/searchinterface/search-controller-private.h b/libsearch/searchinterface/search-controller-private.h deleted file mode 100644 index a89344f..0000000 --- a/libsearch/searchinterface/search-controller-private.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef SEARCHCONTROLLERPRIVATE_H -#define SEARCHCONTROLLERPRIVATE_H - -#include -#include -#include "search-controller.h" -namespace UkuiSearch { - -class SearchControllerPrivate -{ -public: - explicit SearchControllerPrivate(SearchController *parent); - ~SearchControllerPrivate(); - size_t refreshSearchId(); - DataQueue* refreshDataqueue(); - DataQueue* initDataQueue(); - - void addSearchDir(QString &path); - void setRecurse(bool recurse = true); - void addKeyword(QString &keyword); - void setActiveKeywordSegmentation(bool active); - void addFileLabel(QString &label); - void setOnlySearchFile(bool onlySearchFile); - void setOnlySearchDir(bool onlySearchDir); - void setSearchOnlineApps(bool searchOnlineApps); - - size_t getCurrentSearchId(); - DataQueue* getDataQueue(); - ResultDataTypes getResultDataType(SearchType searchType); - QStringList getCustomResultDataType(QString customSearchType); - bool beginSearchIdCheck(size_t searchId); - void finishSearchIdCheck(); - void stop(); - QStringList getSearchDir(); - bool isRecurse(); - QStringList getKeyword(); - bool isKeywordSegmentationActived(); - QStringList getFileLabel(); - bool isSearchFileOnly(); - bool isSearchDirOnly(); - bool isSearchOnlineApps(); - void clearAllConditions(); - void clearKeyWords(); - void clearSearchDir(); - void clearFileLabel(); - - bool setResultDataType(SearchType searchType, ResultDataTypes dataType); - bool setCustomResultDataType(QString customSearchType, QStringList dataType); - - /** - * @brief 分页选项 - * @param first 指定起始位置 - * @param maxResults 每次搜索结果集的数量 - */ - void setPagination(unsigned int first, unsigned int maxResults); - unsigned int first() const; - unsigned int maxResults() const; - -private: - void copyData(); - //TODO: 这里是否可以改为字节对齐的写法? -// DataQueue* m_dataQueue = nullptr ; - std::shared_ptr> m_sharedDataQueue = nullptr; - size_t m_searchId = 0; - QMutex m_searchIdMutex; - SearchController *q = nullptr; - std::shared_ptr m_formerController = nullptr; - - QStringList m_keywords; - QStringList m_searchDirs; - QStringList m_FileLabels; - bool m_recurse = true; - bool m_activeKeywordSegmentation = false; - bool m_onlySearchFile = false; - bool m_onlySearchDir = false; - bool m_searchOnlineApps = false; - - unsigned int m_first = 0; - unsigned int m_maxResults = 100; //默认取100条结果 - - QMap m_searchType2ResultDataType; - QMap m_customSearchType2ResultDataType; -}; -} - -#endif // SEARCHCONTROLLERPRIVATE_H diff --git a/libsearch/searchinterface/search-controller.cpp b/libsearch/searchinterface/search-controller.cpp index d91bedd..effa6e2 100644 --- a/libsearch/searchinterface/search-controller.cpp +++ b/libsearch/searchinterface/search-controller.cpp @@ -1,384 +1,230 @@ #include "search-controller.h" -#include "search-controller-private.h" -#include "ukui-search-task.h" +#include +#include #include -using namespace UkuiSearch; -SearchControllerPrivate::SearchControllerPrivate(SearchController *parent) - : q(parent), - m_formerController(q->m_parent) //如果构造参数里包含父节点智能指针,则子节点带有一个智能指针指向父节点 -{ - copyData(); -} +#include "search-result-property.h" +#include "ukui-search-task.h" +namespace UkuiSearch { -SearchControllerPrivate::~SearchControllerPrivate() +class SearchControllerPrivate { -} +public: + void clearAllConditions(); -size_t SearchControllerPrivate::refreshSearchId() -{ - m_searchIdMutex.lock(); - m_searchId += 1; - m_searchIdMutex.unlock(); - return m_searchId; -} - -DataQueue *SearchControllerPrivate::refreshDataqueue() -{ - if(!m_sharedDataQueue.get()) { -// m_dataQueue = new DataQueue; - m_sharedDataQueue = std::make_shared>(); - return m_sharedDataQueue.get(); - } - m_sharedDataQueue.get()->clear(); - return m_sharedDataQueue.get(); -} - -DataQueue *SearchControllerPrivate::initDataQueue() -{ - if(!m_sharedDataQueue.get()) { - m_sharedDataQueue = std::make_shared>(); - return m_sharedDataQueue.get(); - } - return m_sharedDataQueue.get(); -} - -void SearchControllerPrivate::addSearchDir(QString &path) -{ - m_searchDirs.append(path); -} - -void SearchControllerPrivate::setRecurse(bool recurse) -{ - m_recurse = recurse; -} - -void SearchControllerPrivate::addKeyword(QString &keyword) -{ - m_keywords.append(keyword); -} - -void SearchControllerPrivate::setActiveKeywordSegmentation(bool active) -{ - m_activeKeywordSegmentation = active; -} - -void SearchControllerPrivate::addFileLabel(QString &label) -{ - m_FileLabels.append(label); -} - -void SearchControllerPrivate::setOnlySearchFile(bool onlySearchFile) -{ - m_onlySearchFile = onlySearchFile; -} - -void SearchControllerPrivate::setOnlySearchDir(bool onlySearchDir) -{ - m_onlySearchDir = onlySearchDir; -} - -void SearchControllerPrivate::setSearchOnlineApps(bool searchOnlineApps) -{ - m_searchOnlineApps = searchOnlineApps; -} - -size_t SearchControllerPrivate::getCurrentSearchId() -{ - m_searchIdMutex.lock(); - size_t searchId = m_searchId; - m_searchIdMutex.unlock(); - - return searchId; -} - -DataQueue *SearchControllerPrivate::getDataQueue() -{ - return m_sharedDataQueue.get(); -} - -ResultDataTypes SearchControllerPrivate::getResultDataType(SearchType searchType) -{ - return m_searchType2ResultDataType[searchType]; -} - -QStringList SearchControllerPrivate::getCustomResultDataType(QString customSearchType) -{ - return m_customSearchType2ResultDataType[customSearchType]; -} - -bool SearchControllerPrivate::beginSearchIdCheck(size_t searchId) -{ - if(q->m_parent) { - return q->m_parent->beginSearchIdCheck(searchId); - } - m_searchIdMutex.lock(); - return m_searchId == searchId; -} - -void SearchControllerPrivate::finishSearchIdCheck() -{ - if(q->m_parent) { - return q->m_parent->finishSearchIdCheck(); - } - m_searchIdMutex.unlock(); - return; -} - -void SearchControllerPrivate::stop() -{ - m_searchIdMutex.lock(); - m_searchId += 1; - m_searchIdMutex.unlock(); -} - -QStringList SearchControllerPrivate::getSearchDir() -{ - return m_searchDirs; -} - -bool SearchControllerPrivate::isRecurse() -{ - return m_recurse; -} - -QStringList SearchControllerPrivate::getKeyword() -{ - return m_keywords; -} - -bool SearchControllerPrivate::isKeywordSegmentationActived() -{ - return m_activeKeywordSegmentation; -} - -QStringList SearchControllerPrivate::getFileLabel() -{ - return m_FileLabels; -} - -bool SearchControllerPrivate::isSearchFileOnly() -{ - return m_onlySearchFile; -} - -bool SearchControllerPrivate::isSearchDirOnly() -{ - return m_onlySearchDir; -} - -bool SearchControllerPrivate::isSearchOnlineApps() -{ - return m_searchOnlineApps; -} - -void SearchControllerPrivate::copyData() -{ - if(m_formerController.get()) { - m_searchId = m_formerController.get()->getCurrentSearchId(); - //所有子节点都有一个指向根节点的队列的智能指针 - m_sharedDataQueue = m_formerController.get()->d->m_sharedDataQueue; - m_keywords = m_formerController.get()->getKeyword(); - m_searchDirs = m_formerController.get()->getSearchDir(); - m_FileLabels = m_formerController.get()->getFileLabel(); - m_onlySearchFile = m_formerController.get()->isSearchFileOnly(); - m_onlySearchDir = m_formerController.get()->isSearchDirOnly(); - m_recurse = m_formerController.get()->isRecurse(); - m_activeKeywordSegmentation = m_formerController.get()->isKeywordSegmentationActived(); - } -} + std::shared_ptr> m_sharedDataQueue = nullptr; + size_t m_searchId = 0; + QMutex m_searchIdMutex; + QStringList m_keywords; + QStringList m_searchDirs; + QStringList m_FileLabels; + bool m_recurse = true; + bool m_activeKeywordSegmentation = false; + bool m_onlySearchFile = false; + bool m_onlySearchDir = false; + bool m_searchOnlineApps = false; + bool m_searchHiddenFiles = false; + unsigned int m_maxResults = 100; //默认取100条结果 + int m_informNum = 0; + QMap m_searchType2ResultProperties; + QMap m_customSearchType2ResultDataType; +}; void SearchControllerPrivate::clearAllConditions() -{ - clearKeyWords(); - clearSearchDir(); - clearFileLabel(); -} - -void SearchControllerPrivate::clearKeyWords() { m_keywords.clear(); -} - -void SearchControllerPrivate::clearSearchDir() -{ m_searchDirs.clear(); -} - -void SearchControllerPrivate::clearFileLabel() -{ m_FileLabels.clear(); + m_recurse = true; + m_activeKeywordSegmentation = false; + m_onlySearchFile = false; + m_onlySearchDir = false; + m_searchOnlineApps = false; } -bool SearchControllerPrivate::setResultDataType(SearchType searchType, ResultDataTypes dataType) +SearchController::SearchController(): d(new SearchControllerPrivate) { - bool res(true); - m_searchType2ResultDataType[searchType] = dataType; - return res; } -bool SearchControllerPrivate::setCustomResultDataType(QString customSearchType, QStringList dataType) +SearchController::SearchController(const SearchController &other):d(other.d) { - bool res(true); - m_customSearchType2ResultDataType[customSearchType] = dataType; - return res; } -void SearchControllerPrivate::setPagination(unsigned int first, unsigned int maxResults) +SearchController &SearchController::operator =(const SearchController &other) { - m_first = first; - m_maxResults = maxResults; + d = other.d; + return *this; } - -unsigned int SearchControllerPrivate::first() const -{ - return m_first; -} - -unsigned int SearchControllerPrivate::maxResults() const -{ - return m_maxResults; -} - -SearchController::SearchController(std::shared_ptr parent) : m_parent(parent), d(new SearchControllerPrivate(this)) +SearchController &SearchController::operator=(SearchController &&other) Q_DECL_NOEXCEPT { + d = other.d; + other.d.reset(); + return *this; } SearchController::~SearchController() { - if(d) { - delete d; - d = nullptr; - } + d.reset(); } DataQueue *SearchController::refreshDataqueue() { - return d->refreshDataqueue(); + if(!d->m_sharedDataQueue.get()) { +// m_dataQueue = new DataQueue; + d->m_sharedDataQueue = std::make_shared>(); + return d->m_sharedDataQueue.get(); + } + d->m_sharedDataQueue.get()->clear(); + return d->m_sharedDataQueue.get(); } size_t SearchController::refreshSearchId() { - return d->refreshSearchId(); + d->m_searchIdMutex.lock(); + d->m_searchId += 1; + d->m_searchIdMutex.unlock(); + return d->m_searchId; } DataQueue *SearchController::initDataQueue() { - return d->initDataQueue(); + if(!d->m_sharedDataQueue.get()) { + d->m_sharedDataQueue = std::make_shared>(); + return d->m_sharedDataQueue.get(); + } + return d->m_sharedDataQueue.get(); } -void SearchController::addSearchDir(QString &path) +void SearchController::addSearchDir(const QString &path) { - return d->addSearchDir(path); + d->m_searchDirs.append(path); } void SearchController::setRecurse(bool recurse) { - d->setRecurse(recurse); + d->m_recurse = recurse;; } -void SearchController::addKeyword(QString &keyword) +void SearchController::addKeyword(const QString &keyword) { - d->addKeyword(keyword); + d->m_keywords.append(keyword); } size_t SearchController::getCurrentSearchId() { - return d->getCurrentSearchId(); + d->m_searchIdMutex.lock(); + size_t searchId = d->m_searchId; + d->m_searchIdMutex.unlock(); + + return searchId; } DataQueue *SearchController::getDataQueue() { - return d->getDataQueue(); + return d->m_sharedDataQueue.get(); } -ResultDataTypes SearchController::getResultDataType(SearchType searchType) +SearchResultProperties SearchController::getResultProperties(SearchProperty::SearchType searchType) { - return d->getResultDataType(searchType); + return d->m_searchType2ResultProperties[searchType];; } QStringList SearchController::getCustomResultDataType(QString customSearchType) { - return d->getCustomResultDataType(customSearchType); + return d->m_customSearchType2ResultDataType[customSearchType]; } void SearchController::setActiveKeywordSegmentation(bool active) { - d->setActiveKeywordSegmentation(active); + d->m_activeKeywordSegmentation = active;; } -void SearchController::addFileLabel(QString &label) +void SearchController::addFileLabel(const QString &label) { - d->addFileLabel(label); + d->m_FileLabels.append(label);; } void SearchController::setOnlySearchFile(bool onlySearchFile) { - d->setOnlySearchFile(onlySearchFile); + d->m_onlySearchFile = onlySearchFile; } void SearchController::setOnlySearchDir(bool onlySearchDir) { - d->setOnlySearchDir(onlySearchDir); + d->m_onlySearchDir = onlySearchDir; } void SearchController::setSearchOnlineApps(bool searchOnlineApps) { - d->setSearchOnlineApps(searchOnlineApps); + d->m_searchOnlineApps = searchOnlineApps; +} + +void SearchController::setSearchHiddenFiles(bool searchHiddenFiles) +{ + d->m_searchHiddenFiles = searchHiddenFiles; } bool SearchController::beginSearchIdCheck(size_t searchId) { - return d->beginSearchIdCheck(searchId); + d->m_searchIdMutex.lock(); + return d->m_searchId == searchId; } void SearchController::finishSearchIdCheck() { - d->finishSearchIdCheck(); + d->m_searchIdMutex.unlock(); + return; } QStringList SearchController::getSearchDir() { - return d->getSearchDir(); + return d->m_searchDirs; } bool SearchController::isRecurse() { - return d->isRecurse(); + return d->m_recurse; } QStringList SearchController::getKeyword() { - return d->getKeyword(); + return d->m_keywords; } bool SearchController::isKeywordSegmentationActived() { - return d->isKeywordSegmentationActived(); + return d->m_activeKeywordSegmentation; } QStringList SearchController::getFileLabel() { - return d->getFileLabel(); + return d->m_FileLabels; } bool SearchController::isSearchFileOnly() { - return d->isSearchFileOnly(); + return d->m_onlySearchFile; } bool SearchController::isSearchDirOnly() { - return d->isSearchDirOnly(); + return d->m_onlySearchDir; } bool SearchController::isSearchOnlineApps() { - return d->isSearchOnlineApps(); + return d->m_searchOnlineApps; +} + +bool SearchController::searchHiddenFiles() +{ + return d->m_searchHiddenFiles; } void SearchController::stop() { - d->stop(); + d->m_searchIdMutex.lock(); + d->m_searchId += 1; + d->m_searchIdMutex.unlock(); } void SearchController::clearAllConditions() @@ -388,40 +234,49 @@ void SearchController::clearAllConditions() void SearchController::clearKeyWords() { - d->clearKeyWords(); + d->m_keywords.clear(); } void SearchController::clearSearchDir() { - d->clearSearchDir(); + d->m_searchDirs.clear(); } void SearchController::clearFileLabel() { - d->clearFileLabel(); + d->m_FileLabels.clear(); } -void SearchController::setPagination(unsigned int first, unsigned int maxResults) +void SearchController::setMaxResultNum(unsigned int maxResults) { - d->setPagination(first, maxResults); + d->m_maxResults = maxResults; } -unsigned int SearchController::first() const +void SearchController::setInformNum(int num) { - return d->first(); + if(num >= 0) { + d->m_informNum = num; + } } unsigned int SearchController::maxResults() const { - return d->maxResults(); + return d->m_maxResults; } -bool SearchController::setResultDataType(SearchType searchType, ResultDataTypes dataType) +int SearchController::informNum() const { - return d->setResultDataType(searchType, dataType); + return d->m_informNum; } -bool SearchController::setCustomResultDataType(QString customSearchType, QStringList dataType) +bool SearchController::setResultProperties(SearchProperty::SearchType searchType, SearchResultProperties searchResultProperties) { - return d->setCustomResultDataType(customSearchType, dataType); + d->m_searchType2ResultProperties[searchType] = searchResultProperties; + return true; +} + +void SearchController::setCustomResultDataType(QString customSearchType, QStringList dataType) +{ + d->m_customSearchType2ResultDataType[customSearchType] = dataType; +} } diff --git a/libsearch/searchinterface/search-controller.h b/libsearch/searchinterface/search-controller.h index 53b219a..73c3bdc 100644 --- a/libsearch/searchinterface/search-controller.h +++ b/libsearch/searchinterface/search-controller.h @@ -4,7 +4,7 @@ #include #include #include "data-queue.h" -#include "common-defines.h" +#include "search-result-property.h" //todo: url parser? namespace UkuiSearch { class UkuiSearchTask; @@ -15,31 +15,34 @@ class SearchControllerPrivate; */ class SearchController { - friend class SearchControllerPrivate; public: - explicit SearchController(std::shared_ptr parent = nullptr); - SearchController(SearchController &) = delete; - SearchController &operator =(const SearchController &) = delete; + SearchController(); + SearchController(const SearchController &other); + SearchController &operator=(const SearchController &other); + SearchController &operator=(SearchController &&other) Q_DECL_NOEXCEPT; + ~SearchController(); DataQueue* refreshDataqueue(); size_t refreshSearchId(); DataQueue* initDataQueue(); void stop(); - - void addSearchDir(QString &path); + void addSearchDir(const QString &path); void setRecurse(bool recurse = true); - void addKeyword(QString &keyword); + void addKeyword(const QString &keyword); void setActiveKeywordSegmentation(bool active); - void addFileLabel(QString &label); + void addFileLabel(const QString &label); void setOnlySearchFile(bool onlySearchFile); void setOnlySearchDir(bool onlySearchDir); void setSearchOnlineApps(bool searchOnlineApps); + void setSearchHiddenFiles(bool searchHiddenFiles); + void setMaxResultNum(unsigned int maxResults); + void setInformNum(int num = 0); //以上方法插件请不要调用 //以下方法插件可以调用 size_t getCurrentSearchId(); DataQueue* getDataQueue(); - ResultDataTypes getResultDataType(SearchType searchType); + SearchResultProperties getResultProperties(SearchProperty::SearchType searchType); QStringList getCustomResultDataType(QString customSearchType); bool beginSearchIdCheck(size_t searchId); void finishSearchIdCheck(); @@ -52,20 +55,19 @@ public: bool isSearchFileOnly(); bool isSearchDirOnly(); bool isSearchOnlineApps(); + bool searchHiddenFiles(); void clearAllConditions(); void clearKeyWords(); void clearSearchDir(); void clearFileLabel(); - void setPagination(unsigned int first, unsigned int maxResults); - unsigned int first() const; unsigned int maxResults() const; + int informNum() const; - bool setResultDataType(SearchType searchType, ResultDataTypes dataType); - bool setCustomResultDataType(QString customSearchType, QStringList dataType); + bool setResultProperties(SearchProperty::SearchType searchType, UkuiSearch::SearchResultProperties searchResultProperties); + void setCustomResultDataType(QString customSearchType, QStringList dataType); private: - std::shared_ptr m_parent = nullptr; - SearchControllerPrivate *d = nullptr; + std::shared_ptr d; }; } diff --git a/libsearch/searchinterface/search-interface.pri b/libsearch/searchinterface/search-interface.pri deleted file mode 100644 index a81d7f8..0000000 --- a/libsearch/searchinterface/search-interface.pri +++ /dev/null @@ -1,16 +0,0 @@ -INCLUDEPATH += $$PWD -include(searchtasks/search-tasks.pri) - -HEADERS += \ - $$PWD/result-item-private.h \ - $$PWD/search-controller-private.h \ - $$PWD/search-controller.h \ - $$PWD/result-item.h \ - $$PWD/ukui-search-task-private.h \ - $$PWD/ukui-search-task.h - -SOURCES += \ - $$PWD/search-controller.cpp \ - $$PWD/result-item.cpp \ - $$PWD/ukui-search-task.cpp - diff --git a/libsearch/searchinterface/search-result-property-info.cpp b/libsearch/searchinterface/search-result-property-info.cpp new file mode 100644 index 0000000..cac4f81 --- /dev/null +++ b/libsearch/searchinterface/search-result-property-info.cpp @@ -0,0 +1,117 @@ +#include "search-result-property-info.h" +#include +#include +using namespace UkuiSearch; +class UkuiSearch::SearchResultPropertyInfoPrivate +{ +public: + SearchProperty::SearchResultProperty m_property; + QString m_name; + QString m_displayName; + QMetaType::Type m_valueType; +}; +SearchResultPropertyInfo::SearchResultPropertyInfo():d(new SearchResultPropertyInfoPrivate) +{ + d->m_property = SearchProperty::SearchResultProperty::Invalid; + d->m_name = QStringLiteral("Invalid"); + d->m_valueType = QMetaType::UnknownType; +} + +SearchResultPropertyInfo::SearchResultPropertyInfo(SearchProperty::SearchResultProperty property): d(new SearchResultPropertyInfoPrivate) +{ + d->m_property = property; + switch (property) { + case SearchProperty::SearchResultProperty::FilePath: + d->m_name = QStringLiteral("FilePath"); + d->m_displayName = tr("file path"); + d->m_valueType = QMetaType::QString; + break; + + case SearchProperty::SearchResultProperty::FileName: + d->m_name = QStringLiteral("FileName"); + d->m_displayName = tr("file name"); + d->m_valueType = QMetaType::QString; + break; + + case SearchProperty::SearchResultProperty::FileIconName: + d->m_name = QStringLiteral("FileIconName"); + d->m_displayName = tr("file icon name"); + d->m_valueType = QMetaType::QString; + break; + + case SearchProperty::SearchResultProperty::ModifiedTime: + d->m_name = QStringLiteral("ModifiedTime"); + d->m_displayName = tr("modified time"); + d->m_valueType = QMetaType::QDateTime; + break; + + case SearchProperty::SearchResultProperty::ApplicationDesktopPath: + d->m_name = QStringLiteral("ApplicationDesktopPath"); + d->m_displayName = tr("application desktop file path"); + d->m_valueType = QMetaType::QString; + break; + + case SearchProperty::SearchResultProperty::ApplicationLocalName: + d->m_name = QStringLiteral("ApplicationLocalName"); + d->m_displayName = tr("application local name"); + d->m_valueType = QMetaType::QString; + break; + + case SearchProperty::SearchResultProperty::ApplicationIconName: + d->m_name = QStringLiteral("ApplicationIconName"); + d->m_displayName = tr("application icon name"); + d->m_valueType = QMetaType::QString; + break; + + case SearchProperty::SearchResultProperty::ApplicationDescription: + d->m_name = QStringLiteral("ApplicationDescription"); + d->m_displayName = tr("application description"); + d->m_valueType = QMetaType::QString; + break; + + case SearchProperty::SearchResultProperty::IsOnlineApplication: + d->m_name = QStringLiteral("IsOnlineApplication"); + d->m_displayName = tr("is online application"); + d->m_valueType = QMetaType::Int; + break; + + case SearchProperty::SearchResultProperty::ApplicationPkgName: + d->m_name = QStringLiteral("ApplicationPkgName"); + d->m_displayName = tr("application package name"); + d->m_valueType = QMetaType::QString; + break; + default: + break; + } +} + +SearchResultPropertyInfo::SearchResultPropertyInfo(const SearchResultPropertyInfo &other): d(new SearchResultPropertyInfoPrivate(*other.d)) +{ +} + +SearchResultPropertyInfo &UkuiSearch::SearchResultPropertyInfo::operator=(const SearchResultPropertyInfo &rhs) +{ + *d = *rhs.d; + return *this; +} + +bool SearchResultPropertyInfo::operator==(const SearchResultPropertyInfo &rhs) const +{ + return d->m_name == rhs.d->m_name && d->m_displayName == rhs.d->m_displayName && + d->m_property == rhs.d->m_property; +} + +SearchProperty::SearchResultProperty UkuiSearch::SearchResultPropertyInfo::property() const +{ + return d->m_property; +} + +QString SearchResultPropertyInfo::name() const +{ + return d->m_name; +} + +QString SearchResultPropertyInfo::displayName() const +{ + return d->m_displayName; +} diff --git a/libsearch/searchinterface/search-result-property-info.h b/libsearch/searchinterface/search-result-property-info.h new file mode 100644 index 0000000..f6fb5ef --- /dev/null +++ b/libsearch/searchinterface/search-result-property-info.h @@ -0,0 +1,24 @@ +#ifndef SEARCHRESULTPROPERTYINFO_H +#define SEARCHRESULTPROPERTYINFO_H +#include "search-result-property.h" +#include +namespace UkuiSearch { +class SearchResultPropertyInfoPrivate; +class SearchResultPropertyInfo: public QObject +{ + Q_OBJECT +public: + SearchResultPropertyInfo(); + explicit SearchResultPropertyInfo(SearchProperty::SearchResultProperty property); + SearchResultPropertyInfo(const SearchResultPropertyInfo &other); + SearchResultPropertyInfo& operator=(const SearchResultPropertyInfo& rhs); + bool operator==(const SearchResultPropertyInfo& rhs) const; + + SearchProperty::SearchResultProperty property() const; + QString name() const; + QString displayName() const; +private: + SearchResultPropertyInfoPrivate *d = nullptr; +}; +} +#endif // SEARCHRESULTPROPERTYINFO_H diff --git a/libsearch/searchinterface/search-result-property.h b/libsearch/searchinterface/search-result-property.h new file mode 100644 index 0000000..6402210 --- /dev/null +++ b/libsearch/searchinterface/search-result-property.h @@ -0,0 +1,64 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef SEARCHRESULTPROPERTY_H +#define SEARCHRESULTPROPERTY_H +#include +#include +#include +namespace UkuiSearch { +namespace SearchProperty { + +/** + * @brief The SearchType enum 表示搜索插件种类 + */ +enum class SearchType +{ + File = 1u << 0, + FileContent = 1u << 1, + Application = 1u << 2, + Setting = 1u << 3, + Note = 1u << 4, + Mail = 1u << 5, + Custom = 1u << 6 +}; +/** + * @brief The SearchResultProperty enum 表示搜索结果信息 + */ +enum SearchResultProperty { + Invalid = 0, + //文件搜索 + FilePath, //文件路径 + FileName, //文件名 + FileIconName, //文件图标名称 + ModifiedTime, //文件修改时间 + //应用搜索 + ApplicationDesktopPath, //应用desktop文件路径 + ApplicationLocalName, //应用本地化名称 + ApplicationIconName, //应用图标名称(或路径) + ApplicationDescription, //应用描述(针对软件商店上架应用) + IsOnlineApplication, //是否是未安装应用 + ApplicationPkgName //应用包名 +}; +} +typedef QVector SearchResultProperties; +typedef QMap SearchResultPropertyMap; +} +Q_DECLARE_METATYPE(UkuiSearch::SearchResultProperties); +#endif // SEARCHRESULTPROPERTY_H diff --git a/libsearch/searchinterface/searchtasks/app-search-task.cpp b/libsearch/searchinterface/searchtasks/app-search-task.cpp index feb76cc..91cfe64 100644 --- a/libsearch/searchinterface/searchtasks/app-search-task.cpp +++ b/libsearch/searchinterface/searchtasks/app-search-task.cpp @@ -1,7 +1,25 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "app-search-task.h" #include "index-status-recorder.h" #include "common.h" -#include #include #include #include @@ -13,8 +31,23 @@ AppSearchTask::AppSearchTask(QObject *parent) this->setParent(parent); qRegisterMetaType("size_t"); m_pool = new QThreadPool(this); - m_appInfoTable = new AppInfoTable(this); - m_pool->setMaxThreadCount(1); + m_pool->setMaxThreadCount(3); + m_dbusCallBackThread = new QThread(this); + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>>(); +} + +AppSearchTask::~AppSearchTask() +{ + m_pool->clear(); + m_pool->waitForDone(); + m_dbusCallBackThread->quit(); + m_dbusCallBackThread->wait(); +} + +void AppSearchTask::setController(const SearchController &searchController) +{ + m_searchController = searchController; } const QString AppSearchTask::name() @@ -32,129 +65,151 @@ QString AppSearchTask::getCustomSearchType() return "Application"; } -void AppSearchTask::startSearch(std::shared_ptr searchController) +void AppSearchTask::startSearch() { - AppSearchWorker *appSearchWorker; - appSearchWorker = new AppSearchWorker(this, searchController); + if(!m_dbusCallBackThread->isRunning()) { + m_dbusCallBackThread->start(); + } + AppSearchWorker *appSearchWorker = new AppSearchWorker(this); m_pool->start(appSearchWorker); } void AppSearchTask::stop() { - -} - -void AppSearchTask::sendFinishSignal(size_t searchId) -{ - Q_EMIT searchFinished(searchId); -} - - -AppSearchWorker::AppSearchWorker(AppSearchTask *AppSarchTask, std::shared_ptr searchController) : - m_AppSearchTask(AppSarchTask), m_searchController(searchController) -{ - qDBusRegisterMetaType>(); - qDBusRegisterMetaType>>(); - m_interFace = new QDBusInterface("com.kylin.softwarecenter.getsearchresults", "/com/kylin/softwarecenter/getsearchresults", - "com.kylin.getsearchresults", - QDBusConnection::sessionBus()); - if(!m_interFace->isValid()) { - qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message()); + if(m_dbusCallBackThread->isRunning()) { + m_dbusCallBackThread->exit(); } - m_interFace->setTimeout(1500); - m_currentSearchId = m_searchController->getCurrentSearchId(); +} + +bool AppSearchTask::isSearching() +{ + return m_pool->activeThreadCount() > 0; +} + +void AppSearchTask::dbusCallBack(QDBusPendingCallWatcher *call) +{ + QDBusPendingReply>> reply = *call; + size_t searchId = call->property("id").value(); + if(reply.isValid()) { + SearchResultProperties properties = call->property("prop").value(); + int resultNum = call->property("num").toInt(); + for(int i = 0; i < reply.value().size(); i++) { + if (m_searchController.beginSearchIdCheck(searchId)) { + ResultItem item(searchId); + item.setItemKey(reply.value().at(i).value("appname")); + if(properties.contains(SearchProperty::SearchResultProperty::ApplicationPkgName)) { + item.setValue(SearchProperty::SearchResultProperty::ApplicationPkgName, reply.value().at(i).value("appname")); + } + + if(properties.contains(SearchProperty::SearchResultProperty::ApplicationLocalName)) { + QString localName; + if(QLocale::system().language() == QLocale::Chinese) { + localName = reply.value().at(i).value("displayname_cn"); + } else { + localName = reply.value().at(i).value("appname"); + } + item.setValue(SearchProperty::SearchResultProperty::ApplicationLocalName, localName); + } + if(properties.contains(SearchProperty::SearchResultProperty::ApplicationIconName)) { + item.setValue(SearchProperty::SearchResultProperty::ApplicationIconName, reply.value().at(i).value("icon")); + } + if(properties.contains(SearchProperty::SearchResultProperty::ApplicationDescription)) { + item.setValue(SearchProperty::SearchResultProperty::ApplicationDescription, reply.value().at(i).value("discription")); + } + if(properties.contains(SearchProperty::SearchResultProperty::IsOnlineApplication)) { + item.setValue(SearchProperty::SearchResultProperty::IsOnlineApplication, 1); + } + m_searchController.getDataQueue()->enqueue(item); + if(++resultNum == m_searchController.informNum()) { + Q_EMIT reachInformNum(); + resultNum = 0; + } + m_searchController.finishSearchIdCheck(); + } else { + qDebug() << "Search id changed!"; + m_searchController.finishSearchIdCheck(); + return; + } + } + Q_EMIT searchFinished(searchId); + } else { + qWarning() << "SoftWareCenter dbus called failed!" << reply.error(); + Q_EMIT searchError(searchId, "SoftWareCenter dbus called failed!"); + } + call->deleteLater(); +} + +AppSearchWorker::AppSearchWorker(AppSearchTask *AppSarchTask): m_appSearchTask(AppSarchTask) +{ + m_controller = &m_appSearchTask->m_searchController; + m_currentSearchId = m_controller->getCurrentSearchId(); } void AppSearchWorker::run() { - QStringList results; - QStringList keyWords = m_searchController->getKeyword(); - ResultDataTypes dataType = m_searchController->getResultDataType(SearchType::Application); - m_AppSearchTask->m_appInfoTable->searchInstallApp(keyWords, results); - for (int i = 0; i < results.size() / 3; i++) { - if (m_searchController->beginSearchIdCheck(m_currentSearchId)) { - QVariantList info; - if (dataType & UkuiSearch::ApplicationDesktopPath) { - info << QVariant(results.at(i*3)); - } - if (dataType & UkuiSearch::ApplicationLocalName) { - info << QVariant(results.at(i*3 + 1)); - } - if (dataType & UkuiSearch::ApplicationIconName) { - info << QVariant(XdgIcon::fromTheme(results.at(i*3 + 2))); - } - if (dataType & UkuiSearch::ApplicationDescription) {//本地应用暂无简介 - info << QVariant(QString()); - } - if (dataType & UkuiSearch::IsOnlineApplication) { - info << QVariant(0); - } - ResultItem ri(m_currentSearchId, results.at(i*3), info); - m_searchController->getDataQueue()->enqueue(ri); - m_searchController->finishSearchIdCheck(); + ApplicationProperties applicationProperties; + SearchResultProperties properties = m_controller->getResultProperties(SearchProperty::SearchType::Application); + if(properties.contains(SearchProperty::SearchResultProperty::ApplicationDesktopPath)) { + applicationProperties.append(ApplicationProperty::DesktopFilePath); + } + if(properties.contains(SearchProperty::SearchResultProperty::ApplicationLocalName)) { + applicationProperties.append(ApplicationProperty::LocalName); + } + if(properties.contains(SearchProperty::SearchResultProperty::ApplicationIconName)) { + applicationProperties.append(ApplicationProperty::Icon); + } + ApplicationInfoMap data = m_appSearchTask->m_appinfo.searchApp(applicationProperties, m_controller->getKeyword(), ApplicationPropertyMap{{ApplicationProperty::DontDisplay, 0}, {ApplicationProperty::AutoStart, 0}}); + for (const QString &desktop : data.keys()) { + if (m_controller->beginSearchIdCheck(m_currentSearchId)) { + ResultItem item(desktop); + item.setSearchId(m_currentSearchId); + + ApplicationPropertyMap oneResult = data.value(desktop); + if(oneResult.contains(ApplicationProperty::DesktopFilePath)) { + item.setValue(SearchProperty::SearchResultProperty::ApplicationDesktopPath, oneResult.value(ApplicationProperty::DesktopFilePath).toString()); + } + if(oneResult.contains(ApplicationProperty::LocalName)) { + item.setValue(SearchProperty::SearchResultProperty::ApplicationLocalName, oneResult.value(ApplicationProperty::LocalName).toString()); + } + if(oneResult.contains(ApplicationProperty::Icon)) { + item.setValue(SearchProperty::SearchResultProperty::ApplicationIconName, oneResult.value(ApplicationProperty::Icon).toString()); + } + m_controller->getDataQueue()->enqueue(item); + if(++m_resultNum == m_controller->informNum()) { + QMetaObject::invokeMethod(m_appSearchTask, "reachInformNum"); + m_resultNum = 0; + } + m_controller->finishSearchIdCheck(); } else { qDebug() << "Search id changed!"; - m_searchController->finishSearchIdCheck(); + m_controller->finishSearchIdCheck(); return; } } - if (m_searchController->isSearchOnlineApps()) { + if (m_controller->isSearchOnlineApps()) { //online app search - for (auto keyword : keyWords) { - QDBusReply>> reply = m_interFace->call("get_search_result", keyword); //阻塞,直到远程方法调用完成。 - if(reply.isValid()) { - for(int i = 0; i < reply.value().size(); i++) { - if (m_searchController->beginSearchIdCheck(m_currentSearchId)) { - QVariantList info; - if (dataType & UkuiSearch::ApplicationDesktopPath) { - info << QVariant(reply.value().at(i).value("appname")); - } - if (dataType & UkuiSearch::ApplicationLocalName) { - QLocale locale; - if(locale.language() == QLocale::Chinese) { - info << QVariant(reply.value().at(i).value("displayname_cn")); - } else { - info << QVariant(reply.value().at(i).value("appname")); - } - } - if (dataType & UkuiSearch::ApplicationIconName) { - info << QVariant(QIcon(reply.value().at(i).value("icon"))); - } - if (dataType & UkuiSearch::ApplicationDescription) {//在线应用有效 - info << QVariant(reply.value().at(i).value("discription")); - } - if (dataType & UkuiSearch::IsOnlineApplication) { - info << QVariant(1); - } - ResultItem ri(m_currentSearchId, reply.value().at(i).value("appname"), info); - m_searchController->getDataQueue()->enqueue(ri); - m_searchController->finishSearchIdCheck(); - } else { - qDebug() << "Search id changed!"; - m_searchController->finishSearchIdCheck(); - return; - } - } - } else { - qWarning() << "SoftWareCenter dbus called failed!" << reply.error(); - sendErrorMsg(QString("SoftWareCenter dbus called failed!") + reply.error().message()); - } + for (auto keyword : m_controller->getKeyword()) { + QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("com.kylin.softwarecenter.getsearchresults"), + QStringLiteral("/com/kylin/softwarecenter/getsearchresults"), + QStringLiteral("com.kylin.getsearchresults"), + QStringLiteral("get_search_result")); + msg.setArguments({keyword}); + QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(msg); + auto *watcher = new QDBusPendingCallWatcher(call); + watcher->setProperty("id", QVariant::fromValue(m_currentSearchId)); + watcher->setProperty("prop", QVariant::fromValue(properties)); + watcher->setProperty("num", m_resultNum); + watcher->moveToThread(m_appSearchTask->m_dbusCallBackThread); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, m_appSearchTask, &AppSearchTask::dbusCallBack, Qt::DirectConnection); } + } else { + QMetaObject::invokeMethod(m_appSearchTask, "searchFinished", Q_ARG(size_t, m_currentSearchId)); } - - QMetaObject::invokeMethod(m_AppSearchTask, "searchFinished", Q_ARG(size_t, m_currentSearchId)); -} - -AppSearchWorker::~AppSearchWorker() -{ - if (m_interFace) - delete m_interFace; - m_interFace = nullptr; } void AppSearchWorker::sendErrorMsg(const QString &msg) { - QMetaObject::invokeMethod(m_AppSearchTask, "searchError", + QMetaObject::invokeMethod(m_appSearchTask, "searchError", Q_ARG(size_t, m_currentSearchId), Q_ARG(QString, msg)); } diff --git a/libsearch/searchinterface/searchtasks/app-search-task.h b/libsearch/searchinterface/searchtasks/app-search-task.h index be00f2f..c7d98b7 100644 --- a/libsearch/searchinterface/searchtasks/app-search-task.h +++ b/libsearch/searchinterface/searchtasks/app-search-task.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef APPSEARCHTASK_H #define APPSEARCHTASK_H @@ -9,7 +28,8 @@ #include "search-task-plugin-iface.h" #include "search-controller.h" #include "result-item.h" -#include "app-info-table.h" +#include "application-info.h" +#include "search-result-property.h" namespace UkuiSearch { class AppSearchTask : public SearchTaskPluginIface @@ -17,42 +37,48 @@ class AppSearchTask : public SearchTaskPluginIface friend class AppSearchWorker; Q_OBJECT public: - explicit AppSearchTask(QObject *parent); + explicit AppSearchTask(QObject *parent = nullptr); + ~AppSearchTask(); + void setController(const SearchController &searchController); PluginType pluginType() {return PluginType::SearchTaskPlugin;} const QString name(); const QString description(); const QIcon icon() {return QIcon::fromTheme("appsearch");} - void setEnable(bool enable) {} + void setEnable(bool enable) {Q_UNUSED(enable)} bool isEnable() { return true;} - SearchType getSearchType() {return SearchType::Application;} + SearchProperty::SearchType getSearchType() {return SearchProperty::SearchType::Application;} QString getCustomSearchType(); - void startSearch(std::shared_ptr searchController); + void startSearch(); void stop(); - Q_INVOKABLE void sendFinishSignal(size_t searchId); + bool isSearching(); + +private Q_SLOTS: + void dbusCallBack(QDBusPendingCallWatcher *call); private: - AppInfoTable *m_appInfoTable = nullptr; + ApplicationInfo m_appinfo; + SearchController m_searchController; QThreadPool *m_pool = nullptr; + QThread *m_dbusCallBackThread = nullptr; }; class AppSearchWorker : public QRunnable { public: - explicit AppSearchWorker(AppSearchTask *AppSarchTask, std::shared_ptr searchController); + explicit AppSearchWorker(AppSearchTask *AppSarchTask); protected: void run(); private: - ~AppSearchWorker(); void sendErrorMsg(const QString &msg); private: - AppSearchTask *m_AppSearchTask = nullptr; - std::shared_ptr m_searchController; - QDBusInterface *m_interFace = nullptr; + SearchController* m_controller = nullptr; + AppSearchTask *m_appSearchTask = nullptr; size_t m_currentSearchId = 0; + int m_resultNum = 0; }; } #endif // APPSEARCHTASK_H diff --git a/libsearch/searchinterface/searchtasks/file-content-search-task.cpp b/libsearch/searchinterface/searchtasks/file-content-search-task.cpp index ddaaf4a..850dee1 100644 --- a/libsearch/searchinterface/searchtasks/file-content-search-task.cpp +++ b/libsearch/searchinterface/searchtasks/file-content-search-task.cpp @@ -1,6 +1,22 @@ -// -// Created by hxf on 2022/4/18. -// +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ //ukui-search #include "file-content-search-task.h" @@ -13,7 +29,7 @@ //Qt #include #include -#include +#include using namespace UkuiSearch; @@ -27,7 +43,13 @@ FileContentSearchTask::FileContentSearchTask(QObject *parent) FileContentSearchTask::~FileContentSearchTask() { + m_pool->clear(); + m_pool->waitForDone(); +} +void FileContentSearchTask::setController(const SearchController &searchController) +{ + m_searchController = searchController; } PluginInterface::PluginType FileContentSearchTask::pluginType() @@ -65,14 +87,14 @@ QString FileContentSearchTask::getCustomSearchType() return tr("File Content"); } -SearchType FileContentSearchTask::getSearchType() +SearchProperty::SearchType FileContentSearchTask::getSearchType() { - return SearchType::FileContent; + return SearchProperty::SearchType::FileContent; } -void FileContentSearchTask::startSearch(std::shared_ptr searchController) +void FileContentSearchTask::startSearch() { - FileContentSearchWorker *worker = new FileContentSearchWorker(this, searchController); + FileContentSearchWorker *worker = new FileContentSearchWorker(this, &m_searchController); m_pool->start(worker); } @@ -81,10 +103,15 @@ void FileContentSearchTask::stop() } -FileContentSearchWorker::FileContentSearchWorker(FileContentSearchTask *fileContentSearchTask, std::shared_ptr searchController) +bool FileContentSearchTask::isSearching() +{ + return m_pool->activeThreadCount() > 0; +} + +FileContentSearchWorker::FileContentSearchWorker(FileContentSearchTask *fileContentSearchTask, SearchController *searchController) { m_fileContentSearchTask = fileContentSearchTask; - m_searchController = std::move(searchController); + m_searchController = searchController; m_currentSearchId = m_searchController->getCurrentSearchId(); } @@ -94,7 +121,7 @@ void FileContentSearchWorker::run() searchDirs.removeDuplicates(); for (QString &dir : searchDirs) { - if (dir.endsWith("/")) { + if (dir.endsWith("/") && dir != "/") { dir = dir.mid(0, dir.length() - 1); } @@ -134,14 +161,33 @@ bool FileContentSearchWorker::execSearch() FileContentSearchFilter filter(this); - Xapian::MSet result = enquire.get_mset(m_searchController->first(), m_searchController->maxResults(), 0, &filter); + Xapian::MSet result = enquire.get_mset(0, m_searchController->maxResults(), 0, &filter); for (auto it = result.begin(); it != result.end(); ++it) { if (m_searchController->beginSearchIdCheck(m_currentSearchId)) { QString path = QString::fromStdString(it.get_document().get_value(CONTENT_DATABASE_PATH_SLOT)); - ResultItem resultItem(m_currentSearchId, path); + SearchResultProperties properties = m_searchController->getResultProperties(SearchProperty::SearchType::File); + ResultItem resultItem(m_currentSearchId); + + if(properties.contains(SearchProperty::SearchResultProperty::FilePath)) { + resultItem.setValue(SearchProperty::SearchResultProperty::FilePath, path); + } + if(properties.contains(SearchProperty::SearchResultProperty::FileIconName)) { + resultItem.setValue(SearchProperty::SearchResultProperty::FileIconName, FileUtils::getFileIcon(QUrl::fromLocalFile(path).toString()).name()); + } + if(properties.contains(SearchProperty::SearchResultProperty::FileName)) { + resultItem.setValue(SearchProperty::SearchResultProperty::FileName, path.section("/", -1)); + } + if(properties.contains(SearchProperty::SearchResultProperty::ModifiedTime)) { + resultItem.setValue(SearchProperty::SearchResultProperty::ModifiedTime, + QDateTime::fromString(QString::fromStdString(it.get_document().get_value(3)), "yyyyMMddHHmmsszzz")); + } m_searchController->getDataQueue()->enqueue(resultItem); + if(++m_resultNum == m_searchController->informNum()) { + QMetaObject::invokeMethod(m_fileContentSearchTask, "reachInformNum"); + m_resultNum = 0; + } m_searchController->finishSearchIdCheck(); } else { @@ -185,16 +231,16 @@ bool FileContentSearchFilter::operator()(const Xapian::Document &doc) const { //在此处对搜索结果进行过滤 QString path = QString::fromStdString(doc.get_value(CONTENT_DATABASE_PATH_SLOT)); - bool isExists = QFileInfo::exists(path); - bool inSearchDir = true; + if(!QFileInfo::exists(path)) { + return false; + } //如果不指定搜索目录,那么搜索整个数据库 if (m_worker && !m_worker->m_validDirectories.empty()) { - inSearchDir = std::any_of(m_worker->m_validDirectories.begin(), m_worker->m_validDirectories.end(), [=] (const QString& dir) { - return path.startsWith(dir); - }); - //TODO 黑名单 + for(const QString &dir : m_worker->m_validDirectories) { + return FileUtils::isOrUnder(path, dir); + } } - return isExists && inSearchDir; + return true; } diff --git a/libsearch/searchinterface/searchtasks/file-content-search-task.h b/libsearch/searchinterface/searchtasks/file-content-search-task.h index 48d441f..2c9dc9b 100644 --- a/libsearch/searchinterface/searchtasks/file-content-search-task.h +++ b/libsearch/searchinterface/searchtasks/file-content-search-task.h @@ -1,6 +1,22 @@ -// -// Created by hxf on 2022/4/18. -// +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef UKUI_SEARCH_FILE_CONTENT_SEARCH_TASK_H #define UKUI_SEARCH_FILE_CONTENT_SEARCH_TASK_H @@ -19,11 +35,12 @@ namespace UkuiSearch { class FileContentSearchTask : public SearchTaskPluginIface { + Q_OBJECT public: explicit FileContentSearchTask(QObject *parent = nullptr); ~FileContentSearchTask() override; - + void setController(const SearchController &searchController) override; PluginType pluginType() override; const QString name() override; const QString description() override; @@ -32,13 +49,15 @@ public: bool isEnable() override; QString getCustomSearchType() override; - SearchType getSearchType() override; - void startSearch(std::shared_ptr searchController) override; + SearchProperty::SearchType getSearchType() override; + void startSearch() override; void stop() override; + bool isSearching() override; private: QThreadPool *m_pool = nullptr; bool m_enable = true; + SearchController m_searchController; }; class FileContentSearchWorker : public QRunnable @@ -46,8 +65,7 @@ class FileContentSearchWorker : public QRunnable friend class FileContentSearchFilter; public: - explicit FileContentSearchWorker(FileContentSearchTask *fileContentSearchTask, std::shared_ptr searchController); - + explicit FileContentSearchWorker(FileContentSearchTask *fileContentSearchTask, SearchController *searchController); void run() override; private: @@ -58,11 +76,10 @@ private: private: FileContentSearchTask *m_fileContentSearchTask = nullptr; - std::shared_ptr m_searchController; - + SearchController *m_searchController = nullptr; QStringList m_validDirectories; - size_t m_currentSearchId = 0; + int m_resultNum = 0; }; class FileContentSearchFilter : public Xapian::MatchDecider { diff --git a/libsearch/searchinterface/searchtasks/file-search-task.cpp b/libsearch/searchinterface/searchtasks/file-search-task.cpp index e50124f..8a870af 100644 --- a/libsearch/searchinterface/searchtasks/file-search-task.cpp +++ b/libsearch/searchinterface/searchtasks/file-search-task.cpp @@ -1,14 +1,35 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "file-search-task.h" -#include "index-status-recorder.h" -#include "dir-watcher.h" -#include "common.h" - #include #include #include #include #include +#include #include +#include +#include "index-status-recorder.h" +#include "dir-watcher.h" +#include "common.h" +#include "file-utils.h" using namespace UkuiSearch; FileSearchTask::FileSearchTask(QObject *parent) @@ -19,6 +40,17 @@ FileSearchTask::FileSearchTask(QObject *parent) m_pool->setMaxThreadCount(1); } +FileSearchTask::~FileSearchTask() +{ + m_pool->clear(); + m_pool->waitForDone(); +} + +void FileSearchTask::setController(const SearchController &searchController) +{ + m_searchController = searchController; +} + const QString FileSearchTask::name() { return "File"; @@ -34,10 +66,10 @@ QString FileSearchTask::getCustomSearchType() return "File"; } -void FileSearchTask::startSearch(std::shared_ptr searchController) +void FileSearchTask::startSearch() { FileSearchWorker *fileSearchWorker; - fileSearchWorker = new FileSearchWorker(this, searchController); + fileSearchWorker = new FileSearchWorker(this, &m_searchController); m_pool->start(fileSearchWorker); } @@ -46,14 +78,14 @@ void FileSearchTask::stop() } -void FileSearchTask::sendFinishSignal(size_t searchId) +bool FileSearchTask::isSearching() { - Q_EMIT searchFinished(searchId); + return m_pool->activeThreadCount() > 0; } - -FileSearchWorker::FileSearchWorker(FileSearchTask *fileSarchTask, std::shared_ptr searchController) : m_FileSearchTask(fileSarchTask), m_searchController(searchController) +FileSearchWorker::FileSearchWorker(FileSearchTask *fileSarchTask, SearchController *searchController) : m_FileSearchTask(fileSarchTask) { + m_searchController = searchController; m_currentSearchId = m_searchController->getCurrentSearchId(); } @@ -65,7 +97,7 @@ void FileSearchWorker::run() for (QString &dir : searchDirs) { if (QFileInfo::exists(dir)) { - if (dir.endsWith("/")) { + if (dir.endsWith("/") && dir != "/") { dir.remove(dir.length() - 1, 1); } @@ -85,11 +117,31 @@ void FileSearchWorker::run() } bool finished = true; + bool indexed = true; + + QStringList indexedDir = DirWatcher::getDirWatcher()->currentIndexableDir(); + if(!indexedDir.isEmpty() && IndexStatusRecorder::getInstance()->indexDatabaseEnable() && !m_searchController->searchHiddenFiles()) { + for(const QString &path : m_searchController->getSearchDir()) { + bool pathIndexed = false; + for(const QString &dir : indexedDir) { + if(FileUtils::isOrUnder(path, dir)) { + pathIndexed = true; + break; + } + } + if(!pathIndexed) { + indexed = false; + break; + } + } + } else { + indexed = false; + } + //TODO 还需要判断是否为不能建立索引的目录 - if (IndexStatusRecorder::getInstance()->indexDatabaseEnable()) { + if (indexed) { qDebug() << "index ready"; finished = searchWithIndex(); - } else { if (m_validDirectories.empty()) { //TODO 使用全局的默认可搜索目录 @@ -145,14 +197,32 @@ bool FileSearchWorker::searchWithIndex() enquire.set_query(creatQueryForFileSearch()); FileSearchFilter fileSearchFilter(this); - Xapian::MSet result = enquire.get_mset(m_searchController->first(), m_searchController->maxResults(), 0, &fileSearchFilter); + Xapian::MSet result = enquire.get_mset(0, m_searchController->maxResults(), 0, &fileSearchFilter); for (auto it = result.begin(); it != result.end(); ++it) { if (m_searchController->beginSearchIdCheck(m_currentSearchId)) { - std::string data = it.get_document().get_data(); - - ResultItem resultItem(m_currentSearchId, QString::fromStdString(data)); + QString path = QString::fromStdString(it.get_document().get_data()); + SearchResultProperties properties = m_searchController->getResultProperties(SearchProperty::SearchType::File); + ResultItem resultItem(m_currentSearchId); + resultItem.setItemKey(path); + if(properties.contains(SearchProperty::SearchResultProperty::FilePath)) { + resultItem.setValue(SearchProperty::SearchResultProperty::FilePath, path); + } + if(properties.contains(SearchProperty::SearchResultProperty::FileIconName)) { + resultItem.setValue(SearchProperty::SearchResultProperty::FileIconName, FileUtils::getFileIcon(QUrl::fromLocalFile(path).toString()).name()); + } + if(properties.contains(SearchProperty::SearchResultProperty::FileName)) { + resultItem.setValue(SearchProperty::SearchResultProperty::FileName, path.section("/", -1)); + } + if(properties.contains(SearchProperty::SearchResultProperty::ModifiedTime)) { + resultItem.setValue(SearchProperty::SearchResultProperty::ModifiedTime, + QDateTime::fromString(QString::fromStdString(it.get_document().get_value(2)), "yyyyMMddHHmmsszzz")); + } m_searchController->getDataQueue()->enqueue(resultItem); + if(++m_resultNum == m_searchController->informNum()) { + QMetaObject::invokeMethod(m_FileSearchTask, "reachInformNum"); + m_resultNum = 0; + } m_searchController->finishSearchIdCheck(); } else { @@ -188,19 +258,22 @@ bool FileSearchWorker::directSearch() QDir dir; QFileInfoList infoList; + QDir::Filters filters; if (m_searchController->isSearchDirOnly()) { - dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + filters = QDir::Dirs | QDir::NoDotAndDotDot; } else { - dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot; dir.setSorting(QDir::DirsFirst); } - + if(m_searchController->searchHiddenFiles()) { + filters |= QDir::Hidden; + } + dir.setFilter(filters); while (!searchPathQueue.empty()) { dir.setPath(searchPathQueue.dequeue()); if (!dir.exists()) continue; infoList = dir.entryInfoList(); - for (const auto &fileInfo : infoList) { if (fileInfo.isDir() && !fileInfo.isSymLink()) { QString newPath = fileInfo.absoluteFilePath(); @@ -216,6 +289,9 @@ bool FileSearchWorker::directSearch() if (m_searchController->isRecurse()) { searchPathQueue.enqueue(newPath); } + if (m_searchController->isSearchFileOnly()) { + continue; + } } bool matched = false; @@ -236,8 +312,26 @@ bool FileSearchWorker::directSearch() if (m_searchController->beginSearchIdCheck(m_currentSearchId)) { if (matched) { - ResultItem ri(m_currentSearchId, fileInfo.absoluteFilePath()); + ResultItem ri(m_currentSearchId); + ri.setItemKey(fileInfo.absoluteFilePath()); + SearchResultProperties properties = m_searchController->getResultProperties(SearchProperty::SearchType::File); + if(properties.contains(SearchProperty::SearchResultProperty::FilePath)) { + ri.setValue(SearchProperty::SearchResultProperty::FilePath, fileInfo.absoluteFilePath()); + } + if(properties.contains(SearchProperty::SearchResultProperty::FileIconName)) { + ri.setValue(SearchProperty::SearchResultProperty::FileIconName, FileUtils::getFileIcon(QUrl::fromLocalFile(fileInfo.absoluteFilePath()).toString()).name()); + } + if(properties.contains(SearchProperty::SearchResultProperty::FileName)) { + ri.setValue(SearchProperty::SearchResultProperty::FileName, fileInfo.fileName()); + } + if(properties.contains(SearchProperty::SearchResultProperty::ModifiedTime)) { + ri.setValue(SearchProperty::SearchResultProperty::ModifiedTime, fileInfo.lastModified()); + } m_searchController->getDataQueue()->enqueue(ri); + if(++m_resultNum == m_searchController->informNum()) { + QMetaObject::invokeMethod(m_FileSearchTask, "reachInformNum"); + m_resultNum = 0; + } --maxResults; } m_searchController->finishSearchIdCheck(); @@ -267,7 +361,7 @@ bool FileSearchFilter::operator ()(const Xapian::Document &doc) const if (!m_parent->m_validDirectories.empty()) { inSearchDir = std::any_of(m_parent->m_validDirectories.begin(), m_parent->m_validDirectories.end(), [&](QString &dir) { //限制搜索在该目录下 - if (!path.startsWith(dir + "/")) { + if (dir != "/" && !path.startsWith(dir + "/")) { return false; } diff --git a/libsearch/searchinterface/searchtasks/file-search-task.h b/libsearch/searchinterface/searchtasks/file-search-task.h index 1acacaf..2aef7b9 100644 --- a/libsearch/searchinterface/searchtasks/file-search-task.h +++ b/libsearch/searchinterface/searchtasks/file-search-task.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef FILESEARCHTASK_H #define FILESEARCHTASK_H @@ -15,22 +34,26 @@ class FileSearchTask : public SearchTaskPluginIface { Q_OBJECT public: - explicit FileSearchTask(QObject *parent); + explicit FileSearchTask(QObject *parent = nullptr); + ~FileSearchTask(); + + void setController(const SearchController &searchController); PluginType pluginType() {return PluginType::SearchTaskPlugin;} const QString name(); const QString description(); const QIcon icon() {return QIcon::fromTheme("folder");} - void setEnable(bool enable) {} + void setEnable(bool enable) {Q_UNUSED(enable)} bool isEnable() { return true;} - SearchType getSearchType() {return SearchType::File;} + SearchProperty::SearchType getSearchType() {return SearchProperty::SearchType::File;} QString getCustomSearchType(); - void startSearch(std::shared_ptr searchController); + void startSearch(); void stop(); - Q_INVOKABLE void sendFinishSignal(size_t searchId); + bool isSearching(); private: QThreadPool *m_pool = nullptr; + SearchController m_searchController; }; class FileSearchWorker : public QRunnable @@ -38,7 +61,7 @@ class FileSearchWorker : public QRunnable friend class FileSearchFilter; public: - explicit FileSearchWorker(FileSearchTask *fileSarchTask, std::shared_ptr searchController); + explicit FileSearchWorker(FileSearchTask *fileSarchTask, SearchController *searchController); protected: void run(); @@ -58,9 +81,10 @@ private: private: FileSearchTask *m_FileSearchTask; - std::shared_ptr m_searchController; + SearchController *m_searchController = nullptr; size_t m_currentSearchId = 0; + int m_resultNum = 0; QStringList m_validDirectories; QStringList m_blackList; QStringList m_labels; diff --git a/libsearch/searchinterface/ukui-search-task-private.h b/libsearch/searchinterface/ukui-search-task-private.h index e7d6fa7..a622446 100644 --- a/libsearch/searchinterface/ukui-search-task-private.h +++ b/libsearch/searchinterface/ukui-search-task-private.h @@ -19,10 +19,10 @@ public: explicit UkuiSearchTaskPrivate(UkuiSearchTask* parent); ~UkuiSearchTaskPrivate(); DataQueue* init(); - void addSearchDir(QString &path); + void addSearchDir(const QString &path); void setRecurse(bool recurse = true); - void addKeyword(QString &keyword); - void addFileLabel(QString &label); + void addKeyword(const QString &keyword); + void addFileLabel(const QString &label); void setOnlySearchFile(bool onlySearchFile); void setOnlySearchDir(bool onlySearchDir); void setSearchOnlineApps(bool searchOnlineApps); diff --git a/libsearch/searchinterface/ukui-search-task.cpp b/libsearch/searchinterface/ukui-search-task.cpp index 396d311..2158097 100644 --- a/libsearch/searchinterface/ukui-search-task.cpp +++ b/libsearch/searchinterface/ukui-search-task.cpp @@ -1,226 +1,150 @@ #include "ukui-search-task.h" -#include "ukui-search-task-private.h" #include "search-task-plugin-manager.h" #include using namespace UkuiSearch; -UkuiSearchTaskPrivate::UkuiSearchTaskPrivate(UkuiSearchTask *parent) - : QObject(parent), - q(parent) +namespace UkuiSearch { + +class UkuiSearchTaskPrivate { - m_searchCotroller = std::make_shared(); - m_uuid = QUuid::createUuid(); + friend class UkuiSearchTask; +private: + SearchController m_searchCotroller; + size_t m_searchId = 0; + QUuid m_uuid; +}; } -UkuiSearchTaskPrivate::~UkuiSearchTaskPrivate() +UkuiSearchTask::UkuiSearchTask(QObject *parent) : QObject(parent), d(new UkuiSearchTaskPrivate()) { - this->stop(); - SearchTaskPluginManager::getInstance()->destroyPlugins(m_uuid); + d->m_uuid = QUuid::createUuid(); } -DataQueue *UkuiSearchTaskPrivate::init() +UkuiSearchTask::~UkuiSearchTask() { - return m_searchCotroller->initDataQueue(); + stop(); + SearchTaskPluginManager::getInstance()->destroyPlugins(d->m_uuid); } -void UkuiSearchTaskPrivate::addSearchDir(QString &path) +DataQueue *UkuiSearchTask::init() { - m_searchCotroller->addSearchDir(path); + return d->m_searchCotroller.initDataQueue(); } -void UkuiSearchTaskPrivate::setRecurse(bool recurse) +void UkuiSearchTask::addSearchDir(const QString &path) { - m_searchCotroller->setRecurse(recurse); + d->m_searchCotroller.addSearchDir(path); } -void UkuiSearchTaskPrivate::addKeyword(QString &keyword) +void UkuiSearchTask::setRecurse(bool recurse) { - m_searchCotroller->addKeyword(keyword); + d->m_searchCotroller.setRecurse(recurse); } -void UkuiSearchTaskPrivate::addFileLabel(QString &label) +void UkuiSearchTask::addKeyword(const QString &keyword) { - m_searchCotroller->addFileLabel(label); + d->m_searchCotroller.addKeyword(keyword); } -void UkuiSearchTaskPrivate::setOnlySearchFile(bool onlySearchFile) +void UkuiSearchTask::addFileLabel(const QString &label) { - m_searchCotroller->setOnlySearchFile(onlySearchFile); + d->m_searchCotroller.addFileLabel(label); } -void UkuiSearchTaskPrivate::setOnlySearchDir(bool onlySearchDir) +void UkuiSearchTask::setOnlySearchFile(bool onlySearchFile) { - m_searchCotroller->setOnlySearchDir(onlySearchDir); + d->m_searchCotroller.setOnlySearchFile(onlySearchFile); } -void UkuiSearchTaskPrivate::setSearchOnlineApps(bool searchOnlineApps) +void UkuiSearchTask::setOnlySearchDir(bool onlySearchDir) { - m_searchCotroller->setSearchOnlineApps(searchOnlineApps); + d->m_searchCotroller.setOnlySearchDir(onlySearchDir); } -void UkuiSearchTaskPrivate::initSearchPlugin(SearchType searchType, const QString& customSearchType) +void UkuiSearchTask::setSearchOnlineApps(bool searchOnlineApps) { - SearchTaskPluginIface *plugin = SearchTaskPluginManager::getInstance()->initPlugins(m_uuid, searchType, customSearchType); + d->m_searchCotroller.setSearchOnlineApps(searchOnlineApps); +} + +void UkuiSearchTask::setSearchHiddenFiles(bool searchHiddenFiles) +{ + d->m_searchCotroller.setSearchHiddenFiles(searchHiddenFiles); +} + +void UkuiSearchTask::initSearchPlugin(SearchProperty::SearchType searchType, const QString &customSearchType) +{ + SearchTaskPluginIface *plugin = SearchTaskPluginManager::getInstance()->initPlugins(d->m_uuid, searchType, customSearchType); if (plugin) { - connect(plugin, &SearchTaskPluginIface::searchFinished,this, &UkuiSearchTaskPrivate::searchFinished); - connect(plugin, &SearchTaskPluginIface::searchError,this, &UkuiSearchTaskPrivate::searchError); + plugin->setController(d->m_searchCotroller); + connect(plugin, &SearchTaskPluginIface::searchFinished,this, &UkuiSearchTask::searchFinished); + connect(plugin, &SearchTaskPluginIface::searchError,this, &UkuiSearchTask::searchError); + connect(plugin, &SearchTaskPluginIface::reachInformNum,this, &UkuiSearchTask::reachInformNum); } else { qWarning() << "The plugin has been initialized or the plugin failed to load."; } } - -bool UkuiSearchTaskPrivate::setCustomResultDataType(QString customSearchType, QStringList dataType) +bool UkuiSearchTask::setResultProperties(SearchProperty::SearchType searchType, SearchResultProperties searchResultProperties) { - return m_searchCotroller->setCustomResultDataType(customSearchType, dataType); + return d->m_searchCotroller.setResultProperties(searchType, searchResultProperties); } -bool UkuiSearchTaskPrivate::setResultDataType(SearchType searchType, ResultDataTypes dataType) +void UkuiSearchTask::setCustomResultDataType(QString customSearchType, QStringList dataType) { - return m_searchCotroller->setResultDataType(searchType, dataType); + return d->m_searchCotroller.setCustomResultDataType(customSearchType, dataType); } -size_t UkuiSearchTaskPrivate::startSearch(SearchType searchtype, const QString& customSearchType) +size_t UkuiSearchTask::startSearch(SearchProperty::SearchType searchtype, QString customSearchType) { - m_searchId = m_searchCotroller->refreshSearchId(); - if(m_searchCotroller->getDataQueue() == nullptr) { + d->m_searchId = d->m_searchCotroller.refreshSearchId(); + if(d->m_searchCotroller.getDataQueue() == nullptr) { qWarning() << "the date queue has not been initialized, you need run init first!"; } - m_searchCotroller->refreshDataqueue(); + d->m_searchCotroller.refreshDataqueue(); //plugin manager do async search here - if (!SearchTaskPluginManager::getInstance()->startSearch(m_uuid, m_searchCotroller, searchtype, customSearchType)) { - Q_EMIT searchError(m_searchCotroller->getCurrentSearchId(), tr("Current task uuid error or an unregistered plugin is used!")); + if (!SearchTaskPluginManager::getInstance()->startSearch(d->m_uuid, searchtype, customSearchType)) { + Q_EMIT searchError(d->m_searchCotroller.getCurrentSearchId(), tr("Current task uuid error or an unregistered plugin is used!")); } - return m_searchId; -} - -void UkuiSearchTaskPrivate::stop() -{ - m_searchCotroller->stop(); -} - -void UkuiSearchTaskPrivate::clearKeyWords() -{ - m_searchCotroller->clearKeyWords(); -} - -void UkuiSearchTaskPrivate::clearAllConditions() -{ - m_searchCotroller->clearAllConditions(); -} - -void UkuiSearchTaskPrivate::clearSearchDir() -{ - m_searchCotroller->clearSearchDir(); -} - -void UkuiSearchTaskPrivate::clearFileLabel() -{ - m_searchCotroller->clearFileLabel(); -} - -void UkuiSearchTaskPrivate::setPagination(unsigned int first, unsigned int maxResults) -{ - m_searchCotroller->setPagination(first, maxResults); -} - -UkuiSearchTask::UkuiSearchTask(QObject *parent) : QObject(parent), d(new UkuiSearchTaskPrivate(this)) -{ - connect(d, &UkuiSearchTaskPrivate::searchFinished, this, &UkuiSearchTask::searchFinished); - connect(d, &UkuiSearchTaskPrivate::searchError, this, &UkuiSearchTask::searchError); -} - -UkuiSearchTask::~UkuiSearchTask() -{ -} - -DataQueue *UkuiSearchTask::init() -{ - return d->init(); -} - -void UkuiSearchTask::addSearchDir(QString &path) -{ - d->addSearchDir(path); -} - -void UkuiSearchTask::setRecurse(bool recurse) -{ - d->setRecurse(recurse); -} - -void UkuiSearchTask::addKeyword(QString &keyword) -{ - d->addKeyword(keyword); -} - -void UkuiSearchTask::addFileLabel(QString &label) -{ - d->addFileLabel(label); -} - -void UkuiSearchTask::setOnlySearchFile(bool onlySearchFile) -{ - d->setOnlySearchFile(onlySearchFile); -} - -void UkuiSearchTask::setOnlySearchDir(bool onlySearchDir) -{ - d->setOnlySearchDir(onlySearchDir); -} - -void UkuiSearchTask::setSearchOnlineApps(bool searchOnlineApps) -{ - d->setSearchOnlineApps(searchOnlineApps); -} - -void UkuiSearchTask::initSearchPlugin(SearchType searchType) -{ - d->initSearchPlugin(searchType); -} - -bool UkuiSearchTask::setResultDataType(SearchType searchType, ResultDataTypes dataType) -{ - return d->setResultDataType(searchType, dataType); -} - -bool UkuiSearchTask::setCustomResultDataType(QString customSearchType, QStringList dataType) -{ - return d->setCustomResultDataType(customSearchType, dataType); -} - -size_t UkuiSearchTask::startSearch(SearchType searchtype, QString customSearchType) -{ - return d->startSearch(searchtype, customSearchType); + return d->m_searchId; } void UkuiSearchTask::stop() { - d->stop(); + d->m_searchCotroller.stop(); +} + +bool UkuiSearchTask::isSearching(SearchProperty::SearchType searchtype, QString customSearchType) +{ + return SearchTaskPluginManager::getInstance()->isSearching(d->m_uuid, searchtype, customSearchType); } void UkuiSearchTask::clearAllConditions() { - d->clearAllConditions(); + d->m_searchCotroller.clearAllConditions(); } void UkuiSearchTask::clearKeyWords() { - d->clearKeyWords(); + d->m_searchCotroller.clearKeyWords(); } void UkuiSearchTask::clearSearchDir() { - d->clearSearchDir(); + d->m_searchCotroller.clearSearchDir(); } void UkuiSearchTask::clearFileLabel() { - d->clearFileLabel(); + d->m_searchCotroller.clearFileLabel(); } -void UkuiSearchTask::setPagination(unsigned int first, unsigned int maxResults) +void UkuiSearchTask::setMaxResultNum(unsigned int maxResults) { - d->setPagination(first, maxResults); + d->m_searchCotroller.setMaxResultNum(maxResults); +} + +void UkuiSearchTask::setInformNum(int num) +{ + d->m_searchCotroller.setInformNum(num); } diff --git a/libsearch/searchinterface/ukui-search-task.h b/libsearch/searchinterface/ukui-search-task.h index b2d71e8..b45eb42 100644 --- a/libsearch/searchinterface/ukui-search-task.h +++ b/libsearch/searchinterface/ukui-search-task.h @@ -1,9 +1,28 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #ifndef UKUISEARCH_H #define UKUISEARCH_H #include "result-item.h" #include "data-queue.h" -#include "common-defines.h" +#include "search-result-property.h" namespace UkuiSearch { class UkuiSearchTaskPrivate; class UkuiSearchTask : public QObject @@ -13,35 +32,69 @@ public: explicit UkuiSearchTask(QObject *parent = nullptr); ~UkuiSearchTask(); DataQueue* init(); - void addSearchDir(QString &path); + void addSearchDir(const QString &path); void setRecurse(bool recurse = true); - void addKeyword(QString &keyword); - void addFileLabel(QString &label); + void addKeyword(const QString &keyword); + void addFileLabel(const QString &label); void setOnlySearchFile(bool onlySearchFile); void setOnlySearchDir(bool onlySearchDir); void setSearchOnlineApps(bool searchOnlineApps); - void initSearchPlugin(SearchType searchType); + /** + * 是否搜索隐藏文件 + * @brief setSearchHiddenFiles + * @param searchHiddenFiles + */ + void setSearchHiddenFiles(bool searchHiddenFiles); + /** + * @brief initSearchPlugin 初始化搜索插件 + * @param searchType + * @param customSearchType + */ + void initSearchPlugin(SearchProperty::SearchType searchType, const QString& customSearchType = QString()); /** * @brief setResultDataType * @param searchType * @param dataType * @return */ - bool setResultDataType(SearchType searchType, UkuiSearch::ResultDataTypes dataType); - bool setCustomResultDataType(QString customSearchType, QStringList dataType); + bool setResultProperties(SearchProperty::SearchType searchType, SearchResultProperties searchResultProperties); + void setCustomResultDataType(QString customSearchType, QStringList dataType); void clearAllConditions(); void clearKeyWords(); void clearSearchDir(); void clearFileLabel(); - void setPagination(unsigned int first, unsigned int maxResults); + /** + * @brief setMaxResultNum 设置最大结果数量 + * @param maxResults + */ + void setMaxResultNum(unsigned int maxResults = 99999999); + /** + * @brief setInformNum 设置搜索结果提醒数量 + * @param num + */ + void setInformNum(int num); - size_t startSearch(SearchType searchtype, QString customSearchType = QString()); + /** + * @brief startSearch 启动搜索 + * @param searchtype 搜索插件 + * @param customSearchType 外部插件类型,当searchType为Custom时可用 + * @return + */ + size_t startSearch(SearchProperty::SearchType searchtype, QString customSearchType = QString()); + /** + * @brief stop 停止搜索 + */ void stop(); + /** + * @brief isSearching 查询某个插件是否处于搜索中 + */ + bool isSearching(SearchProperty::SearchType searchtype, QString customSearchType = {}); Q_SIGNALS: void searchFinished(size_t searchId); void searchError(size_t searchId, QString msg); + void reachInformNum(); private: UkuiSearchTaskPrivate* d = nullptr; diff --git a/libsearch/settingsearch/settings-search-plugin.cpp b/libsearch/settingsearch/settings-search-plugin.cpp index bd2ac6a..65c7419 100644 --- a/libsearch/settingsearch/settings-search-plugin.cpp +++ b/libsearch/settingsearch/settings-search-plugin.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "settings-search-plugin.h" #include "file-utils.h" @@ -55,11 +57,13 @@ void SettingsSearchPlugin::stopSearch() QList SettingsSearchPlugin::getActioninfo(int type) { + Q_UNUSED(type) return m_actionInfo; } void SettingsSearchPlugin::openAction(int actionkey, QString key, int type) { + Q_UNUSED(type) //TODO add some return message here. switch (actionkey) { case 0: @@ -89,8 +93,7 @@ void SettingsSearchPlugin::openAction(int actionkey, QString key, int type) if (res) break; //打开控制面板对应页面 - QProcess process; - process.startDetached(QString("ukui-control-center -m %1").arg(key.toLower())); + QProcess::startDetached("ukui-control-center", {"-m", key.toLower()}); break; } default: @@ -436,6 +439,12 @@ void SettingsMatch::createResultInfo(SearchPluginIface::ResultInfo &resultInfo, { QLocale ql; resultInfo.name = ql.language() == QLocale::English ? itemInfo.at(0) : itemInfo.at(1); + if (path.split("/").size() == 3) { + QStringList topInfo = m_dataMap.value(path.left(path.lastIndexOf("/"))); + resultInfo.name.prepend("--"); + resultInfo.name.prepend(ql.language() == QLocale::English ? topInfo.at(0) : topInfo.at(1)); + } + resultInfo.icon = FileUtils::getSettingIcon(); resultInfo.actionKey = path.section("/", 1, 1); } diff --git a/libsearch/settingsearch/settings-search-plugin.h b/libsearch/settingsearch/settings-search-plugin.h index d0f9405..a4af278 100644 --- a/libsearch/settingsearch/settings-search-plugin.h +++ b/libsearch/settingsearch/settings-search-plugin.h @@ -15,6 +15,7 @@ #include "action-label.h" #include "separation-line.h" #include "search-plugin-iface.h" +#include "icon-loader.h" namespace UkuiSearch { class LIBSEARCH_EXPORT SettingsSearchPlugin : public QObject, public SearchPluginIface @@ -27,7 +28,7 @@ public: PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); - const QIcon icon() {return QIcon::fromTheme("folder");} + const QIcon icon() {return IconLoader::loadIconQt("folder");} void setEnable(bool enable) {m_enable = enable;} bool isEnable() {return m_enable;} QString getPluginName(); diff --git a/libsearch/settingsearch/settingsearch.pri b/libsearch/settingsearch/settingsearch.pri deleted file mode 100644 index fd5ff3b..0000000 --- a/libsearch/settingsearch/settingsearch.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/settings-search-plugin.h - -SOURCES += \ - $$PWD/settings-search-plugin.cpp diff --git a/libsearch/ukui-search-config.cmake.in b/libsearch/ukui-search-config.cmake.in new file mode 100644 index 0000000..5e07a90 --- /dev/null +++ b/libsearch/ukui-search-config.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(Qt@QT_VERSION_MAJOR@Core "@REQUIRED_QT_VERSION@") +if(TARGET Qt6::Core) + find_dependency(Qt6Core5Compat @REQUIRED_QT_VERSION@) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/ukui-search-targets.cmake") \ No newline at end of file diff --git a/libsearch/ukui-search.pc.in b/libsearch/ukui-search.pc.in new file mode 100644 index 0000000..ab4ce78 --- /dev/null +++ b/libsearch/ukui-search.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib/@CMAKE_LIBRARY_ARCHITECTURE@ +includedir=${prefix}/include/ukui-search + +Name: ukui-search +Description: ukui-search header files +URL: https://www.ukui.org/ +Version: @VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lukui-search \ No newline at end of file diff --git a/libsearch/websearch/web-search-plugin.cpp b/libsearch/websearch/web-search-plugin.cpp index 6c2462a..a2a78aa 100644 --- a/libsearch/websearch/web-search-plugin.cpp +++ b/libsearch/websearch/web-search-plugin.cpp @@ -1,13 +1,30 @@ -#include #include "web-search-plugin.h" #include "global-settings.h" -#define WEB_ENGINE_KEY "webEngine" +#include +#include +#include +#include +#include + +#define UKUI_SEARCH_SCHEMAS "org.ukui.search.settings" #define BROWSERTYPE "x-scheme-handler/http" #define DESKTOPPATH "/usr/share/applications/" +#define WEB_ENGINE_KEY "webEngine" using namespace UkuiSearch; WebSearchPlugin::WebSearchPlugin(QObject *parent) : QObject(parent) { + if (QGSettings::isSchemaInstalled(UKUI_SEARCH_SCHEMAS)) { + m_settings = new QGSettings(UKUI_SEARCH_SCHEMAS, QByteArray(), this); + if (m_settings->keys().contains(WEB_ENGINE_KEY)) { + m_webEngine = m_settings->get(WEB_ENGINE_KEY).toString(); + } + connect(m_settings, &QGSettings::changed, this, [ & ] (const QString& key) { + if (key == WEB_ENGINE_KEY) { + m_webEngine = m_settings->get(WEB_ENGINE_KEY).toString(); + } + }); + } SearchPluginIface::Actioninfo open { 0, tr("Start browser search")}; m_actionInfo << open; initDetailPage(); @@ -35,14 +52,11 @@ void UkuiSearch::WebSearchPlugin::KeywordSearch(QString keyword, DataQueue UkuiSearch::WebSearchPlugin::getActioninfo(int type) { + Q_UNUSED(type) return m_actionInfo; } void UkuiSearch::WebSearchPlugin::openAction(int actionkey, QString key, int type) { + Q_UNUSED(actionkey) + Q_UNUSED(key) + Q_UNUSED(type) QString address; - QString engine = GlobalSettings::getInstance()->getValue("webEngine").toString(); - if(!engine.isEmpty()) { - if(engine == "360") { + if(!m_webEngine.isEmpty()) { + if(m_webEngine == "360") { address = "https://so.com/s?q=" + m_keyWord; //360 - } else if(engine == "sougou") { + } else if(m_webEngine == "sougou") { address = "https://www.sogou.com/web?query=" + m_keyWord; //搜狗 } else { address = "http://baidu.com/s?word=" + m_keyWord; //百度 @@ -106,6 +123,7 @@ void UkuiSearch::WebSearchPlugin::openAction(int actionkey, QString key, int typ QWidget *UkuiSearch::WebSearchPlugin::detailPage(const UkuiSearch::SearchPluginIface::ResultInfo &ri) { + Q_UNUSED(ri) return m_detailPage; } @@ -118,14 +136,14 @@ void UkuiSearch::WebSearchPlugin::initDetailPage() m_detailLyt->setContentsMargins(8, 0, 16, 0); m_iconLabel = new QLabel(m_detailPage); m_iconLabel->setAlignment(Qt::AlignCenter); - QString type = GlobalSettings::getInstance()->getValue(STYLE_NAME_KEY).toString(); + QString type = GlobalSettings::getInstance().getValue(STYLE_NAME_KEY).toString(); if (type == "ukui-dark") { m_iconLabel->setPixmap(QIcon(":/res/icons/search-web-dark.svg").pixmap(128, 128)); } else { m_iconLabel->setPixmap(QIcon(":/res/icons/search-web-default.svg").pixmap(128, 128)); } connect(qApp, &QApplication::paletteChanged, this, [=] () { - QString type = GlobalSettings::getInstance()->getValue(STYLE_NAME_KEY).toString(); + QString type = GlobalSettings::getInstance().getValue(STYLE_NAME_KEY).toString(); if (type == "ukui-dark") { m_iconLabel->setPixmap(QIcon(":/res/icons/search-web-dark.svg").pixmap(128, 128)); } else { diff --git a/libsearch/websearch/web-search-plugin.h b/libsearch/websearch/web-search-plugin.h index 87d2414..1abdb34 100644 --- a/libsearch/websearch/web-search-plugin.h +++ b/libsearch/websearch/web-search-plugin.h @@ -13,6 +13,8 @@ #include "action-label.h" #include "search-plugin-iface.h" #include +#include +#include "icon-loader.h" namespace UkuiSearch { @@ -25,7 +27,7 @@ public: PluginType pluginType() {return PluginType::SearchPlugin;} const QString name(); const QString description(); - const QIcon icon() {return QIcon::fromTheme("folder");} + const QIcon icon() {return IconLoader::loadIconQt("folder");} void setEnable(bool enable) {m_enable = enable;} bool isEnable() {return m_enable;} QString getPluginName(); @@ -48,6 +50,9 @@ private: QVBoxLayout * m_actionLyt = nullptr; + QGSettings *m_settings = nullptr; + QString m_webEngine; + bool m_enable = true; QList m_actionInfo; diff --git a/libsearch/websearch/websearch.pri b/libsearch/websearch/websearch.pri deleted file mode 100644 index 3a3830b..0000000 --- a/libsearch/websearch/websearch.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/web-search-plugin.h - -SOURCES += \ - $$PWD/web-search-plugin.cpp diff --git a/search-ukcc-plugin/CMakeLists.txt b/search-ukcc-plugin/CMakeLists.txt new file mode 100644 index 0000000..0142303 --- /dev/null +++ b/search-ukcc-plugin/CMakeLists.txt @@ -0,0 +1,45 @@ +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus Widgets LinguistTools REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus Widgets LinguistTools REQUIRED) +find_package(PkgConfig REQUIRED) +set(UKCC_PLUGIN_EXTERNAL_LIBS "") +set(UKCC_PLUGIN_PC_PKGS gsettings-qt kysdk-qtwidgets) + +foreach(PC_LIB IN ITEMS ${UKCC_PLUGIN_PC_PKGS}) + pkg_check_modules(${PC_LIB} REQUIRED ${PC_LIB}) + if(${${PC_LIB}_FOUND}) + include_directories(${${PC_LIB}_INCLUDE_DIRS}) + link_directories(${${PC_LIB}_LIBRARY_DIRS}) + list(APPEND UKCC_PLUGIN_EXTERNAL_LIBS PkgConfig::${PC_LIB}) + endif() +endforeach() + +file(GLOB UKCC_PLUGIN_TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts) +set_source_files_properties(${UKCC_PLUGIN_TS_FILES} PROPERTIES OUTPUT_LOCATION ${CMAKE_BINARY_DIR}/search-ukcc-plugin/.qm) +qt5_create_translation(UKCC_PLUGIN_QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${UKCC_PLUGIN_TS_FILES}) + +add_library(search-ukcc-plugin MODULE + search.cpp search.h + ${UKCC_PLUGIN_QM_FILES} + ) +target_link_libraries(search-ukcc-plugin PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets + gsettings-qt + ukcc + ${UKCC_PLUGIN_PC_PKGS} + ) + +install(TARGETS search-ukcc-plugin + DESTINATION /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/ukui-control-center) +install(FILES + ${UKCC_PLUGIN_TS_FILES} + ${UKCC_PLUGIN_QM_FILES} + DESTINATION /usr/share/ukui-search/search-ukcc-plugin/translations) +file(GLOB IMG_FILES ./image/*) +install(FILES ${IMG_FILES} DESTINATION /usr/share/ukui-search/search-ukcc-plugin/image) diff --git a/search-ukcc-plugin/search-ukcc-plugin.pro b/search-ukcc-plugin/search-ukcc-plugin.pro deleted file mode 100644 index 3c79959..0000000 --- a/search-ukcc-plugin/search-ukcc-plugin.pro +++ /dev/null @@ -1,37 +0,0 @@ -QT += widgets dbus - -TEMPLATE = lib -TARGET = $$qtLibraryTarget(search-ukcc-plugin) -target.path = $$[QT_INSTALL_LIBS]/ukui-control-center/ - -CONFIG += plugin link_pkgconfig c++11 lrelease - -PKGCONFIG += gio-2.0 gio-unix-2.0 gsettings-qt kysdk-qtwidgets - -LIBS += -L$$[QT_INSTALL_LIBS] -lgsettings-qt -LIBS += -lukcc - -DEFINES += QT_DEPRECATED_WARNINGS - -SOURCES += search.cpp - -HEADERS += search.h - -TRANSLATIONS += translations/zh_CN.ts \ - translations/bo_CN.ts \ - translations/en_US.ts - -images.files = image/* -images.path = /usr/share/ukui-search/search-ukcc-plugin/image/ - -qm_files.files = translations/* $$OUT_PWD/.qm/*.qm -qm_files.path = /usr/share/ukui-search/search-ukcc-plugin/translations - - -INSTALLS += target images qm_files - -DISTFILES += \ - ./image/360.svg \ - ./image/baidu.scg \ - ./image/sougou.svg \ - ./image/add.svg diff --git a/search-ukcc-plugin/search.cpp b/search-ukcc-plugin/search.cpp index bcb33bf..fae356e 100644 --- a/search-ukcc-plugin/search.cpp +++ b/search-ukcc-plugin/search.cpp @@ -1,6 +1,32 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #include "search.h" #include #include +#include + +static const QByteArray UKUI_SEARCH_SCHEMAS = QByteArrayLiteral("org.ukui.search.settings"); +static const QString SEARCH_METHOD_KEY = QStringLiteral("fileIndexEnable"); +static const QString WEB_ENGINE_KEY = QStringLiteral("webEngine"); +static const QString CONTENT_FUZZY_SEARCH_KEY = QStringLiteral("contentFuzzySearch"); +static const QString CONTENT_INDEX_ENABLE_KEY = QStringLiteral("contentIndexEnable"); Search::Search() { @@ -29,9 +55,6 @@ Search::Search() QDBusConnection::sessionBus(), this); - m_dirSettings = new QSettings(QDir::homePath() + CONFIG_FILE, QSettings::NativeFormat, this); - m_dirSettings->setIniCodec(QTextCodec::codecForName("UTF-8")); - const QByteArray id(UKUI_SEARCH_SCHEMAS); if (QGSettings::isSchemaInstalled(id)) { m_gsettings = new QGSettings(id, QByteArray(), this); @@ -62,14 +85,21 @@ QWidget *Search::pluginUi() if (m_gsettings) { //按钮状态初始化 if (m_gsettings->keys().contains(SEARCH_METHOD_KEY)) { - //当前是否使用索引搜索/暴力搜索 - bool is_index_search_on = m_gsettings->get(SEARCH_METHOD_KEY).toBool(); - m_searchMethodBtn->setChecked(is_index_search_on); - if (is_index_search_on) { + bool fileIndexOn = m_gsettings->get(SEARCH_METHOD_KEY).toBool(); + m_fileIndexBtn->setChecked(fileIndexOn); + } else { + m_fileIndexBtn->setEnabled(false); + } + + if (m_gsettings->keys().contains(CONTENT_INDEX_ENABLE_KEY)) { + //当前是否开启内容索引 + bool isContentIndexOn= m_gsettings->get(CONTENT_INDEX_ENABLE_KEY).toBool(); + m_contentIndexBtn->setChecked(isContentIndexOn); + if (isContentIndexOn) { m_indexSetFrame->show(); } } else { - m_searchMethodBtn->setEnabled(false); + m_contentIndexBtn->setEnabled(false); } if (m_gsettings->keys().contains(WEB_ENGINE_KEY)) { @@ -80,9 +110,9 @@ QWidget *Search::pluginUi() m_webEngineFrame->mCombox->setEnabled(false); } - if (m_gsettings->keys().contains(CONTENT_SEARCH_KEY)) { + if (m_gsettings->keys().contains(CONTENT_FUZZY_SEARCH_KEY)) { //是否为模糊搜索 - bool isFuzzy = m_gsettings->get(CONTENT_SEARCH_KEY).toBool(); + bool isFuzzy = m_gsettings->get(CONTENT_FUZZY_SEARCH_KEY).toBool(); if (isFuzzy) { m_fuzzyBtn->setChecked(true); } else { @@ -95,11 +125,16 @@ QWidget *Search::pluginUi() //监听gsettings值改变,更新控制面板UI connect(m_gsettings, &QGSettings::changed, this, [ = ](const QString &key) { if (key == SEARCH_METHOD_KEY) { - bool isIndexSearchOn = m_gsettings->get(SEARCH_METHOD_KEY).toBool(); - m_searchMethodBtn->blockSignals(true); - m_searchMethodBtn->setChecked(isIndexSearchOn); - m_searchMethodBtn->blockSignals(false); - if (isIndexSearchOn) { + bool isFileIndexOn = m_gsettings->get(SEARCH_METHOD_KEY).toBool(); + m_fileIndexBtn->blockSignals(true); + m_fileIndexBtn->setChecked(isFileIndexOn); + m_fileIndexBtn->blockSignals(false); + } else if (key == CONTENT_INDEX_ENABLE_KEY) { + bool isContentIndexOn = m_gsettings->get(CONTENT_INDEX_ENABLE_KEY).toBool(); + m_contentIndexBtn->blockSignals(true); + m_contentIndexBtn->setChecked(isContentIndexOn); + m_contentIndexBtn->blockSignals(false); + if (isContentIndexOn) { m_indexSetFrame->show(); } else { m_indexSetFrame->hide(); @@ -109,8 +144,8 @@ QWidget *Search::pluginUi() m_webEngineFrame->mCombox->blockSignals(true); m_webEngineFrame->mCombox->setCurrentIndex(m_webEngineFrame->mCombox->findData(engine)); m_webEngineFrame->mCombox->blockSignals(false); - } else if (key == CONTENT_SEARCH_KEY) { - bool isFuzzy = m_gsettings->get(CONTENT_SEARCH_KEY).toBool(); + } else if (key == CONTENT_FUZZY_SEARCH_KEY) { + bool isFuzzy = m_gsettings->get(CONTENT_FUZZY_SEARCH_KEY).toBool(); if (isFuzzy) { m_fuzzyBtn->setChecked(true); } else { @@ -118,26 +153,32 @@ QWidget *Search::pluginUi() } } }); - connect(m_searchMethodBtn, &kdk::KSwitchButton::stateChanged, this, [ = ](bool checked) { + + connect(m_fileIndexBtn, &kdk::KSwitchButton::stateChanged, this, [ = ](bool checked) { if (m_gsettings && m_gsettings->keys().contains(SEARCH_METHOD_KEY)) { m_gsettings->set(SEARCH_METHOD_KEY, checked); } }); + connect(m_contentIndexBtn, &kdk::KSwitchButton::stateChanged, this, [ = ](bool checked) { + if (m_gsettings && m_gsettings->keys().contains(CONTENT_INDEX_ENABLE_KEY)) { + m_gsettings->set(CONTENT_INDEX_ENABLE_KEY, checked); + } + }); connect(m_indexMethodBtnGroup, QOverload::of(&QButtonGroup::buttonToggled),[ = ](int id, bool checked) { if (id == -3) {//fuzzyBtn's id - if (m_gsettings && m_gsettings->keys().contains(CONTENT_SEARCH_KEY)) { - m_gsettings->set(CONTENT_SEARCH_KEY, checked); + if (m_gsettings && m_gsettings->keys().contains(CONTENT_FUZZY_SEARCH_KEY)) { + m_gsettings->set(CONTENT_FUZZY_SEARCH_KEY, checked); } } }); - connect(m_webEngineFrame->mCombox, QOverload::of(&QComboBox::currentIndexChanged), this, [=](int index) { + connect(m_webEngineFrame->mCombox, QOverload::of(&QComboBox::currentIndexChanged), this, [=] { if (m_gsettings && m_gsettings->keys().contains(WEB_ENGINE_KEY)) { m_gsettings->set(WEB_ENGINE_KEY, m_webEngineFrame->mCombox->currentData().toString()); } }); } else { qCritical() << "Gsettings of the search plugin for ukcc is not initialized!"; - m_searchMethodBtn->setEnabled(false); + m_contentIndexBtn->setEnabled(false); m_webEngineFrame->mCombox->setEnabled(false); } @@ -195,7 +236,31 @@ void Search::initUi() m_webEngineFrame->mCombox->insertItem(2, QIcon("/usr/share/ukui-search/search-ukcc-plugin/image/360.svg"), tr("360"), "360"); m_mainLyt->addWidget(m_webEngineFrame); - //设置索引部分的ui + //设置索引开关 + m_indexTitleLabel = new TitleLabel(m_pluginWidget); + //~ contents_path /Search/Create index + m_indexTitleLabel->setText(tr("Create index")); + m_mainLyt->addSpacing(32); + m_mainLyt->addWidget(m_indexTitleLabel); + + m_fileIndexFrame = new QFrame(m_pluginWidget); + m_fileIndexFrame->setFrameShape(QFrame::Shape::Box); + m_fileIndexFrame->setFixedHeight(64); + m_fileIndexLyt = new QHBoxLayout(m_fileIndexFrame); + m_fileIndexLyt->setContentsMargins(16, 20, 16, 20); + m_fileIndexFrame->setLayout(m_fileIndexLyt); + + m_fileIndexLabel = new QLabel(m_fileIndexFrame); + //~ contents_path /Search/Create file index + m_fileIndexLabel->setText(tr("Create file index")); + m_fileIndexLabel->setContentsMargins(0, 0, 0, 0); + m_fileIndexBtn = new kdk::KSwitchButton(m_fileIndexFrame); + m_fileIndexLyt->addWidget(m_fileIndexLabel); + m_fileIndexLyt->addStretch(); + m_fileIndexLyt->addWidget(m_fileIndexBtn); + m_mainLyt->addWidget(m_fileIndexFrame); + + //设置内容索引部分的ui m_setFrame = new QFrame(m_pluginWidget); m_setFrame->setFrameShape(QFrame::Shape::Box); m_setFrameLyt = new QVBoxLayout(m_setFrame); @@ -203,58 +268,50 @@ void Search::initUi() m_setFrameLyt->setSpacing(0); //索引开关UI - m_searchMethodFrame = new QFrame(m_setFrame); - m_searchMethodFrame->setMinimumWidth(550); - m_searchMethodLyt = new QHBoxLayout(m_searchMethodFrame); - m_searchMethodLyt->setContentsMargins(16, 18, 16, 21); - m_searchMethodFrame->setLayout(m_searchMethodLyt); + m_contentIndexFrame = new QFrame(m_setFrame); + m_contentIndexFrame->setMinimumWidth(550); + m_contentIndexFrame->setFixedHeight(64); + m_contentIndexLyt = new QHBoxLayout(m_contentIndexFrame); + m_contentIndexLyt->setContentsMargins(16, 20, 16, 20); + m_contentIndexFrame->setLayout(m_contentIndexLyt); - m_descFrame = new QFrame(m_searchMethodFrame); - m_descFrameLyt = new QVBoxLayout(m_descFrame); - m_descFrameLyt->setContentsMargins(0, 0, 0, 0); - m_descFrame->setLayout(m_descFrameLyt); - m_descLabel1 = new QLabel(m_descFrame); - m_descLabel2 = new QLabel(m_descFrame); - - //~ contents_path /Search/Create index - m_descLabel1->setText(tr("Create index")); - m_descLabel2->setText(tr("Creating index can help you getting results quickly.")); - m_descLabel2->setEnabled(false); - m_descFrameLyt->addWidget(m_descLabel1); - m_descFrameLyt->addWidget(m_descLabel2); - m_searchMethodBtn = new kdk::KSwitchButton(m_searchMethodFrame); - m_searchMethodLyt->addWidget(m_descFrame); - m_searchMethodLyt->addStretch(); - m_searchMethodLyt->addWidget(m_searchMethodBtn); + m_contentIndexLabel = new QLabel(m_contentIndexFrame); + //~ contents_path /Search/Create file content index + m_contentIndexLabel->setText(tr("Create file content index")); + m_contentIndexLabel->setContentsMargins(0, 0, 0, 0); + m_contentIndexBtn = new kdk::KSwitchButton(m_contentIndexFrame); + m_contentIndexLyt->addWidget(m_contentIndexLabel); + m_contentIndexLyt->addStretch(); + m_contentIndexLyt->addWidget(m_contentIndexBtn); m_indexSetFrame = new QFrame(m_setFrame); + m_indexSetFrame->setFixedHeight(104); m_indexSetLyt = new QVBoxLayout(m_indexSetFrame); - m_indexSetLyt->setContentsMargins(0, 0, 0, 0); + m_indexSetLyt->setContentsMargins(8, 0, 16, 0);//radiobutton本身左边有8间距 m_indexSetLyt->setSpacing(0); //分隔线 QFrame *line = new QFrame(m_indexSetFrame); line->setFixedHeight(1); + line->setContentsMargins(8, 0, 0, 0);// 为了与radiobutton平齐也设置8间距 line->setLineWidth(0); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); //设置索引模式的ui m_indexMethodFrame = new QFrame(m_indexSetFrame); + m_indexMethodFrame->setFixedHeight(103); m_indexMethodLyt = new QVBoxLayout(m_indexMethodFrame); - m_indexMethodLyt->setContentsMargins(8, 16, 0, 0);//radiobutton本身左边有8间距 + m_indexMethodLyt->setContentsMargins(0, 0, 0, 0); m_indexMethodFrame->setLayout(m_indexMethodLyt); - m_indexMethodDescLabel = new QLabel(m_indexMethodFrame); - m_indexMethodDescLabel->setContentsMargins(8, 0, 0, 0); - //~ contents_path /Search/File Content Search - m_indexMethodDescLabel->setText(tr("File Content Search")); - m_preciseBtnFrame = new QFrame(m_indexMethodFrame); + m_preciseBtnFrame->setFixedHeight(50); m_preciseBtnLyt = new QHBoxLayout(m_preciseBtnFrame); m_preciseBtnFrame->setLayout(m_preciseBtnLyt); m_preciseBtn = new QRadioButton(tr("Precise Search"), m_indexMethodFrame); m_preciseDescLabel = new QLabel(m_indexMethodFrame); + m_preciseDescLabel->setContentsMargins(0, 0, 0, 0); m_preciseDescLabel->setText(tr("show the results that exactly match the keyword")); m_preciseDescLabel->setEnabled(false); m_preciseBtnLyt->addWidget(m_preciseBtn); @@ -262,10 +319,12 @@ void Search::initUi() m_preciseBtnLyt->addStretch(); m_fuzzyBtnFrame = new QFrame(m_indexMethodFrame); + m_fuzzyBtnFrame->setFixedHeight(53); m_fuzzyBtnLyt = new QHBoxLayout(m_fuzzyBtnFrame); m_fuzzyBtnFrame->setLayout(m_fuzzyBtnLyt); m_fuzzyBtn = new QRadioButton(tr("Fuzzy Search"), m_indexMethodFrame); m_fuzzyDescLabel = new QLabel(m_indexMethodFrame); + m_fuzzyDescLabel->setContentsMargins(0, 0, 0, 0); m_fuzzyDescLabel->setText(tr("show more results that match the keyword")); m_fuzzyDescLabel->setEnabled(false); m_fuzzyBtnLyt->addWidget(m_fuzzyBtn); @@ -277,14 +336,14 @@ void Search::initUi() m_indexMethodBtnGroup->addButton(m_fuzzyBtn); m_indexMethodBtnGroup->setExclusive(true); - m_indexMethodLyt->addWidget(m_indexMethodDescLabel); m_indexMethodLyt->addWidget(m_preciseBtnFrame); m_indexMethodLyt->addWidget(m_fuzzyBtnFrame); + m_indexMethodLyt->addSpacing(24); m_indexSetLyt->addWidget(line); m_indexSetLyt->addWidget(m_indexMethodFrame); - m_setFrameLyt->addWidget(m_searchMethodFrame); + m_setFrameLyt->addWidget(m_contentIndexFrame); m_setFrameLyt->addWidget(m_indexSetFrame); m_indexSetFrame->hide();//默认隐藏,根据是否开索引来初始化 @@ -345,46 +404,10 @@ void Search::initUi() m_addBlockDirFrame->setFrameShape(QFrame::Shape::NoFrame); m_addBlockDirFrame->setFixedHeight(60); -// m_addBlockDirWidget = new QPushButton(m_addBlockDirFrame); m_addBlockDirWidget = new AddBtn(m_addBlockDirFrame); -// m_addBlockDirWidget->setFixedHeight(60); - -// m_addBlockDirWidget->setObjectName("addBlockDirWidget"); -// QPalette pal; -// QBrush brush = pal.highlight(); //获取window的色值 -// QColor highLightColor = brush.color(); -// QString stringColor = QString("rgba(%1,%2,%3)") //叠加20%白色 -// .arg(highLightColor.red()*0.8 + 255*0.2) -// .arg(highLightColor.green()*0.8 + 255*0.2) -// .arg(highLightColor.blue()*0.8 + 255*0.2); - -// m_addBlockDirWidget->setStyleSheet(QString("HoverWidget#addBlockDirWidget{background: palette(button);\ -// border-radius: 4px;}\ -// HoverWidget:hover:!pressed#addBlockDirWidget{background: %1; \ -// border-radius: 4px;}").arg(stringColor)); - - //之前自己写的添加按钮,目前方案用控制面板提供的AddBtn,后面有变动再放出来(属性全都注掉了,有问题找ukcc寻求帮助) -// m_addBlockDirWidget->setProperty("useButtonPalette", true); -//// m_addBlockDirWidget->setStyleSheet("QPushButton:!checked{background: palette(base);}"); -// m_addBlockDirWidget->setFlat(true); - -// m_addBlockDirIcon = new QLabel(m_addBlockDirWidget); -// m_addBlockDirIcon->setPixmap(QIcon("/usr/share/ukui-search/search-ukcc-plugin/image/add.svg").pixmap(12, 12)); -// m_addBlockDirIcon->setProperty("useIconHighlightEffect", true); -// m_addBlockDirIcon->setProperty("iconHighlightEffectMode", 1); - -// m_addBlockDirLabel = new QLabel(m_addBlockDirWidget); -// m_addBlockDirLabel->setText(tr("Choose folder")); - -// m_addBlockDirLyt = new QHBoxLayout(m_addBlockDirWidget); -// m_addBlockDirWidget->setLayout(m_addBlockDirLyt); m_blockDirsLyt->addWidget(m_addBlockDirWidget); -// m_addBlockDirLyt->addStretch(); -// m_addBlockDirLyt->addWidget(m_addBlockDirIcon); -// m_addBlockDirLyt->addWidget(m_addBlockDirLabel); -// m_addBlockDirLyt->addStretch(); m_mainLyt->addSpacing(32); m_mainLyt->addWidget(m_blockDirTitleLabel); m_mainLyt->addWidget(m_blockDirDescLabel); @@ -426,25 +449,25 @@ void Search::initFileDialog() qDebug() << "Selected a folder in onBtnAddClicked(): " << selectedDir; int returnCode = setBlockDir(selectedDir, true); switch (returnCode) { - case ReturnCode::Succeed : + case ReturnCode::Successful : qDebug() << "Add blocked folder succeed! path = " << selectedDir; getBlockDirs(); break; - case ReturnCode::PathEmpty : - qWarning() << "Add blocked folder failed, choosen path is empty! path = " << selectedDir; - QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add blocked folder failed, choosen path is empty!")); - break; -// case ReturnCode::NotInHomeDir : -// qWarning() << "Add blocked folder failed, it is not in home path! path = " << selectedDir; -// QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add blocked folder failed, it is not in home path!")); -// break; - case ReturnCode::ParentExist : + case ReturnCode::Duplicated : qWarning() << "Add blocked folder failed, its parent dir is exist! path = " << selectedDir; - QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add blocked folder failed, its parent dir is exist!")); + QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add blocked folder failed, its parent dir has been added!")); + break; + case ReturnCode::NotExists : + qWarning() << "Add blocked folder failed, it's not exist! path = " << selectedDir; + QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add blocked folder failed, choosen path is not exist!")); break; case ReturnCode::HasBeenBlocked : qWarning() << "Add blocked folder failed, it has been already blocked! path = " << selectedDir; - QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add blocked folder failed, it has been already blocked!")); + QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add blocked folder failed, it has already been blocked!")); + break; + case ReturnCode::Hidden : + qWarning() << "Add blocked folder failed, it has been hidden! path = " << selectedDir; + QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, hidden path is not supported!")); break; default: break; @@ -469,24 +492,30 @@ void Search::initFileDialog() qDebug() << "Selected a folder in onAddSearchDirBtnClicked(): " << selectedDir; int returnCode = setSearchDir(selectedDir, true); switch (returnCode) { - case 1: + case ReturnCode::Successful: qDebug() << "Add search folder succeed! path = " << selectedDir; break; - case -1: + case ReturnCode::Duplicated: QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path or its parent dir has been added!")); break; - case -2: + case ReturnCode::UnderBlackList: QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is not supported currently!")); break; - case -3: + case ReturnCode::RepeatMount1: QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is in repeat mounted devices and another path which is in the same device has been added!")); break; - case -4: + case ReturnCode::RepeatMount2: QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, another path which is in the same device has been added!")); break; - case -5: + case ReturnCode::NotExists: QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is not exists!")); break; + case ReturnCode::Hidden : + QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, hidden path is not supported!")); + break; + case ReturnCode::PermissionDenied: + QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, permission denied!")); + break; default: break; } @@ -500,9 +529,12 @@ void Search::initFileDialog() */ void Search::getBlockDirs() { - m_blockDirs.clear(); - if (m_dirSettings) - m_blockDirs = m_dirSettings->allKeys(); + if (m_interface->isValid()) { + QDBusReply reply = m_interface->call("blockDirsForUser"); + if (reply.isValid()) { + m_blockDirs = reply.value(); + } + } } /** @@ -513,39 +545,54 @@ void Search::getBlockDirs() */ int Search::setBlockDir(const QString &dirPath, const bool &is_add) { - if (!is_add) { - if (dirPath.isEmpty()) { - return ReturnCode::PathEmpty; - } - //删除黑名单目录 - m_dirSettings->remove(dirPath); + if (!QFile::exists(dirPath)) { removeBlockDirFromList(dirPath); - return ReturnCode::Succeed; + return ReturnCode::NotExists; } -// if (!dirPath.startsWith(QDir::homePath())) { -// return ReturnCode::NotInHomeDir; -// } - QString pathKey = dirPath.right(dirPath.length() - 1); + QStringList pathSections = dirPath.split("/"); + for (const QString §ion : pathSections) { + if (section.startsWith(".")) { + return ReturnCode::Hidden; + } + } + + if (!m_interface->isValid()) { + return ReturnCode::DirWatcherError; + } + + if (!is_add) { + //删除黑名单目录 + m_interface->call("removeBlockDirOfUser", dirPath); + removeBlockDirFromList(dirPath); + return ReturnCode::Successful; + } + + QStringList oldBlockList = m_blockDirs; + getBlockDirs(); + for (const QString& oldBlockDir : oldBlockList) { + if (!m_blockDirs.contains(oldBlockDir)) { + removeBlockDirFromList(oldBlockDir); + } + } for (QString dir : m_blockDirs) { - if (pathKey == dir) { + if (dirPath == dir) { return ReturnCode::HasBeenBlocked; } - if (pathKey.startsWith(dir)) { - return ReturnCode::ParentExist; + if (dirPath.startsWith(dir + "/") || dir == "/") { + return ReturnCode::Duplicated; } //有它的子文件夹已被添加,删除这些子文件夹 - if (dir.startsWith(pathKey)) { - m_dirSettings->remove(dir); - removeBlockDirFromList("/" + dir); + if (dir.startsWith(dirPath + "/") || dirPath == "/") { + removeBlockDirFromList(dir); } } - m_dirSettings->setValue(pathKey, "0"); + m_interface->call("addBlockDirOfUser", dirPath); appendBlockDirToList(dirPath); - return ReturnCode::Succeed; + return ReturnCode::Successful; } /** @@ -555,9 +602,8 @@ void Search::initBlockDirsList() { getBlockDirs(); for (QString path: m_blockDirs) { - QString wholePath = QString("/%1").arg(path); - if (QFileInfo(wholePath).isDir() /*&& path.startsWith("home")*/) { - appendBlockDirToList(wholePath); + if (QFileInfo(path).isDir() /*&& path.startsWith("home")*/) { + appendBlockDirToList(path); } } } @@ -580,23 +626,39 @@ void Search::initSearchDirs() int Search::setSearchDir(const QString &dirPath, const bool isAdd) { + QFileInfo info(dirPath); + if (!(info.isExecutable() && info.isReadable())) { + //路径不存在时从ui上删除 + if (!isAdd) { + this->removeSearchDirFromList(dirPath); + } + return ReturnCode::PermissionDenied; + } + if (!m_setSearchDirInterface->isValid()) { - return 0; + return ReturnCode::DirWatcherError; + } + + QStringList pathSections = dirPath.split("/"); + for (const QString §ion : pathSections) { + if (section.startsWith(".")) { + return ReturnCode::Hidden; + } } if (isAdd) { - QDBusReply indexDirsRpl = m_interface->call("currentIndexableDir"); + QDBusReply indexDirsRpl = m_interface->call("currentSearchDirs"); QStringList indexDirs; if (indexDirsRpl.isValid()) { indexDirs = indexDirsRpl.value(); } - QDBusReply appendIndexRpl = m_setSearchDirInterface->call("appendIndexableListItem", dirPath); + QDBusReply appendIndexRpl = m_setSearchDirInterface->call("appendSearchDir", dirPath); if (appendIndexRpl.isValid()) { - if (appendIndexRpl.value() == 1) { + if (appendIndexRpl.value() == 0) { this->appendSearchDirToList(dirPath); if (!indexDirs.isEmpty()) { - indexDirsRpl = m_interface->call("currentIndexableDir"); + indexDirsRpl = m_interface->call("currentSearchDirs"); if (indexDirsRpl.isValid() && (indexDirsRpl.value().size() < indexDirs.size() + 1)) { QStringList dirsAfterAppend = indexDirsRpl.value(); for (const QString& dir : indexDirs) { @@ -610,16 +672,11 @@ int Search::setSearchDir(const QString &dirPath, const bool isAdd) return appendIndexRpl.value(); } } else { - QDBusReply reply = m_setSearchDirInterface->call("removeIndexableListItem", dirPath); - if (reply.isValid()) { - if (reply.value()) { - this->removeSearchDirFromList(dirPath); - } - return reply.value(); - } + this->removeSearchDirFromList(dirPath); + m_setSearchDirInterface->call("removeSearchDir", dirPath); } - return 0; + return ReturnCode::Successful; } void Search::appendSearchDirToList(const QString &path) diff --git a/search-ukcc-plugin/search.h b/search-ukcc-plugin/search.h index bc54ede..d251e75 100644 --- a/search-ukcc-plugin/search.h +++ b/search-ukcc-plugin/search.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef SEARCH_H #define SEARCH_H @@ -28,19 +47,20 @@ #include #include -#define UKUI_SEARCH_SCHEMAS "org.ukui.search.settings" -#define SEARCH_METHOD_KEY "fileIndexEnable" -#define WEB_ENGINE_KEY "webEngine" -#define CONTENT_SEARCH_KEY "contentFuzzySearch" //TODO #define CONFIG_FILE "/.config/org.ukui/ukui-search/ukui-search-block-dirs.conf" enum ReturnCode { - Succeed, - PathEmpty, - NotInHomeDir, - ParentExist, - HasBeenBlocked + DirWatcherError = -1, + Successful, + Duplicated, + UnderBlackList, + RepeatMount1, + RepeatMount2, + NotExists, + HasBeenBlocked, + Hidden, + PermissionDenied }; class Search : public QObject, CommonInterface @@ -81,18 +101,21 @@ private: ComboxFrame * m_webEngineFrame = nullptr; QVBoxLayout * m_webEngineLyt = nullptr; - //索引详细设置 + //索引开关设置 + TitleLabel *m_indexTitleLabel = nullptr; + QFrame *m_fileIndexFrame = nullptr; + QHBoxLayout *m_fileIndexLyt = nullptr; + QLabel *m_fileIndexLabel = nullptr; + kdk::KSwitchButton *m_fileIndexBtn = nullptr; + + //内容索引开关设置 QFrame *m_setFrame = nullptr; QVBoxLayout *m_setFrameLyt = nullptr; - //索引开关 - QFrame *m_descFrame = nullptr; - QVBoxLayout *m_descFrameLyt = nullptr; - QLabel *m_descLabel1 = nullptr; - QLabel *m_descLabel2 = nullptr; - QFrame *m_searchMethodFrame = nullptr; - QHBoxLayout *m_searchMethodLyt = nullptr; + QLabel *m_contentIndexLabel = nullptr; + QFrame *m_contentIndexFrame = nullptr; + QHBoxLayout *m_contentIndexLyt = nullptr; // QLabel *m_searchMethodLabel = nullptr; - kdk::KSwitchButton *m_searchMethodBtn = nullptr; + kdk::KSwitchButton *m_contentIndexBtn = nullptr; //设置索引搜索模式 QFrame *m_indexSetFrame = nullptr; QVBoxLayout *m_indexSetLyt = nullptr; @@ -137,7 +160,6 @@ private: QFileDialog *m_searchDirDialog = nullptr; QStringList m_blockDirs; - QSettings * m_dirSettings = nullptr; void getBlockDirs(); int setBlockDir(const QString &dirPath, const bool &is_add = true); void appendBlockDirToList(const QString &path); diff --git a/search-ukcc-plugin/search.ui b/search-ukcc-plugin/search.ui deleted file mode 100644 index 0a9f70e..0000000 --- a/search-ukcc-plugin/search.ui +++ /dev/null @@ -1,19 +0,0 @@ - - - Search - - - - 0 - 0 - 784 - 630 - - - - Form - - - - - diff --git a/search-ukcc-plugin/translations/bo_CN.ts b/search-ukcc-plugin/translations/bo_CN.ts index 65199f2..baa4772 100644 --- a/search-ukcc-plugin/translations/bo_CN.ts +++ b/search-ukcc-plugin/translations/bo_CN.ts @@ -4,52 +4,51 @@ Search - - + + Search འཚོལ་ཞིབ། /Search/Search - + Create index གསར་འཛུགས་འཚོལ་ཞིབ་བྱེད་པར་ཁྲིད་སྟོན། /Search/Create index - Creating index can help you getting results quickly. - སྟོན་གྲངས་གསར་སྐྲུན་བྱས་ན་ཁྱོད་ལ་མགྱོགས་མྱུར་ངང་གྲུབ་འབྲས་ཐོབ་པར་རོགས་རམ་བྱེད་ཐུབ། + སྟོན་གྲངས་གསར་སྐྲུན་བྱས་ན་ཁྱོད་ལ་མགྱོགས་མྱུར་ངང་གྲུབ་འབྲས་ཐོབ་པར་རོགས་རམ་བྱེད་ཐུབ། - + Default web searching engine ཁོག་གི་དྲ་ཤོག་གཏོད་པ་བཤེར་འཚོལ་རིགས་དབྱིབས། /Search/Default web searching engine - + baidu པའེ་ཏུའུ། - + sougou སོའོ་གོའུ། - + 360 360 - + Block Folders ལྐོག་བཀོད་མིང་ཐོ། /Search/Block Folders - + Following folders will not be searched. You can set it by adding and removing folders. གཤམ་གྱི་ཡིག་སྣོད་འཚོལ་བཤེར་མི་བྱེད། ཡིག་སྣོད་གསར་སྣོན་དང་གསུབ་འཕྲི་བྱས་ཚེ་ཡིག་ཆའི་དཀར་ཆག་སྒྲིག་འགོད་བྱ་ཐུབ། @@ -58,149 +57,178 @@ བསལ་འདེམས་ཀྱི་དཀར་ཆག། - - + + delete བསུབ་པ། - - + + Directories དཀར་ཆག - File Content Search - + ཡིག་ཆའི་ནང་དོན་བཤེར་འཚོལ། /Search/File Content Search - + show more results that match the keyword - + ངེས་མངོན་པ་དེ་བས་མང་བ་དང་ནང་འདྲེན་བྱེད་པའི་ནང་དོན་གཉིས་དོ་མཉམ་པའི་འཚོལ་ཞིབ་བྱས་པའི་འབྲས་བུ། - + Fuzzy Search - + རབ་རིབ་བཤེར་འཚོལ - + + Create file index + ཡིག་ཆའི་མིང་གི་སྟོན་གྲངས་གསར་སྐྲུན་བྱེད་པ། + /Search/Create file index + + + + Create file content index + ཡིག་ཆའི་ནང་དོན་སྟོན་གྲངས་གསར་སྐྲུན་བྱེད་པ། + /Search/Create file content index + + + Precise Search - + གནད་ལ་འཁེལ་བའི་བཤེར་འཚོལ - + show the results that exactly match the keyword - + ཕྱིར་མངོན་པ་དང་ནང་འཇུག་གི་ནང་དོན་ཡོངས་སུ་མཐུན་པའི་འཚོལ་ཞིབ་ཀྱི་མཇུག་འབྲས - + Search Folders - + བཤེར་འཚོལ་གྱི་ཁྱབ་ཁོངས། /Search/Search Folders - + Following folders will be searched. You can set it by adding and removing folders. - + གཤམ་གྱི་ཡིག་ཆ་འཚོལ་བཤེར་བྱེད་སྲིད།ཁྱོད་ཀྱིས་ཡིག་ཆའི་སྒམ་ནང་འཇུག་དང་མེད་པར་བཟོས་ནས་འཚོལ་བཤེར་གྱི་ཁྱབ་ཁོངས་བཀོད་སྒྲིག་བྱེད་ཆོག - + select blocked folder བཀག་སྡོམ་བྱས་པའི་ཡིག་སྣོད་གདམ་གསེས - - + + Select བདམས་ཐོན་བྱུང་བ། - - + + Position: གོ་གནས་ནི། - - + + FileName: ཡིག་ཆའི་མིང་ནི། - - + + FileType: ཡིག་ཆའི་རིགས་དབྱིབས་ནི། - - + + Cancel ཕྱིར་འཐེན། - - - - - - - - + + + + + + + + + + + Warning ཐ་ཚིག་སྒྲོག་པ། - + + + Add search folder failed, hidden path is not supported! + ཡིག་ཆའི་སྒམ་དེ་མིང་ཐོ་ནག་པོའི་ནང་དུ་འཇོག་མི་རུང་།རྒྱུ་མཚན་ནི་སྦས་ཡོད་པའི་ཡིག་ཆའི་སྒམ་འཇོག་མི་རུང་། + + + + Add search folder failed, permission denied! + ཡིག་ཆའི་སྒམ་དེ་མིང་ཐོ་ནག་པོའི་ནང་དུ་འཇོག་མི་རུང་།རྒྱུ་མཚན་ནི་ལྟ་སྤྱོད་བྱེད་པའི་དབང་ཆ་མེད་པའི་ཡིག་ཆའི་སྒམ་ཁ་སྣོན་བྱེད་མི་ཐུབ། + + Add blocked folder failed, choosen path is empty! - སྦྱོར་རྟ་ལྐོག་བཀོད་མིང་ཐོ་ཕམ་ཁ་བསལ་འདེམས་ཀྱི་ཐབས་ལམ་སྟོང་བ་རེད། + སྦྱོར་རྟ་ལྐོག་བཀོད་མིང་ཐོ་ཕམ་ཁ་བསལ་འདེམས་ཀྱི་ཐབས་ལམ་སྟོང་བ་རེད། Add blocked folder failed, it is not in home path! སྦྱོར་རྟ་ལྐོག་བཀོད་མིང་ཐོ་ཕམ་ཁ་བསལ་འདེམས་ཀྱི་དཀར་ཆག་མི་ཁྱིམ་དཀར་ཆག་འོག། - - Add blocked folder failed, its parent dir is exist! + + Add blocked folder failed, its parent dir has been added! སྦྱོར་རྟ་ལྐོག་བཀོད་མིང་ཐོ་ཕམ་ཁ་བསལ་འདེམས་ཀྱི་དཀར་ཆག་ནི་ལྐོག་བཀོད་མིང་ཐོ་འི་ཁྲོད་ཀྱི་དཀར་ཆག་འོག - - Add blocked folder failed, it has been already blocked! + + Add blocked folder failed, choosen path is not exist! + ཡིག་ཆའི་སྒམ་དེ་མིང་ཐོ་ནག་པོའི་ནང་དུ་འཇོག་མི་རུང་།རྒྱུ་མཚན་ནི་མི་གནས་པའི་ཡིག་ཆའི་སྒམ་འཇོག་མི་རུང་། + + + + Add blocked folder failed, it has already been blocked! སྦྱོར་རྟ་ལྐོག་བཀོད་མིང་ཐོ་ཕམ་ཁ་བསལ་འདེམས་ཀྱི་དཀར་ཆག་ནི་ལྐོག་བཀོད་མིང་ཐོ་འི་ཁྲོད་ཀྱི་དཀར་ཆག་འོག - + select search folder - + འཚོལ་ཞིབ་བྱེད་དགོས་པའི་དཀར་ཆག་འདེམས་དགོས། - + Add search folder failed, choosen path is not supported currently! - + ཡིག་ཆའི་སྒམ་དེ་འཚོལ་བཤེར་གྱི་ཁྱབ་ཁོངས་སུ་འཇོག་མི་རུང་།རྒྱུ་མཚན་ནི་མིག་སྔར་ད་དུང་རྒྱབ་སྐྱོར་མི་བྱེད་པའི་ཡིག་ཆའི་སྒམ་ཁ་སྣོན་བྱེད་མི་རུང་། - + Add search folder failed, another path which is in the same device has been added! - + ཡིག་ཁུག་འཚོལ་བཤེར་ཁྱབ་ཁོངས་སུ་ཁ་སྣོན་བྱེད་མི་ཆོགགང་ལགས་ཤེ་ན།སྒྲིག་ཆས་འོག་གི་ཡིག་ཁུག་ཅིག་ཁ་སྣོན་བྱས་ཡོད་པས་རེད། - + Add search folder failed, choosen path or its parent dir has been added! - + ཡིག་ཆ་འཚོལ་བཤེར་གྱི་ཁྱབ་ཁོངས་སུ་འཇོག་མི་རུང་།རྒྱུ་མཚན་ནི་དེའི་ཨ་ཕའི་ཡིག་ཆ་འཚོལ་བཤེར་གྱི་ཁྱབ་ཁོངས་སུ་ཁ་སྣོན་བྱས་ཡོད། - + Add search folder failed, choosen path is in repeat mounted devices and another path which is in the same device has been added! - + ཡིག་ཆའི་སྒམ་དེ་འཚོལ་བཤེར་གྱི་ཁྱབ་ཁོངས་སུ་འཇོག་མི་རུང་།རྒྱུ་མཚན་ནི་དེ་ནི་བསྐྱར་ཟློས་ཀྱི་སྒྲིག་ཆས་འོག་གི་ཡིག་ཆའི་སྒམ་ཡིན་པར་མ་ཟད།སྒྲིག་ཆས་འདིའི་འོག་གི་ཡིག་ཆའི་སྒམ་ཁ་སྣོན་བྱས་ཡོད། - + Add search folder failed, choosen path is not exists! - + ཡིག་ཆའི་སྒམ་དེ་འཚོལ་བཤེར་གྱི་ཁྱབ་ཁོངས་སུ་འཇོག་མི་རུང་།རྒྱུ་མཚན་ནི་མི་གནས་པའི་ཡིག་ཆའི་སྒམ་ཁ་སྣོན་བྱེད་མི་རུང་། diff --git a/search-ukcc-plugin/translations/en_US.ts b/search-ukcc-plugin/translations/en_US.ts index c85460d..932679e 100644 --- a/search-ukcc-plugin/translations/en_US.ts +++ b/search-ukcc-plugin/translations/en_US.ts @@ -4,193 +4,213 @@ Search - - + + Search Search /Search/Search - + Default web searching engine Default web searching engine /Search/Default web searching engine - + baidu - + sougou - + 360 - + Create index Create index /Search/Create index - - Creating index can help you getting results quickly. - - - - File Content Search - File Content Search + File Content Search /Search/File Content Search - + Precise Search - + show the results that exactly match the keyword - + Fuzzy Search - + show more results that match the keyword - + Search Folders Search Folders /Search/Search Folders - + Following folders will be searched. You can set it by adding and removing folders. - + Block Folders Block Folders /Search/Block Folders - + Following folders will not be searched. You can set it by adding and removing folders. - - + + Directories - + select blocked folder - - + + Select - - + + Position: - - + + FileName: - - + + FileType: - - + + Cancel - - - - - - - - + + + + + + + + + + + Warning - - Add blocked folder failed, choosen path is empty! + + Add blocked folder failed, its parent dir has been added! - - Add blocked folder failed, its parent dir is exist! + + Add blocked folder failed, choosen path is not exist! + Add blocked folder failed, choosen path is not exist! + + + + Add blocked folder failed, it has already been blocked! - - Add blocked folder failed, it has been already blocked! - - - - + select search folder - + Add search folder failed, choosen path or its parent dir has been added! - + Add search folder failed, choosen path is not supported currently! - + Add search folder failed, choosen path is in repeat mounted devices and another path which is in the same device has been added! - + Add search folder failed, another path which is in the same device has been added! - + Add search folder failed, choosen path is not exists! - - + + + Add search folder failed, hidden path is not supported! + Add search folder failed, hidden path is not supported! + + + + Create file index + Create file index + /Search/Create file index + + + + Create file content index + Create file content index + /Search/Create file content index + + + + Add search folder failed, permission denied! + Add search folder failed, permission denied! + + + + delete diff --git a/search-ukcc-plugin/translations/mn.ts b/search-ukcc-plugin/translations/mn.ts new file mode 100644 index 0000000..4bdf4e3 --- /dev/null +++ b/search-ukcc-plugin/translations/mn.ts @@ -0,0 +1,242 @@ + + + + + Search + + + + Search + ᠪᠦᠬᠦ᠌ ᠪᠠᠢᠳᠠᠯ᠎ᠤᠨ ᠬᠠᠢᠯᠳᠠ + /Search/Search + + + + Create index + ᠬᠡᠯᠬᠢᠶᠡᠰᠦ ᠪᠠᠢᠭᠤᠯᠬᠤ + /Search/Create index + + + Creating index can help you getting results quickly. + ᠡᠬᠢᠯᠡᠬᠦᠯᠦᠭᠰᠡᠨ᠎ᠦ ᠳᠠᠷᠠᠭ᠎ᠠ ᠬᠠᠢᠯᠲᠠ᠎ᠶᠢᠨ ᠦᠷ᠎ᠡ ᠳ᠋ᠦᠩ᠎ᠢ ᠬᠤᠷᠳᠤᠨ ᠤᠯᠵᠤ ᠪᠤᠯᠤᠨ᠎ᠠ ᠃ + + + + Default web searching engine + ᠠᠶᠠᠳᠠᠯ ᠢᠨᠲᠸᠷᠨ᠋ᠸᠲ᠎ᠦᠨ ᠡᠷᠢᠯᠳᠡ ᠬᠦᠳᠡᠯᠬᠡᠬᠦᠷ + /Search/Default web searching engine + + + + baidu + ᠪᠠᠢ ᠳ᠋ᠦ᠋ + + + + sougou + ᠰᠸᠤ ᠭᠸᠦ + + + + 360 + 360 + + + + Create file index + ᠪᠢᠴᠢᠭ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠨᠡᠷ᠎ᠡ ᠶᠢᠨ ᠰᠦᠪᠡᠭᠴᠢ ᠶᠢ ᠡᠭᠦᠳᠦᠨ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠶ᠃ + /Search/Create file index + + + + Create file content index + ᠪᠢᠴᠢᠭ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠠᠭᠤᠯᠭ᠎ᠠ ᠶᠢᠨ ᠰᠦᠪᠡᠭᠴᠢ ᠶᠢ ᠡᠭᠦᠳᠦᠨ ᠪᠠᠶᠢᠭᠤᠯᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠶ᠃ + /Search/Create file content index + + + + Block Folders + ᠢᠯᠭᠠᠵᠤ ᠭᠠᠷᠭᠠᠭᠰᠠᠨ ᠴᠤᠮᠤᠭ + /Search/Block Folders + + + + Following folders will not be searched. You can set it by adding and removing folders. + ᠬᠠᠢᠯᠲᠠ᠎ᠪᠠᠷ ᠳᠠᠷᠠᠭᠠᠬᠢ ᠴᠤᠮᠤᠭ᠎ᠢ ᠪᠠᠢᠴᠠᠭᠠᠵᠤ ᠦᠵᠡᠬᠦ᠌ ᠦᠬᠡᠢ ᠂ ᠨᠡᠮᠡᠬᠦ᠌ ᠪᠤᠶᠤ ᠬᠠᠰᠤᠬᠤ᠎ᠪᠠᠷ ᠳᠠᠮᠵᠢᠭᠤᠯᠤᠨ ᠢᠯᠭᠠᠵᠤ ᠭᠠᠷᠭᠠᠭᠰᠠᠨ ᠴᠤᠮᠤᠭ᠎ᠤᠨ ᠪᠠᠢᠷᠢ᠎ᠶᠢ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠵᠤ ᠪᠤᠯᠤᠨ᠎ᠠ ᠃ + + + Choose folder + ᠨᠡᠮᠡᠬᠦ᠌ + + + + + delete + ᠬᠠᠰᠤᠬᠤ + + + + + Directories + ᠴᠤᠮᠤᠭ + + + File Content Search + ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠠᠭᠤᠯᠭ᠎ᠠ ᠡᠷᠢᠬᠦ + /Search/File Content Search + + + + Precise Search + ᠣᠨᠣᠪᠴᠢᠲᠠᠢ ᠡᠷᠢᠬᠦ + + + + show the results that exactly match the keyword + ᠵᠠᠩᠭᠢᠯᠠᠭ᠎ᠠ ᠶᠢᠨ ᠦᠰᠦᠭ ᠲᠡᠢ ᠪᠦᠷᠢᠮᠦᠰᠦᠨ ᠲᠣᠬᠢᠷᠠᠯᠴᠠᠭᠰᠠᠨ ᠦᠷ᠎ᠡ ᠳ᠋ᠦᠩ ᠢ ᠢᠯᠡᠷᠡᠭᠦᠯᠵᠡᠢ + + + + Fuzzy Search + ᠪᠠᠯᠠᠷᠬᠠᠢ ᠡᠷᠢᠬᠦ + + + + show more results that match the keyword + ᠨᠡᠩ ᠠᠷᠪᠢᠨ ᠵᠠᠩᠭᠢᠯᠠᠭ᠎ᠠ ᠶᠢᠨ ᠦᠰᠦᠭ ᠲᠡᠢ ᠲᠣᠬᠢᠷᠠᠯᠴᠠᠭᠰᠠᠨ ᠦᠷ᠎ᠡ ᠳ᠋ᠦᠩ ᠢ ᠢᠯᠡᠷᠡᠭᠦᠯᠵᠡᠢ + + + + Search Folders + ᠡᠷᠢᠬᠦ ᠭᠠᠷᠴᠠᠭ + /Search/Search Folders + + + + Following folders will be searched. You can set it by adding and removing folders. + ᠳᠣᠣᠷᠠᠬᠢ ᠭᠠᠷᠴᠠᠭ ᠢ ᠡᠷᠢᠨ᠎ᠡ ᠃ ᠲᠠ ᠭᠠᠷᠴᠠᠭ ᠢᠶᠠᠷ ᠳᠠᠮᠵᠢᠨ ᠡᠷᠢᠬᠦ ᠬᠡᠪᠴᠢᠶ᠎ᠡ ᠶᠢ ᠵᠢᠭᠠᠨ ᠲᠣᠭᠲᠠᠭᠠᠵᠤ ᠪᠣᠯᠣᠨ᠎ᠠ᠃ + + + + select blocked folder + ᠢᠯᠭᠠᠵᠤ ᠭᠠᠷᠭᠠᠭᠰᠠᠨ ᠴᠤᠮᠤᠭ᠎ᠢ ᠰᠤᠩᠭᠤᠬᠤ + + + + + Select + ᠰᠤᠩᠭᠤᠬᠤ + + + + + Position: + ᠪᠠᠢᠷᠢ ᠄ + + + + + FileName: + ᠹᠠᠢᠯ᠎ᠤᠨ ᠨᠡᠷ᠎ᠡ ᠄ + + + + + FileType: + ᠬᠡᠯᠪᠡᠷᠢ ᠮᠠᠶᠢᠭ + + + + + Cancel + ᠦᠬᠡᠢᠰᠭᠡᠬᠦ᠌ + + + + + + + + + + + + + + Warning + ᠰᠡᠷᠡᠮᠵᠢᠯᠡᠬᠦᠯᠬᠦ᠌ + + + + Add blocked folder failed, its parent dir has been added! + ᠡᠨᠡ ᠭᠠᠷᠴᠠᠭ ᠢ ᠨᠡᠮᠡᠵᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ ᠂ ᠲᠡᠭᠦᠨ ᠦ ᠡᠴᠢᠭᠡ ᠶᠢᠨ ᠭᠠᠷᠴᠠᠭ ᠨᠢᠭᠡᠨᠲᠡ ᠨᠡᠮᠡᠭ᠍ᠳᠡᠵᠡᠢ ! + + + + Add blocked folder failed, choosen path is not exist! + ᠭᠠᠷᠴᠠᠭ ᠨᠡᠮᠡᠵᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ ᠂ ᠡᠨᠡ ᠭᠠᠷᠴᠠᠭ ᠣᠷᠣᠰᠢᠬᠤ ᠦᠭᠡᠢ ! + + + + Add blocked folder failed, it has already been blocked! + ᠭᠠᠷᠴᠠᠭ ᠨᠡᠮᠡᠵᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ ᠂ ᠡᠨᠡ ᠭᠠᠷᠴᠠᠭ ᠨᠢᠭᠡᠨᠲᠡ ᠨᠡᠮᠡᠭ᠍ᠳᠡᠵᠡᠢ ! + + + + + Add search folder failed, hidden path is not supported! + ᠭᠠᠷᠴᠠᠭ ᠨᠡᠮᠡᠬᠦ ᠶᠢᠨ ᠠᠷᠭ᠎ᠠ ᠦᠭᠡᠢ ᠂ ᠨᠢᠭᠤᠴᠠ ᠭᠠᠷᠴᠠᠭ ᠢ ᠳᠡᠮᠵᠢᠬᠦ ᠦᠭᠡᠢ ! + + + + select search folder + ᠡᠷᠢᠬᠦ ᠭᠠᠷᠴᠠᠭ ᠢ ᠰᠣᠩᠭᠣᠨ᠎ᠠ + + + + Add search folder failed, choosen path or its parent dir has been added! + ᠡᠷᠢᠬᠦ ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠢ ᠨᠡᠮᠡᠵᠦ ᠢᠯᠠᠭᠳᠠᠵᠠᠢ ᠂ ᠨᠢᠭᠡᠨᠲᠡ ᠰᠤᠩᠭ᠋ᠤᠬᠤ ᠵᠠᠮ ᠪᠤᠶᠤ ᠲᠡᠭᠦᠨ ᠦ ᠡᠴᠢᠭᠡ ᠶᠢᠨ ᠭᠠᠷᠴᠠᠭ ᠨᠡᠮᠡᠵᠡᠢ ! + + + + Add search folder failed, choosen path is not supported currently! + ᠡᠷᠢᠬᠦ ᠭᠠᠷᠴᠠᠭ ᠢ ᠨᠡᠮᠡᠵᠦ ᠢᠯᠠᠭᠳᠠᠵᠠᠢ ᠂ ᠣᠳᠣᠬᠠᠨ ᠳᠤ ᠡᠨᠡ ᠭᠠᠷᠴᠠᠭ ᠢ ᠳᠡᠮᠵᠢᠬᠦ ᠦᠭᠡᠢ ! + + + + Add search folder failed, choosen path is in repeat mounted devices and another path which is in the same device has been added! + ᠡᠷᠢᠬᠦ ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠢ ᠬᠠᠪᠴᠢᠭᠤᠯᠤᠨ ᠢᠯᠠᠭᠳᠠᠵᠠᠢ ᠂ ᠠᠷᠭ᠎ᠠ ᠵᠠᠮ ᠢ ᠰᠣᠩᠭᠣᠵᠤ ᠳᠠᠬᠢᠨ ᠳᠠᠪᠲᠠᠨ ᠠᠴᠢᠶᠠᠯᠠᠭᠰᠠᠨ ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ ᠳᠦ ᠨᠡᠮᠡᠵᠦ ᠂ ᠨᠢᠭᠡᠨᠲᠡ ᠠᠳᠠᠯᠢ ᠨᠢᠭᠡᠨ ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ ᠳᠣᠲᠣᠷᠠᠬᠢ ᠨᠥᠭᠥᠭᠡ ᠨᠢᠭᠡ ᠠᠷᠭ᠎ᠠ ᠵᠠᠮ ᠨᠡᠮᠡᠵᠡᠢ ! + + + + Add search folder failed, another path which is in the same device has been added! + ᠡᠷᠢᠬᠦ ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠢ ᠨᠡᠮᠡᠵᠦ ᠢᠯᠠᠭᠳᠠᠵᠠᠢ ᠂ ᠨᠢᠭᠡᠨᠲᠡ ᠠᠳᠠᠯᠢ ᠨᠢᠭᠡᠨ ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ ᠳᠣᠲᠣᠷᠠᠬᠢ ᠨᠥᠭᠥᠭᠡ ᠨᠢᠭᠡ ᠠᠷᠭ᠎ᠠ ᠵᠠᠮ ᠢ ᠨᠡᠮᠡᠵᠡᠢ ! + + + + Add search folder failed, choosen path is not exists! + ᠨᠡᠮᠡᠵᠦ ᠡᠷᠢᠬᠦ ᠭᠠᠷᠴᠠᠭ ᠢᠯᠠᠭᠳᠠᠵᠠᠢ ᠂ ᠡᠨᠡ ᠭᠠᠷᠴᠠᠭ ᠣᠷᠣᠰᠢᠬᠤ ᠦᠭᠡᠢ ! + + + + Add search folder failed, permission denied! + ᠡᠷᠢᠬᠦ ᠭᠠᠷᠴᠠᠭ ᠢ ᠨᠡᠮᠡᠵᠦ ᠢᠯᠠᠭᠳᠠᠵᠠᠢ ᠂ ᠡᠨᠡ ᠭᠠᠷᠴᠠᠭ ᠢ ᠰᠤᠷᠪᠤᠯᠵᠢᠯᠠᠬᠤ ᠡᠷᠬᠡ ᠦᠭᠡᠢ ! + + + Add blocked folder failed, choosen path is empty! + ᠨᠡᠮᠡᠯᠳᠡ ᠢᠯᠠᠭᠳᠠᠪᠠ ᠂ ᠰᠤᠩᠭᠤᠭᠰᠠᠨ ᠵᠠᠮ ᠬᠤᠭᠤᠰᠤᠨ ᠪᠠᠢᠨ᠎ᠠ! + + + Add blocked folder failed, it is not in home path! + ᠨᠡᠮᠡᠯᠳᠡ ᠢᠯᠠᠭᠳᠠᠪᠠ ᠂ ᠨᠡᠮᠡᠭᠰᠡᠨ ᠵᠠᠮ ᠲᠤᠰ ᠭᠠᠷᠴᠠᠭ᠎ᠤᠨ ᠳᠤᠤᠷ᠎ᠠ ᠪᠠᠢᠬᠤ ᠦᠬᠡᠢ! + + + Add blocked folder failed, its parent dir is exist! + ᠨᠡᠮᠡᠯᠳᠡ ᠢᠯᠠᠭᠳᠠᠪᠠ ᠂ ᠡᠬᠢ ᠭᠠᠷᠴᠠᠭ᠎ᠢ ᠨᠢᠭᠡᠨᠳᠡ ᠨᠡᠮᠡᠭᠰᠡᠨ ᠪᠠᠢᠨ᠎ᠠ! + + + Add blocked folder failed, it has been already blocked! + ᠨᠡᠮᠡᠯᠳᠡ ᠢᠯᠠᠭᠳᠠᠪᠠ ᠂ ᠡᠨᠡ ᠴᠤᠮᠤᠭ᠎ᠢ ᠨᠢᠭᠡᠨᠳᠡ ᠨᠡᠮᠡᠴᠢᠬᠡᠭᠰᠡᠨ ᠪᠠᠢᠨ᠎ᠠ! + + + diff --git a/search-ukcc-plugin/translations/zh_CN.ts b/search-ukcc-plugin/translations/zh_CN.ts index c8c403c..56a2e2a 100644 --- a/search-ukcc-plugin/translations/zh_CN.ts +++ b/search-ukcc-plugin/translations/zh_CN.ts @@ -4,52 +4,51 @@ Search - - + + Search 全局搜索 /Search/Search - + Create index 创建索引 /Search/Create index - Creating index can help you getting results quickly. - 开启之后可以快速获取搜索结果 + 开启之后可以快速获取搜索结果 - + Default web searching engine 默认互联网搜索引擎 /Search/Default web searching engine - + baidu 百度 - + sougou 搜狗 - + 360 360 - + Block Folders 排除的文件夹 /Search/Block Folders - + Following folders will not be searched. You can set it by adding and removing folders. 搜索将不查看以下文件夹,通过添加和删除可以设置排除的文件夹位置 @@ -58,153 +57,170 @@ 添加 - - + + delete 删除 - - + + Directories 文件夹 - File Content Search - 搜索文本内容 + 搜索文本内容 /Search/File Content Search - precise Search - 精确搜索 - - - + show more results that match the keyword 显示更多与输入内容匹配的搜索结果 - + Fuzzy Search 模糊搜索 - + + Create file index + 文件索引 + /Search/Create file index + + + + Create file content index + 文件内容索引 + /Search/Create file content index + + + Precise Search 精确搜索 - + show the results that exactly match the keyword 仅显示与输入内容完全一致的搜索结果 - + Search Folders 搜索范围 /Search/Search Folders - + Following folders will be searched. You can set it by adding and removing folders. 以下文件的内容将出现在全局搜索的结果中 - + select blocked folder 选择排除的文件夹 - - + + Select 选择 - - + + Position: 位置 - - + + FileName: 文件名 - - + + FileType: 类型 - - + + Cancel 取消 - - - - - - - - + + + + + + + + + + + Warning 警告 - - Add blocked folder failed, choosen path is empty! - 添加失败,选择的路径为空! + + + Add search folder failed, hidden path is not supported! + 添加失败,不支持隐藏目录! - Add blocked folder failed, it is not in home path! - 添加失败,添加的路径不在家目录下! + + Add search folder failed, permission denied! + 添加失败,该目录无权限访问! - - Add blocked folder failed, its parent dir is exist! + + Add blocked folder failed, its parent dir has been added! 添加失败,父目录已被添加! - - Add blocked folder failed, it has been already blocked! + + Add blocked folder failed, choosen path is not exist! + 添加失败,要添加的路径不存在! + + + + Add blocked folder failed, it has already been blocked! 添加失败,这个文件夹已经被添加过了! - + select search folder 选择要搜索的文件夹 - + Add search folder failed, choosen path is not supported currently! - 添加失败!暂不支持该目录! + 添加失败,暂不支持该目录! - + Add search folder failed, another path which is in the same device has been added! - 添加失败!文件夹位于重复挂载设备下,相同内容的文件夹已被添加! + 添加失败,文件夹位于重复挂载设备下,相同内容的文件夹已被添加! - + Add search folder failed, choosen path or its parent dir has been added! - 添加失败!该目录或其父目录已被添加! + 添加失败,该目录或其父目录已被添加! - + Add search folder failed, choosen path is in repeat mounted devices and another path which is in the same device has been added! - 添加失败!文件夹位于重复挂载设备下,且该设备另一个挂载点的文件夹已被添加! + 添加失败,文件夹位于重复挂载设备下,且该设备另一个挂载点的文件夹已被添加! - + Add search folder failed, choosen path is not exists! - 添加失败!要添加的路径不存在! + 添加失败,要添加的路径不存在! diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..0846b57 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.16) +project(tests VERSION 1.0 LANGUAGES C CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) + +add_executable(tests + file-system-watcher-test.cpp file-system-watcher-test.h + main.cpp +) +target_include_directories(tests PRIVATE + ../libsearch ../libsearch + ../libsearch/appsearch + ../libsearch/dirwatcher + ../libsearch/filesystemwatcher + ../libsearch/index + ../libsearch/parser + ../libsearch/plugininterface + ../libsearch/pluginmanage + ../libsearch/searchinterface + ../libsearch/settingsearch +) +target_link_libraries(tests PRIVATE + # Remove: L${CMAKE_CURRENT_BINARY_DIR}/../libsearch/ + Qt${QT_VERSION_MAJOR}::Core + libukui-search +) diff --git a/tests/file-system-watcher-test.cpp b/tests/file-system-watcher-test.cpp index caa943e..a38840e 100644 --- a/tests/file-system-watcher-test.cpp +++ b/tests/file-system-watcher-test.cpp @@ -11,7 +11,7 @@ FileSystemWatcherTest::FileSystemWatcherTest(QObject *parent) : QObject(parent) void FileSystemWatcherTest::beginSignalTest() { - m_watcher->addWatch("/home/zpf/图片/新建文夹"); + m_watcher->addWatch(""); connect(m_watcher, &FileSystemWatcher::attributeChanged, [](const QString& fileUrl) { qDebug() << "AttrbuteChanged:" << fileUrl; }); @@ -30,4 +30,6 @@ void FileSystemWatcherTest::beginSignalTest() connect(m_watcher, &FileSystemWatcher::closedWrite, [](const QString& fileUrl) { qDebug() << "ClosedWrite:" << fileUrl; }); + connect(m_watcher, &FileSystemWatcher::moveTo, + [](const QString& fileUrl) { qDebug() << "moveTo:" << fileUrl; }); } diff --git a/translations/libukui-search/libukui-search_bo_CN.ts b/translations/libukui-search/libukui-search_bo_CN.ts index c7664d0..4edf88e 100644 --- a/translations/libukui-search/libukui-search_bo_CN.ts +++ b/translations/libukui-search/libukui-search_bo_CN.ts @@ -4,12 +4,12 @@ QObject - + Content index incomplete. ནང་དོན་གྱི་སྟོན་གྲངས་ཆ་མི་ཚང་བ། - + Warning, Can not find home path. ཁྱིམ་གྱི་དཀར་ཆག་རྙེད་ཐབས་མེད། @@ -24,42 +24,42 @@ UkuiSearch::AppSearchPlugin - - + + Open སྒོ་ཕྱེ་བ། - - + + Add Shortcut to Desktop ཅོག་ངོས་སུ་མྱུར་འཐེབ་སྣོན་པ། - - + + Add Shortcut to Panel ལས་འགན་གྱི་སྒྲོམ་ཐོག་མགྱོགས་མྱུར་གྱི་བྱེད་ཐབས་གསར་སྣོན་བྱ་དགོས - - + + Install སྒྲིག་སྦྱོར་བྱེད་པ - + Application Description: - ཉེར་སྤྱོད་གོ་རིམ་གྱི་གསལ་བཤད། + ཉེར་སྤྱོད་གོ་རིམ་གྱི་གསལ་བཤད། - - + + Applications Search ཉེར་སྤྱོད་གོ་རིམ་འཚོལ་བཤེར། - + Application ཉེར་སྤྱོད་བྱ་རིམ། @@ -67,62 +67,62 @@ UkuiSearch::AppSearchTask - + Application - ཉེར་སྤྱོད་བྱ་རིམ། + ཉེར་སྤྱོད་བྱ་རིམ། - + Application search. - + ཉེར་སྤྱོད་གོ་རིམ་འཚོལ་བཤེར། UkuiSearch::DirSearchPlugin - - + + Open སྒོ་ཕྱེ་བ། - - + + Open path ཡིག་ཆའི་ཐབས་ལམ་འབྱེད་དགོས། - + Copy Path ཡིག་ཆའི་ལམ་ཐིག་དཔར་བ། - + Dir search. ཡིག་ཆའི་དཀར་ཆག་ལ་ཞིབ་བཤེར་དང་འཚོལ་ཞིབ་ - + Dir Search ཡིག་ཆའི་དཀར་ཆག་ལ་ཞིབ་བཤེར་དང་འཚོལ་ཞིབ་ - + Directory དཀར་ཆག - + Path ལམ་ཐིག - + Last time modified ཐེངས་སྔ་མའི་བཟོ་བཅོས་དུས་ཚོད། - + Copy path ཡིག་ཆའི་ལམ་ཐིག་དཔར་བ། @@ -130,54 +130,54 @@ UkuiSearch::FileContengSearchPlugin - - + + Open སྒོ་ཕྱེ་བ། - - + + Open path ཡིག་ཆའི་ཐབས་ལམ་འབྱེད་དགོས། - + Copy Path ཡིག་ཆའི་ལམ་ཐིག་དཔར་བ། - + File content search. ཡིག་ཆའི་ནང་དོན་འཚོལ་ཞིབ་ - + File content search ཡིག་ཆའི་ནང་དོན་འཚོལ་ཞིབ་ - + OCR OCR - + File ཡིག་ཆ། - + Path ལམ་ཐིག - + Last time modified ཐེངས་སྔ་མའི་བཟོ་བཅོས་དུས་ཚོད། - + Copy path ཡིག་ཆའི་ལམ་ཐིག་དཔར་བ། @@ -185,13 +185,13 @@ UkuiSearch::FileContentSearchTask - - + + File Content ཡིག་ཆའི་ནང་དོན། - + File Content Search ཡིག་ཆའི་ནང་དོན་འཚོལ་ཞིབ་ @@ -199,61 +199,65 @@ UkuiSearch::FileSearchPlugin - - + + Open སྒོ་ཕྱེ་བ། - - + + Open path ཡིག་ཆའི་ཐབས་ལམ་འབྱེད་དགོས། - + Copy Path ཡིག་ཆའི་ལམ་ཐིག་དཔར་བ། - + File search. ཡིག་ཆ་འཚོལ་བཤེར། - + File Search ཡིག་ཆ་འཚོལ་བཤེར། - - - Yes + + + OK རེད། - - + Yes + རེད། + + + + Can not get a default application for opening %1. བཀོལ་སྤྱོད་ཀྱི་གོ་རིམ་མེད་ན་ཁ་ཕྱེ་ཆོག། - + File ཡིག་ཆ། - + Path ལམ་ཐིག - + Last time modified ཐེངས་སྔ་མའི་བཟོ་བཅོས་དུས་ཚོད། - + Copy path ཡིག་ཆའི་ལམ་ཐིག་དཔར་བ། @@ -261,22 +265,22 @@ UkuiSearch::MailSearch - + From དེ་ནས་ཡོང་བ་ཡིན། - + Time དུས་ཚོད། - + To དམིགས་ཡུལ་ས་གནས། - + Cc Cc @@ -284,24 +288,24 @@ UkuiSearch::MailSearchPlugin - + open སྒོ་ཕྱེ་བ། - - - + + + Mail Search སྦྲག་རྫས་འཚོལ་བཤེར། - + Mail སྦྲག་རྫས། - + Open སྒོ་ཕྱེ་བ། @@ -309,7 +313,7 @@ UkuiSearch::NoteSearch - + Note Description: སྟབས་བདེ་བྱང་བུ།ནང་དོན། @@ -317,24 +321,24 @@ UkuiSearch::NoteSearchPlugin - - + + Open སྒོ་ཕྱེ་བ། - + Note Search. སྟབས་བདེ་བྱང་བུ།འཚོལ་ཞིབ་བྱེད་པ། - - + + Note Search སྟབས་བདེ་བྱང་བུ།འཚོལ་ཞིབ་བྱེད་པ། - + Application ཉེར་སྤྱོད་བྱ་རིམ། @@ -353,73 +357,114 @@ - UkuiSearch::SearchTaskPluginManager + UkuiSearch::SearchResultPropertyInfo - - - plugin type: %1, is disabled! - ནུས་པ་སྒོ་བརྒྱབ་ཡོད། + + file path + ཡིག་ཆའི་ཐབས་ལམ། + + + + file name + ཡིག་ཆའི་མིང་། + + + + file icon name + ཡིག་ཆའི་མཚོན་རྟགས་ཀྱི་མིང་། + + + + modified time + བཟོ་བཅོས་བརྒྱབ་པའི་དུས་ཚོད + + + + application desktop file path + ཉེར་སྤྱོད་གོ་རིམ་གྱི་ཅོག་ངོས་ཡིག་ཆའི་ཐབས་ལམ། + + + + application local name + ས་གནས་དེ་གའི་མིང་ + + + + application icon name + ཉེར་སྤྱོད་མཚོན་རྟགས་ཀྱི་མིང་། + + + + application description + ཉེར་སྤྱོད་གོ་རིམ་གྱི་གསལ་བཤད། + + + + is online application + དྲ་རྒྱའི་ཉེར་སྤྱོད་གོ་རིམ་ཡིན + + + + application package name + ཉེར་སྤྱོད་གོ་རིམ་ལྟར་ཐུམ་སྒྲིལ་གྱི་མིང་སྒྲིག་སྦྱོར་བྱས། + + + + UkuiSearch::SearchTaskPluginManager + + plugin type: %1, is disabled! + ནུས་པ་སྒོ་བརྒྱབ་ཡོད། - - plugin type: %1, is not registered! - ནུས་པ་ཐོ་འགོད་བྱས་མེད་པ། + ནུས་པ་ཐོ་འགོད་བྱས་མེད་པ། UkuiSearch::SettingsSearchPlugin - - + + Open སྒོ་ཕྱེ་བ། - + Settings search. སྒྲིག་བཀོད་འཚོལ་བཤེར་བྱ་དགོས། - + Settings Search སྒྲིག་བཀོད་འཚོལ་བཤེར་བྱ་དགོས། - + Settings སྒྲིག་བཀོད། - UkuiSearch::UkuiSearchTaskPrivate + UkuiSearch::UkuiSearchTask - + Current task uuid error or an unregistered plugin is used! - + ᠣᠳᠣᠬᠠᠨ ᠤ ᠡᠭᠦᠷᠭᠡ UUID ᠪᠤᠷᠤᠭᠤ ᠪᠤᠶᠤ ᠳᠠᠩᠰᠠᠯᠠᠭᠤᠯᠤᠭᠰᠠᠨ ᠦᠭᠡᠢ ᠬᠠᠳᠬᠤᠮᠠᠯ ᠬᠡᠷᠡᠭᠰᠡᠯ ᠢ ᠬᠡᠷᠡᠭᠯᠡᠭᠳᠡᠵᠡᠢ ! UkuiSearch::WebSearchPlugin - - + + Start browser search དྲ་ངོས་ནས་འཚོལ་ཞིབ་བྱེད་འགོ་འཛུགས་དགོས། - - + + Web Page དྲ་ངོས། - - search - - - search - - - diff --git a/translations/libukui-search/libukui-search_mn.ts b/translations/libukui-search/libukui-search_mn.ts new file mode 100644 index 0000000..c256749 --- /dev/null +++ b/translations/libukui-search/libukui-search_mn.ts @@ -0,0 +1,497 @@ + + + + + QObject + + + Content index incomplete. + ᠠᠭᠤᠯᠭ᠎ᠠ᠎ᠶᠢᠨ ᠬᠡᠯᠬᠢᠶᠡᠰᠦ ᠪᠦᠷᠢᠨ ᠪᠤᠰᠤ ᠃ + + + + Warning, Can not find home path. + ᠰᠡᠷᠡᠮᠵᠢᠯᠡᠬᠦᠦᠯ ᠂home ᠵᠠᠮ᠎ᠢ ᠤᠯᠵᠤ ᠮᠡᠳᠡᠭᠰᠡᠨ ᠦᠬᠡᠢ᠃ + + + + UkuiSearch::AppMatch + + Application Description: + 应用描述: + + + + UkuiSearch::AppSearch + + Application Description: + ᠬᠡᠷᠡᠭᠯᠡᠯᠳᠡ᠎ᠶᠢᠨ ᠳᠦᠷᠰᠦᠯᠡᠯ ᠄ + + + + UkuiSearch::AppSearchPlugin + + + + Open + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + + Add Shortcut to Desktop + ᠱᠢᠷᠡᠭᠡᠨ ᠨᠢᠭᠤᠷ᠎ᠤᠨ ᠲᠦᠳᠡ ᠴᠦᠷᠬᠡ᠎ᠶᠢᠨ ᠠᠷᠭ᠎ᠠ᠎ᠳᠤ ᠨᠡᠮᠡᠬᠦ᠌ + + + + + Add Shortcut to Panel + ᠡᠬᠦᠷᠭᠡ᠎ᠶᠢᠨ ᠬᠡᠷᠡᠭᠰᠡᠬᠡ᠎ᠶᠢᠨ ᠲᠦᠲᠡ ᠴᠦᠷᠬᠡ᠎ᠳᠦ ᠨᠡᠮᠡᠬᠦ᠌ + + + + + Install + ᠤᠭᠰᠠᠷᠠᠬᠤ + + + + + Applications Search + ᠬᠡᠷᠡᠭᠯᠡᠯᠳᠡ + + + + Application + ᠬᠡᠷᠡᠭᠯᠡᠯᠳᠡ + + + + Application Description: + 应用描述: + + + + UkuiSearch::AppSearchTask + + + Application + ᠬᠡᠷᠡᠭᠯᠡᠯᠳᠡ + + + + Application search. + ᠬᠡᠷᠡᠭᠯᠡᠭᠡᠨ ᠦ ᠡᠷᠢᠯᠲᠡ ᠃ + + + + UkuiSearch::DirSearchPlugin + + + + Open + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + + Open path + ᠹᠠᠢᠯ᠎ᠤᠨ ᠪᠠᠢᠭ᠎ᠠ ᠵᠠᠮ᠎ᠢ ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + Copy Path + ᠵᠠᠮ᠎ᠢ ᠬᠠᠭᠤᠯᠪᠤᠷᠢᠯᠠᠬᠤ + + + + Dir Search + ᠭᠠᠷᠴᠠᠭ + + + + Directory + ᠭᠠᠷᠴᠠᠭ + + + + Dir search. + ᠭᠠᠷᠴᠠᠭ᠎ᠤᠨ ᠬᠠᠢᠯᠲᠠ + + + directory + 目录 + + + + Path + ᠵᠠᠮ + + + + Last time modified + ᠳᠡᠭᠡᠷ᠎ᠡ ᠤᠳᠠᠭ᠎ᠠ᠎ᠶᠢᠨ ᠵᠠᠰᠠᠭᠰᠠᠨ ᠴᠠᠭ + + + + Copy path + ᠵᠠᠮ᠎ᠢ ᠬᠠᠭᠤᠯᠪᠤᠷᠢᠯᠠᠬᠤ + + + + UkuiSearch::FileContengSearchPlugin + + + + Open + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + + Open path + ᠹᠠᠢᠯ᠎ᠤᠨ ᠪᠠᠢᠭ᠎ᠠ ᠵᠠᠮ᠎ᠢ ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + Copy Path + ᠹᠠᠢᠯ᠎ᠤᠨ ᠵᠠᠮ᠎ᠢ ᠬᠠᠭᠤᠯᠪᠤᠷᠢᠯᠠᠬᠤ + + + File Content Search + 文本内容搜索 + + + + File content search. + ᠲᠸᠺᠰᠲ᠎ᠦᠨ ᠠᠭᠤᠯᠭ᠎ᠠ᠎ᠶᠢ ᠬᠠᠢᠬᠤ᠃ + + + + File content search + ᠲᠸᠺᠰᠲ᠎ᠦᠨ ᠠᠭᠤᠯᠭ᠎ᠠ + + + + OCR + OCR + + + + File + ᠹᠠᠢᠯ + + + + Path + ᠵᠠᠮ + + + + Last time modified + ᠳᠡᠭᠡᠷ᠎ᠡ ᠤᠳᠠᠭ᠎ᠠ᠎ᠶᠢᠨ ᠵᠠᠰᠠᠭᠰᠠᠨ ᠴᠠᠭ + + + + Copy path + ᠹᠠᠢᠯ᠎ᠤᠨ ᠵᠠᠮ᠎ᠢ ᠬᠠᠭᠤᠯᠪᠤᠷᠢᠯᠠᠬᠤ + + + + UkuiSearch::FileContentSearchTask + + + + File Content + ᠲᠸᠺᠰᠲ᠎ᠦᠨ ᠠᠭᠤᠯᠭ᠎ᠠ + + + + File Content Search + ᠲᠸᠺᠰᠲ᠎ᠦᠨ ᠠᠭᠤᠯᠭ᠎ᠠ᠎ᠶᠢ ᠬᠠᠢᠬᠤ᠃ + + + + UkuiSearch::FileSearchPlugin + + + + Open + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + + Open path + ᠹᠠᠢᠯ᠎ᠤᠨ ᠪᠠᠢᠭ᠎ᠠ ᠵᠠᠮ᠎ᠢ ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + Copy Path + ᠵᠠᠮ᠎ᠢ ᠬᠠᠭᠤᠯᠪᠤᠷᠢᠯᠠᠬᠤ + + + + File Search + ᠹᠠᠢᠯ + + + + File search. + ᠹᠠᠢᠯ᠎ᠤᠨ ᠬᠠᠢᠯᠲᠠ + + + Yes + Yes + + + + + OK + ᠪᠣᠯᠣᠨ᠎ᠠ + + + + + Can not get a default application for opening %1. + ᠠᠶᠠᠳᠠᠯ ᠨᠡᠬᠡᠬᠡᠬᠦ᠌%1᠎ᠶᠢᠨ ᠬᠡᠷᠡᠭᠯᠡᠯᠳᠡ᠎ᠶᠢ ᠡᠷᠢᠵᠤ ᠤᠯᠤᠭᠰᠠᠨ ᠦᠬᠡᠢ ᠃ + + + + File + ᠹᠠᠢᠯ + + + + Path + ᠵᠠᠮ + + + + Last time modified + ᠳᠡᠭᠡᠷ᠎ᠡ ᠤᠳᠠᠭ᠎ᠠ᠎ᠶᠢᠨ ᠵᠠᠰᠠᠭᠰᠠᠨ ᠴᠠᠭ + + + + Copy path + ᠵᠠᠮ᠎ᠢ ᠬᠠᠭᠤᠯᠪᠤᠷᠢᠯᠠᠬᠤ + + + + UkuiSearch::MailSearch + + + From + ᠢᠮᠸᠯ ᠢᠯᠡᠬᠡᠭᠴᠢ + + + + Time + ᠴᠠᠭ + + + + To + ᠢᠮᠸᠯ ᠬᠤᠷᠢᠶᠠᠭᠴᠢ + + + + Cc + ᠬᠠᠭᠤᠯᠵᠤ ᠬᠦᠷᠬᠡᠭᠴᠢ + + + + UkuiSearch::MailSearchPlugin + + + open + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + + + Mail Search + ᠢᠮᠸᠯ ᠬᠠᠢᠬᠤ + + + + Mail + ᠢᠮᠸᠯ + + + + Open + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + UkuiSearch::NoteSearch + + + Note Description: + 便签内容: + ᠳᠦᠬᠦᠮ ᠱᠤᠱᠢᠭ᠎ᠠ᠎ᠶᠢᠨ ᠠᠭᠤᠯᠭ᠎ᠠ ᠄ + + + + UkuiSearch::NoteSearchPlugin + + + + Open + 打开 + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + + Note Search + 便签 + ᠳᠦᠬᠦᠮ ᠱᠤᠱᠢᠭ᠎ᠠ + + + + Note Search. + 便签. + ᠳᠦᠬᠦᠮ ᠱᠤᠱᠢᠭ᠎ᠠ ᠄ + + + + Application + 应用 + ᠬᠡᠷᠡᠭᠯᠡᠯᠳᠡ + + + + UkuiSearch::SearchManager + + + Path: + ᠵᠠᠮ᠄ + + + + Modified time: + ᠵᠠᠰᠠᠭᠰᠠᠨ ᠴᠠᠭ ᠄ + + + + UkuiSearch::SearchResultPropertyInfo + + + file path + ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠠᠷᠭ᠎ᠠ ᠵᠠᠮ + + + + file name + ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠨᠡᠷ᠎ᠡ + + + + file icon name + ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠵᠢᠷᠤᠭ ᠤᠨ ᠨᠡᠷ᠎ᠡ + + + + modified time + ᠴᠠᠭ ᠢᠶᠠᠨ ᠵᠠᠰᠠᠨ᠎ᠠ + + + + application desktop file path + ᠬᠡᠷᠡᠭᠯᠡᠭᠡᠨ ᠦ ᠫᠷᠦᠭᠷᠠᠮ ᠤᠨ ᠰᠢᠷᠡᠭᠡᠨ ᠦ ᠨᠢᠭᠤᠷ ᠤᠨ ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠠᠷᠭ᠎ᠠ ᠵᠠᠮ + + + + application local name + ᠬᠡᠷᠡᠭᠯᠡᠭᠡᠨ ᠦ ᠫᠷᠦᠭᠷᠠᠮ ᠲᠤᠰ ᠭᠠᠵᠠᠷ ᠤᠨ ᠨᠡᠷᠡᠶᠢᠳᠦᠯ + + + + application icon name + ᠬᠡᠷᠡᠭᠯᠡᠭᠡᠨ ᠦ ᠫᠷᠦᠭᠷᠠᠮ ᠤᠨ ᠵᠢᠷᠤᠭ ᠤᠨ ᠵᠢᠷᠤᠭ ᠤᠨ ᠨᠡᠷᠡᠶᠢᠳᠦᠯ + + + + application description + ᠬᠡᠷᠡᠭᠯᠡᠭᠡᠨ ᠦ ᠲᠣᠳᠣᠷᠬᠠᠶᠢᠯᠠᠯᠲᠠ + + + + is online application + ᠰᠦᠯᠵᠢᠶᠡᠨ ᠳᠡᠭᠡᠷᠡᠬᠢ ᠬᠡᠷᠡᠭᠯᠡᠯᠲᠡ ᠮᠥᠨ + + + + application package name + ᠵᠥᠭᠡᠯᠡᠨ ᠲᠣᠨᠣᠭ ᠤᠨ ᠪᠣᠭᠴᠣ ᠶᠢᠨ ᠨᠡᠷ᠎ᠡ + + + + UkuiSearch::SearchTaskPluginManager + + plugin type: %1, is disabled! + ᠤᠭᠯᠤᠷᠭ᠎ᠠ ᠲᠤᠨᠤᠭ᠎ᠤᠨ ᠬᠡᠯᠪᠡᠷᠢ ᠮᠠᠶᠢᠭ ᠄%1 ᠂ ᠨᠢᠭᠡᠨᠳᠡ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ᠌᠎ᠶᠢ ᠴᠠᠭᠠᠵᠠᠯᠠᠪᠠ! + + + plugin type: %1, is not registered! + ᠤᠭᠯᠤᠷᠭ᠎ᠠ ᠲᠤᠨᠤᠭ᠎ᠤᠨ ᠬᠡᠯᠪᠡᠷᠢ ᠮᠠᠶᠢᠭ ᠄%1 ᠂ ᠪᠦᠷᠢᠳᠭᠡᠬᠦᠯᠦᠬᠡ ᠦᠬᠡᠢ! + + + + UkuiSearch::SettingsSearchPlugin + + + + Open + ᠨᠡᠬᠡᠬᠡᠬᠦ᠌ + + + + Settings Search + ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠤᠯ ᠬᠡᠱᠢᠬᠦᠨ + + + + Settings search. + ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠤᠯ ᠬᠡᠱᠢᠬᠦᠨ᠎ᠦ ᠬᠠᠢᠯᠲᠠ ᠃ + + + + Settings + ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ ᠵᠦᠢᠯ + + + + UkuiSearch::UkuiSearchTask + + + Current task uuid error or an unregistered plugin is used! + ᠲᠤᠰ ᠡᠬᠦᠷᠭᠡuuid ᠨᠢ ᠪᠤᠷᠤᠭᠤ ᠡᠰᠡᠪᠡᠯ ᠨᠢᠭᠡ ᠪᠦᠷᠢᠳᠭᠡᠬᠦᠯᠦᠭᠰᠡᠨ ᠦᠬᠡᠢ ᠤᠭᠯᠤᠷᠭ᠎ᠠ ᠲᠤᠨᠤᠭ ᠬᠡᠷᠡᠭᠯᠡᠭᠳᠡᠭᠰᠡᠨ ᠪᠠᠢᠨ᠎ᠠ! + + + + UkuiSearch::UkuiSearchTaskPrivate + + Current task uuid error or an unregistered plugin is used! + ᠲᠤᠰ ᠡᠬᠦᠷᠭᠡuuid ᠨᠢ ᠪᠤᠷᠤᠭᠤ ᠡᠰᠡᠪᠡᠯ ᠨᠢᠭᠡ ᠪᠦᠷᠢᠳᠭᠡᠬᠦᠯᠦᠭᠰᠡᠨ ᠦᠬᠡᠢ ᠤᠭᠯᠤᠷᠭ᠎ᠠ ᠲᠤᠨᠤᠭ ᠬᠡᠷᠡᠭᠯᠡᠭᠳᠡᠭᠰᠡᠨ ᠪᠠᠢᠨ᠎ᠠ! + + + + UkuiSearch::WebSearchPlugin + + + + Start browser search + ᠬᠠᠢᠭᠤᠷ᠎ᠤᠨ ᠬᠠᠢᠯᠲᠠ᠎ᠶᠢ ᠡᠬᠢᠯᠡᠬᠦᠯᠬᠦ᠌ + + + + + Web Page + ᠰᠦᠯᠵᠢᠶᠡᠨ ᠨᠢᠭᠤᠷ + + + diff --git a/translations/libukui-search/libukui-search_zh_CN.ts b/translations/libukui-search/libukui-search_zh_CN.ts index c7ca100..9d0e957 100644 --- a/translations/libukui-search/libukui-search_zh_CN.ts +++ b/translations/libukui-search/libukui-search_zh_CN.ts @@ -4,14 +4,14 @@ QObject - + Content index incomplete. - + 内容索引未完成。 - + Warning, Can not find home path. - + 警告,找不到家目录。 @@ -31,42 +31,42 @@ UkuiSearch::AppSearchPlugin - - + + Open 打开 - - + + Add Shortcut to Desktop 添加到桌面快捷方式 - - + + Add Shortcut to Panel 添加到任务栏快捷方式 - - + + Install 安装 - - + + Applications Search 应用 - + Application 应用 - + Application Description: 应用描述: @@ -74,12 +74,12 @@ UkuiSearch::AppSearchTask - + Application 应用 - + Application search. 应用搜索 @@ -87,34 +87,34 @@ UkuiSearch::DirSearchPlugin - - + + Open 打开 - - + + Open path 打开文件所在路径 - + Copy Path 复制文件路径 - + Dir Search 目录 - + Directory 目录 - + Dir search. 目录搜索。 @@ -123,17 +123,17 @@ 目录 - + Path 路径 - + Last time modified 上次修改时间 - + Copy path 复制路径 @@ -141,19 +141,19 @@ UkuiSearch::FileContengSearchPlugin - - + + Open 打开 - - + + Open path 打开文件所在路径 - + Copy Path 复制文件路径 @@ -162,37 +162,37 @@ 文本内容搜索 - + File content search. 文本内容搜索。 - + File content search 文本内容 - + OCR OCR - + File 文件 - + Path 路径 - + Last time modified 上次修改时间 - + Copy path 复制路径 @@ -200,13 +200,13 @@ UkuiSearch::FileContentSearchTask - - + + File Content 文本内容 - + File Content Search 文本内容搜索 @@ -214,61 +214,65 @@ UkuiSearch::FileSearchPlugin - - + + Open 打开 - - + + Open path 打开文件所在路径 - + Copy Path 复制文件路径 - + File Search 文件 - + File search. 文件搜索。 - - Yes + 确定 + + + + + OK 确定 - - + + Can not get a default application for opening %1. 没有找到默认打开%1的应用。 - + File 文件 - + Path 路径 - + Last time modified 上次修改时间 - + Copy path 复制路径 @@ -276,22 +280,22 @@ UkuiSearch::MailSearch - + From 发件人 - + Time 时间 - + To 收件人 - + Cc 抄送人 @@ -299,24 +303,24 @@ UkuiSearch::MailSearchPlugin - + open 打开 - - - + + + Mail Search 邮件搜索 - + Mail 邮件 - + Open 打开 @@ -324,7 +328,7 @@ UkuiSearch::NoteSearch - + Note Description: 便签内容: 便签内容: @@ -333,27 +337,27 @@ UkuiSearch::NoteSearchPlugin - - + + Open 打开 打开 - - + + Note Search 便签 便签 - + Note Search. 便签. 便签. - + Application 应用 应用 @@ -373,63 +377,101 @@ - UkuiSearch::SearchTaskPluginManager + UkuiSearch::SearchResultPropertyInfo - - - plugin type: %1, is disabled! - + + file path + 文件路径 - - - plugin type: %1, is not registered! - + + file name + 文件名 + + + + file icon name + 文件图标名 + + + + modified time + 修改时间 + + + + application desktop file path + 应用desktop文件路径 + + + + application local name + 应用本地名 + + + + application icon name + 应用图标名 + + + + application description + 应用描述 + + + + is online application + 是在线应用 + + + + application package name + 应用程序软件包名 UkuiSearch::SettingsSearchPlugin - - + + Open 打开 - + Settings Search 配置项 - + Settings search. 配置项搜索。 - + Settings 设置项 - UkuiSearch::UkuiSearchTaskPrivate + UkuiSearch::UkuiSearchTask - + Current task uuid error or an unregistered plugin is used! - + 当前任务uuid错误或使用了未注册的插件 UkuiSearch::WebSearchPlugin - - + + Start browser search 启动浏览器搜索 - - + + Web Page 网页 @@ -437,10 +479,9 @@ search - search 全局搜索 - 全局搜索 + 全局搜索 diff --git a/translations/ukui-search/appwidget/search_bo_CN.ts b/translations/ukui-search/appwidget/search_bo_CN.ts new file mode 100644 index 0000000..b0ba42a --- /dev/null +++ b/translations/ukui-search/appwidget/search_bo_CN.ts @@ -0,0 +1,112 @@ + + + + + UkuiSearch::BestListWidget + + + Best Matches + + + + + UkuiSearch::CreateIndexAskDialog + + + ukui-search + + + + + Search + + + + + close + + + + + Creating index can help you get results more quickly. Would you like to create one? + + + + + Don't remind + + + + + No + + + + + Yes + + + + + UkuiSearch::MainWindow + + + ukui-search + + + + + Global Search + + + + + UkuiSearch::SearchLineEdit + + + Search + + + + + UkuiSearch::UkuiSearchGui + + + Quit ukui-search application + + + + + Show main window + + + + + unregister a plugin with <pluginName> + + + + + register a plugin with <pluginName> + + + + + move <pluginName> to the target pos + + + + + move plugin to <index> + + + + + search + + + search + འཚོལ་བཤེར། + + + diff --git a/translations/ukui-search/appwidget/search_mn.ts b/translations/ukui-search/appwidget/search_mn.ts new file mode 100644 index 0000000..63cabce --- /dev/null +++ b/translations/ukui-search/appwidget/search_mn.ts @@ -0,0 +1,112 @@ + + + + + UkuiSearch::BestListWidget + + + Best Matches + + + + + UkuiSearch::CreateIndexAskDialog + + + ukui-search + + + + + Search + + + + + close + + + + + Creating index can help you get results more quickly. Would you like to create one? + + + + + Don't remind + + + + + No + + + + + Yes + + + + + UkuiSearch::MainWindow + + + ukui-search + + + + + Global Search + + + + + UkuiSearch::SearchLineEdit + + + Search + + + + + UkuiSearch::UkuiSearchGui + + + Quit ukui-search application + + + + + Show main window + + + + + unregister a plugin with <pluginName> + + + + + register a plugin with <pluginName> + + + + + move <pluginName> to the target pos + + + + + move plugin to <index> + + + + + search + + + search + ᠡᠷᠢᠬᠦ + + + diff --git a/translations/ukui-search/appwidget/search_zh_CN.ts b/translations/ukui-search/appwidget/search_zh_CN.ts new file mode 100644 index 0000000..f26856f --- /dev/null +++ b/translations/ukui-search/appwidget/search_zh_CN.ts @@ -0,0 +1,94 @@ + + + + + UkuiSearch::BestListWidget + + Best Matches + + + + + UkuiSearch::CreateIndexAskDialog + + ukui-search + + + + Search + + + + Don't remind + + + + No + + + + Yes + + + + close + + + + Creating index can help you get results more quickly. Would you like to create one? + + + + + UkuiSearch::MainWindow + + ukui-search + + + + Global Search + + + + + UkuiSearch::SearchLineEdit + + Search + + + + + UkuiSearch::UkuiSearchGui + + Quit ukui-search application + + + + Show main window + + + + unregister a plugin with <pluginName> + + + + register a plugin with <pluginName> + + + + move <pluginName> to the target pos + + + + move plugin to <index> + + + + + search + + search + 全局搜索 + + + diff --git a/translations/ukui-search/bo_CN.ts b/translations/ukui-search/bo_CN.ts index 5de56e1..9bcea0a 100644 --- a/translations/ukui-search/bo_CN.ts +++ b/translations/ukui-search/bo_CN.ts @@ -4,7 +4,7 @@ UkuiSearch::BestListWidget - + Best Matches སྙོམས་སྒྲིག་ལེགས་ཤོས། @@ -12,32 +12,37 @@ UkuiSearch::CreateIndexAskDialog - + ukui-search འཚོལ་བཤེར། - + Search འཚོལ་ཞིབ། - - Creating index can help you getting results quickly, whether to create or not? + + close + སྒོ་རྒྱག་པ། + + + + Creating index can help you get results more quickly. Would you like to create one? དཀར་ཆག་གསར་བཟོ་བྱས་ཚེ་འཚོལ་བྱ་མྱུར་དུ་རྙེད་ཐུབ། གསར་བཟོ་བྱའམ། - + Don't remind ད་ནས་གསལ་བརྡ་མི་གཏོང་བ། - + No མིན། - + Yes རེད། @@ -45,20 +50,19 @@ UkuiSearch::FolderListItem - Delete the folder out of blacklist - མིང་ཐོ་ནག་པོའི་ནང་ནས་ཡིག་སྣོད་བསུབ་པ། + མིང་ཐོ་ནག་པོའི་ནང་ནས་ཡིག་སྣོད་བསུབ་པ། UkuiSearch::MainWindow - + ukui-search འཚོལ་བཤེར། - + Global Search འཚོལ་བཤེར། @@ -66,7 +70,7 @@ UkuiSearch::SearchLineEdit - + Search འཚོལ་ཞིབ། @@ -74,183 +78,176 @@ UkuiSearch::SettingsWidget - ukui-search-settings - འཚོལ་བཤེར། + འཚོལ་བཤེར། - - - Search - འཚོལ་ཞིབ། + འཚོལ་ཞིབ། - <h2>Settings</h2> - <h2> སྒྲིག་འགོད། </h2> + <h2> སྒྲིག་འགོད། </h2> - <h3>Index State</h3> - <h3>དཀར་ཆག་གི་རྣམ་པ།</h3> + <h3>དཀར་ཆག་གི་རྣམ་པ།</h3> - - ... - ... + ... - <h3>File Index Settings</h3> - <h3>ཡིག་ཆའི་དཀར་ཆག་སྒྲིག་འགོད། </h3> + <h3>ཡིག་ཆའི་དཀར་ཆག་སྒྲིག་འགོད། </h3> - Following folders will not be searched. You can set it by adding and removing folders. - གཤམ་གྱི་ཡིག་སྣོད་འཚོལ་བཤེར་མི་བྱེད། ཡིག་སྣོད་གསར་སྣོན་དང་གསུབ་འཕྲི་བྱས་ཚེ་ཡིག་ཆའི་དཀར་ཆག་སྒྲིག་འགོད་བྱ་ཐུབ། + གཤམ་གྱི་ཡིག་སྣོད་འཚོལ་བཤེར་མི་བྱེད། ཡིག་སྣོད་གསར་སྣོན་དང་གསུབ་འཕྲི་བྱས་ཚེ་ཡིག་ཆའི་དཀར་ཆག་སྒྲིག་འགོད་བྱ་ཐུབ། - Add ignored folders - སྣང་མེད་དུ་བཞག་པའི་ཡིག་སྣོད་ཁ་སྣོན་ + སྣང་མེད་དུ་བཞག་པའི་ཡིག་སྣོད་ཁ་སྣོན་ - <h3>Search Engine Settings</h3> - <h3>འཚོལ་བཤེར་ཆས་སྒྲིག་འགོད།</h3> + <h3>འཚོལ་བཤེར་ཆས་སྒྲིག་འགོད།</h3> - Please select search engine you preferred. - ཁྱེད་རང་གིས་དགའ་པོ་བྱེད་པའི་འཚོལ་བཤེར་མ་ལག་འདེམས་ + ཁྱེད་རང་གིས་དགའ་པོ་བྱེད་པའི་འཚོལ་བཤེར་མ་ལག་འདེམས་ - baidu - པའེ་ཏུའུ། + པའེ་ཏུའུ། - sougou - སོའོ་གོའུ། + སོའོ་གོའུ། - 360 - 360 + 360 - Whether to delete this directory? - དཀར་ཆག་འདི་གསུབ་བམ། + དཀར་ཆག་འདི་གསུབ་བམ། - Yes - རེད། + རེད། - No - མིན། + མིན། - Creating ... - དཀར་ཆག་འདྲེན་བཞིན་ཡོད། + དཀར་ཆག་འདྲེན་བཞིན་ཡོད། - Done - བསྒྲུབས་ཚར། + བསྒྲུབས་ཚར། - Index Entry: %1 - གསལ་བྱང་ཚན་པ།: + གསལ་བྱང་ཚན་པ།: - Directories - དཀར་ཆག + དཀར་ཆག - select blocked folder - བཀག་སྡོམ་བྱས་པའི་ཡིག་སྣོད་གདམ་གསེས + བཀག་སྡོམ་བྱས་པའི་ཡིག་སྣོད་གདམ་གསེས - Select - བདམས་ཐོན་བྱུང་བ། + བདམས་ཐོན་བྱུང་བ། - Position: - གོ་གནས་ནི། + གོ་གནས་ནི། - FileName: - ཡིག་ཆའི་མིང་ནི། + ཡིག་ཆའི་མིང་ནི། - FileType: - ཡིག་ཆའི་རིགས་དབྱིབས་ནི། + ཡིག་ཆའི་རིགས་དབྱིབས་ནི། - Cancel - ཕྱིར་འཐེན། + ཕྱིར་འཐེན། - Choosen path is Empty! - བདམས་ཟིན་པའི་ལམ་ཐིག་མི་འདུག + བདམས་ཟིན་པའི་ལམ་ཐིག་མི་འདུག - Choosen path is not in "home"! - ཁྱིམ་གྱི་དཀར་ཆག་ནང་གི་ཡིག་སྣོད་འདེམ་རོགས། + ཁྱིམ་གྱི་དཀར་ཆག་ནང་གི་ཡིག་སྣོད་འདེམ་རོགས། - Its' parent folder has been blocked! - རིམ་པ་གོང་མའི་ཡིག་སྣོད་གབ་ཟིན། + རིམ་པ་གོང་མའི་ཡིག་སྣོད་གབ་ཟིན། - Set blocked folder failed! - བཀག་སྡོམ་བྱས་པའི་ཡིག་སྣོད་ལ་ཕམ་ཉེས་བྱུང་བ་རེད། + བཀག་སྡོམ་བྱས་པའི་ཡིག་སྣོད་ལ་ཕམ་ཉེས་བྱུང་བ་རེད། - OK - འགྲིགས། + འགྲིགས། UkuiSearch::UkuiSearchGui - + Quit ukui-search application ཉེར་སྤྱོད་གོ་རིམ་ལས་ཕྱིར་འཐེན་བྱ། - + Show main window སྒེའུ་ཁུང་གཙོ་བོ་མངོན་པ། + + + unregister a plugin with <pluginName> + + + + + register a plugin with <pluginName> + + + + + move <pluginName> to the target pos + + + + + move plugin to <index> + + UkuiSearch::WebSearchWidget - Web Page - དྲ་ངོས། + དྲ་ངོས། + + + + search + + + search + diff --git a/translations/ukui-search/mn.ts b/translations/ukui-search/mn.ts new file mode 100644 index 0000000..82e2288 --- /dev/null +++ b/translations/ukui-search/mn.ts @@ -0,0 +1,253 @@ + + + + + UkuiSearch::BestListWidget + + + Best Matches + ᠬᠠᠮᠤᠭ᠎ᠤᠨ ᠰᠠᠢᠨ ᠢᠵᠢᠯᠢᠱᠢᠯ + + + + UkuiSearch::CreateIndexAskDialog + + + ukui-search + ᠬᠠᠢᠯᠲᠠ + + + + Search + ᠬᠠᠢᠯᠳᠠ + + + + close + ᠬᠠᠭᠠᠬᠤ + + + + Creating index can help you get results more quickly. Would you like to create one? + ᠬᠡᠯᠬᠢᠶᠡᠰᠦ ᠪᠠᠢᠭᠤᠯᠵᠤ ᠬᠠᠢᠯᠲᠠ᠎ᠶᠢᠨ ᠦᠷ᠎ᠡ ᠳ᠋ᠦᠩ᠎ᠢ ᠬᠤᠷᠳᠤᠨ ᠤᠯᠵᠤ ᠪᠤᠯᠤᠨ᠎ᠠ ᠂ ᠪᠠᠢᠭᠤᠯᠬᠤ ᠤᠤ? + + + + Don't remind + ᠳᠠᠬᠢᠵᠤ ᠰᠠᠨᠠᠭᠤᠯᠬᠤ ᠦᠬᠡᠢ + + + + No + ᠦᠭᠡᠢ + + + + Yes + ᠪᠣᠯᠣᠨ᠎ᠠ + + + + UkuiSearch::FolderListItem + + Delete the folder out of blacklist + ᠬᠠᠰᠤᠬᠤ + + + + UkuiSearch::MainWindow + + + ukui-search + ᠬᠠᠢᠯᠲᠠ + + + + Global Search + ᠬᠠᠢᠯᠲᠠ + + + + UkuiSearch::SearchLineEdit + + + Search + ᠬᠠᠢᠯᠳᠠ + + + + UkuiSearch::SettingsWidget + + ukui-search-settings + ᠬᠠᠢᠯᠲᠠ + + + Search + ᠬᠠᠢᠯᠲᠠ + + + <h2>Settings</h2> + <h2> ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ</h2> + + + <h3>Index State</h3> + <h3> ᠬᠡᠯᠬᠢᠶᠡᠰᠦ᠎ᠶᠢᠨ ᠪᠠᠢᠳᠠᠯ</h3> + + + ... + ... + + + <h3>File Index Settings</h3> + <h3> ᠹᠠᠢᠯ᠎ᠤᠨ ᠬᠡᠯᠬᠢᠶᠡᠰᠦ᠎ᠶᠢ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ</h3> + + + Following folders will not be searched. You can set it by adding and removing folders. + ᠬᠠᠢᠯᠲᠠ᠎ᠪᠠᠷ ᠳᠠᠷᠠᠭᠠᠬᠢ ᠴᠤᠮᠤᠭ᠎ᠢ ᠪᠠᠢᠴᠠᠭᠠᠵᠤ ᠦᠵᠡᠬᠦ᠌ ᠦᠬᠡᠢ ᠂ ᠨᠡᠮᠡᠬᠦ᠌ ᠪᠤᠶᠤ ᠬᠠᠰᠤᠬᠤ᠎ᠪᠠᠷ ᠳᠠᠮᠵᠢᠭᠤᠯᠤᠨ ᠢᠯᠭᠠᠵᠤ ᠭᠠᠷᠭᠠᠭᠰᠠᠨ ᠴᠤᠮᠤᠭ᠎ᠤᠨ ᠪᠠᠢᠷᠢ᠎ᠶᠢ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠵᠤ ᠪᠤᠯᠤᠨ᠎ᠠ ᠃ + + + Add ignored folders + ᠴᠤᠮᠤᠭ᠎ᠢ ᠬᠠᠷ᠎ᠠ ᠳᠠᠩᠰᠠᠨ᠎ᠳᠤ ᠨᠡᠮᠡᠬᠦ᠌ + + + <h3>Search Engine Settings</h3> + <h3>ᠡᠷᠢᠯᠲᠡ ᠬᠦᠳᠡᠯᠬᠡᠬᠦᠷ᠎ᠢ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ</h3> + + + Please select search engine you preferred. + ᠢᠨᠲᠸᠷᠨ᠋ᠸᠲ᠎ᠦᠨ ᠡᠷᠢᠯᠳᠡ ᠬᠦᠳᠡᠯᠬᠡᠬᠦᠷ᠎ᠢ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ + + + baidu + ᠪᠠᠢ ᠳ᠋ᠦ᠋ + + + sougou + ᠰᠸᠤ ᠭᠸᠦ + + + 360 + 360 + + + Whether to delete this directory? + ᠲᠤᠰ ᠭᠠᠷᠴᠠᠭ᠎ᠢ ᠬᠠᠰᠤᠬᠤ ᠤᠤ? + + + Yes + Yes + + + No + No + + + Creating ... + ᠶᠠᠭ ᠬᠡᠯᠬᠢᠶᠡᠰᠦᠯᠡᠵᠤ ᠪᠠᠢᠨ᠎ᠠ ... + + + Done + ᠬᠡᠯᠬᠢᠶᠡᠰᠦᠯᠡᠵᠤ ᠳᠠᠭᠤᠰᠪᠠ + + + Index Entry: %1 + ᠬᠡᠯᠬᠢᠶᠡᠰᠦ᠎ᠶᠢᠨ ᠵᠦᠢᠯ ᠄%1 + + + Directories + ᠴᠤᠮᠤᠭ + + + select blocked folder + ᠬᠠᠯᠬᠠᠯᠠᠭᠰᠠᠨ ᠴᠤᠮᠤᠭ᠎ᠢ ᠰᠤᠩᠭᠤᠬᠤ + + + Select + ᠰᠤᠩᠭᠤᠬᠤ + + + Position: + ᠪᠠᠢᠷᠢ ᠄ + + + FileName: + ᠹᠠᠢᠯ᠎ᠤᠨ ᠨᠡᠷ᠎ᠡ ᠄ + + + FileType: + ᠬᠡᠯᠪᠡᠷᠢ ᠮᠠᠶᠢᠭ ᠄ + + + Cancel + ᠦᠬᠡᠢᠰᠭᠡᠬᠦ᠌ + + + Choosen path is Empty! + ᠰᠤᠩᠭᠤᠭᠰᠠᠨ ᠵᠠᠮ ᠪᠠᠢᠬᠤ ᠦᠬᠡᠢ! + + + Choosen path is not in "home"! + ᠲᠤᠰ ᠭᠠᠷᠴᠠ ᠳᠤᠤᠷᠠᠬᠢ ᠴᠤᠮᠤᠭ᠎ᠢ ᠰᠤᠩᠭᠤᠭᠠᠷᠠᠢ! + + + Its' parent folder has been blocked! + ᠡᠬᠢ ᠴᠤᠮᠤᠭ ᠨᠢᠭᠡᠨᠳᠡ ᠬᠠᠯᠬᠠᠯᠠᠭᠳᠠᠪᠠ! + + + Set blocked folder failed! + ᠬᠠᠱᠢᠭᠳᠠᠭᠰᠠᠨ ᠴᠤᠮᠤᠭ᠎ᠢ ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠵᠤ ᠴᠢᠳᠠᠭᠰᠠᠨ ᠦᠬᠡᠢ! + + + OK + OK + + + + UkuiSearch::UkuiSearchGui + + + Quit ukui-search application + ᠬᠠᠢᠯᠲᠠ᠎ᠶᠢᠨ ᠬᠡᠷᠡᠭᠯᠡᠯᠳᠡ᠎ᠡᠴᠡ ᠪᠤᠴᠠᠵᠤ ᠭᠠᠷᠬᠤ + + + + Show main window + ᠭᠤᠤᠯ ᠨᠢᠭᠤᠷ ᠬᠠᠭᠤᠳᠠᠰᠤ᠎ᠶᠢ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ᠌ + + + + unregister a plugin with <pluginName> + + + + + register a plugin with <pluginName> + + + + + move <pluginName> to the target pos + + + + + move plugin to <index> + + + + + UkuiSearch::WebSearchWidget + + Web Page + ᠰᠦᠯᠵᠢᠶᠡᠨ ᠨᠢᠭᠤᠷ᠎ᠤᠨ ᠬᠠᠢᠯᠲᠠ + + + + search + + + search + ᠬᠠᠢᠯᠲᠠ + + + diff --git a/translations/ukui-search/tr.ts b/translations/ukui-search/tr.ts index 22a8182..2602e94 100644 --- a/translations/ukui-search/tr.ts +++ b/translations/ukui-search/tr.ts @@ -246,7 +246,7 @@ UkuiSearch::BestListWidget - + Best Matches En İyi Eşleşen @@ -297,32 +297,37 @@ UkuiSearch::CreateIndexAskDialog - + ukui-search - + Search Ara - - Creating index can help you getting results quickly, whether to create or not? + + close - + + Creating index can help you get results more quickly. Would you like to create one? + + + + Don't remind - + No - + Yes @@ -330,9 +335,8 @@ UkuiSearch::FolderListItem - Delete the folder out of blacklist - Klasörü kara listeden silin + Klasörü kara listeden silin @@ -353,12 +357,12 @@ UkuiSearch::MainWindow - + ukui-search - + Global Search Genel Arama @@ -419,7 +423,7 @@ UkuiSearch::SearchLineEdit - + Search Ara @@ -427,162 +431,84 @@ UkuiSearch::SettingsWidget - - ukui-search-settings - - - - - - Search - Ara + Ara - <h2>Settings</h2> - <h2>Ayarlar</h2> + <h2>Ayarlar</h2> - <h3>Index State</h3> - <h3>Dizin Durumu</h3> + <h3>Dizin Durumu</h3> - - ... - ... + ... - <h3>File Index Settings</h3> - <h3>Dosya Dizini Ayarları</h3> + <h3>Dosya Dizini Ayarları</h3> - Following folders will not be searched. You can set it by adding and removing folders. - Aşağıdaki klasörler aranmayacaktır. Klasör ekleyip kaldırarak ayarlayabilirsiniz. + Aşağıdaki klasörler aranmayacaktır. Klasör ekleyip kaldırarak ayarlayabilirsiniz. - Add ignored folders - Göz ardı edilen klasörleri ekleyin + Göz ardı edilen klasörleri ekleyin - <h3>Search Engine Settings</h3> - <h3>SArama Motoru Ayarları</h3> + <h3>SArama Motoru Ayarları</h3> - Please select search engine you preferred. - Lütfen tercih ettiğiniz arama motorunu seçin. + Lütfen tercih ettiğiniz arama motorunu seçin. - - baidu - - - - - sougou - - - - - 360 - - - - Whether to delete this directory? - Bu dizini silinsin mi? + Bu dizini silinsin mi? - - Yes - - - - - No - - - - Creating ... - Oluşturuluyor... + Oluşturuluyor... - Done - Tamam + Tamam - Index Entry: %1 - Dizin Girişi: %1 + Dizin Girişi: %1 - Directories - Dizinler + Dizinler - select blocked folder - engellenen klasörü seç + engellenen klasörü seç - Select - Seç + Seç - Position: - Pozisyon: + Pozisyon: - FileName: - Dosya Adı: + Dosya Adı: - FileType: - Dosya Türü: + Dosya Türü: - Cancel - İptal - - - - Choosen path is Empty! - - - - - Choosen path is not in "home"! - - - - - Its' parent folder has been blocked! - - - - - Set blocked folder failed! - - - - - OK - + İptal @@ -615,21 +541,41 @@ UkuiSearch::UkuiSearchGui - + Quit ukui-search application - + Show main window + + + unregister a plugin with <pluginName> + + + + + register a plugin with <pluginName> + + + + + move <pluginName> to the target pos + + + + + move plugin to <index> + + - UkuiSearch::WebSearchWidget + search - - Web Page + + search diff --git a/translations/ukui-search/zh_CN.ts b/translations/ukui-search/zh_CN.ts index 5cfe395..56d4c51 100644 --- a/translations/ukui-search/zh_CN.ts +++ b/translations/ukui-search/zh_CN.ts @@ -4,7 +4,7 @@ UkuiSearch::BestListWidget - + Best Matches 最佳匹配 @@ -59,42 +59,46 @@ UkuiSearch::CreateIndexAskDialog - + ukui-search 搜索 - + Search 搜索 - - Creating index can help you getting results quickly, whether to create or not? + + close + 关闭 + + + + Creating index can help you get results more quickly. Would you like to create one? 创建索引可以快速获取搜索结果,是否创建? - + Don't remind 不再提醒 - + No - 否(N) + 取消 - + Yes - 是(Y) + 确定 UkuiSearch::FolderListItem - Delete the folder out of blacklist - 删除 + 删除 @@ -115,12 +119,12 @@ UkuiSearch::MainWindow - + ukui-search 搜索 - + Global Search 搜索 @@ -193,7 +197,7 @@ UkuiSearch::SearchLineEdit - + Search 搜索 @@ -201,162 +205,120 @@ UkuiSearch::SettingsWidget - ukui-search-settings - 搜索 + 搜索 - - - Search - 搜索 + 搜索 - <h2>Settings</h2> - <h2>设置</h2> + <h2>设置</h2> - <h3>Index State</h3> - <h3>索引状态</h3> + <h3>索引状态</h3> - - - ... - - - - <h3>File Index Settings</h3> - <h3>文件索引设置</h3> + <h3>文件索引设置</h3> - Following folders will not be searched. You can set it by adding and removing folders. - 搜索将不再查看以下文件夹。通过增加和删除文件夹可进行文件索引设置。 + 搜索将不再查看以下文件夹。通过增加和删除文件夹可进行文件索引设置。 - Add ignored folders - 添加文件夹至黑名单 + 添加文件夹至黑名单 - <h3>Search Engine Settings</h3> - <h3>搜索引擎设置</h3> + <h3>搜索引擎设置</h3> - Please select search engine you preferred. - 设置互联网搜索引擎 + 设置互联网搜索引擎 - baidu - 百度 + 百度 - sougou - 搜狗 + 搜狗 - 360 - 360 + 360 - Whether to delete this directory? - 是否要删除此目录? + 是否要删除此目录? - Yes - 是(Y) + 是(Y) - No - 否(N) + 否(N) - Creating ... - 正在索引... + 正在索引... - Done - 索引完成 + 索引完成 - Index Entry: %1 - 索引项: %1 + 索引项: %1 - Directories - 文件夹 + 文件夹 - select blocked folder - 选择屏蔽文件夹 + 选择屏蔽文件夹 - Select - 选择 + 选择 - Position: - 位置: + 位置: - FileName: - 名称: + 名称: - FileType: - 类型: + 类型: - Cancel - 取消 + 取消 - Choosen path is Empty! - 选择的路径不存在! + 选择的路径不存在! - Choosen path is not in "home"! - 请选择家目录下的文件夹! + 请选择家目录下的文件夹! - Its' parent folder has been blocked! - 父文件夹已被屏蔽! + 父文件夹已被屏蔽! - - Set blocked folder failed! - - - - OK - 好的 + 好的 @@ -389,22 +351,49 @@ UkuiSearch::UkuiSearchGui - + Quit ukui-search application 退出搜索应用 - + Show main window 显示主页面 + + + unregister a plugin with <pluginName> + + + + + register a plugin with <pluginName> + + + + + move <pluginName> to the target pos + + + + + move plugin to <index> + + UkuiSearch::WebSearchWidget - Web Page - 网页搜索 + 网页搜索 + + + + search + + + search + diff --git a/ukui-search-app-data-service/CMakeLists.txt b/ukui-search-app-data-service/CMakeLists.txt new file mode 100644 index 0000000..d40c3f9 --- /dev/null +++ b/ukui-search-app-data-service/CMakeLists.txt @@ -0,0 +1,65 @@ +cmake_minimum_required(VERSION 3.14) +project(ukui-search-app-data-service VERSION 1.0.0 LANGUAGES CXX) + +set(VERSION_MAJOR 1) +set(VERSION_MINOR 0) +set(VERSION_MICRO 0) +set(UKUI_SEARCH_APP_DATA_SERVICE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus Gui Widgets Sql Network REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus Gui Widgets Sql Network REQUIRED) +find_package(KF5WindowSystem) +find_package(qt5xdg) + +set(UKUI_SEARCH_APP_DATA_SERVICE_SRC + app-db-manager.cpp app-db-manager.h + main.cpp + pending-app-info.h + pending-app-info-queue.cpp pending-app-info-queue.h + signal-transformer.cpp signal-transformer.h + ukui-search-app-data-service.cpp ukui-search-app-data-service.h) + +if(COMMAND qt_add_dbus_adaptor) + qt_add_dbus_adaptor(UKUI_SEARCH_APP_DATA_SERVICE_SRC dbus/org.ukui.AppDatabase.xml app-db-manager.h UkuiSearch::AppDBManager) +else() + qt5_add_dbus_adaptor(UKUI_SEARCH_APP_DATA_SERVICE_SRC dbus/org.ukui.AppDatabase.xml app-db-manager.h UkuiSearch::AppDBManager) +endif() + +add_executable(ukui-search-app-data-service + ${UKUI_SEARCH_APP_DATA_SERVICE_SRC} +) +target_include_directories(ukui-search-app-data-service PRIVATE + ../3rd-parties/qtsingleapplication/src + ../libchinese-segmentation + ../libsearch + ../libsearch/appdata + ../libsearch/filesystemwatcher +) + +target_compile_definitions(ukui-search-app-data-service PRIVATE + QT_DEPRECATED_WARNINGS + VERSION="${UKUI_SEARCH_APP_DATA_SERVICE_VERSION}" +) + +target_link_libraries(ukui-search-app-data-service PRIVATE + KF5::WindowSystem + Qt5Xdg + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Network + Qt${QT_VERSION_MAJOR}::Sql + chinese-segmentation + libukui-search + qtsingleapplication + ) + +install(TARGETS ukui-search-app-data-service DESTINATION /usr/bin) +install(FILES ../data/ukui-search-app-data-service.desktop DESTINATION /etc/xdg/autostart) +install(FILES conf/com.ukui.search.appdb.service DESTINATION /usr/share/dbus-1/services/) \ No newline at end of file diff --git a/ukui-search-app-data-service/app-db-manager.cpp b/ukui-search-app-data-service/app-db-manager.cpp index 5012410..dbf247c 100644 --- a/ukui-search-app-data-service/app-db-manager.cpp +++ b/ukui-search-app-data-service/app-db-manager.cpp @@ -1,11 +1,30 @@ -#include "app-db-manager.h" -#include "file-utils.h" -#include "convert-winid-to-desktop.h" +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #include #include #include #include +#include +#include "appdatabaseadaptor.h" +#include "file-utils.h" +#include "application-property-helper.h" #define GENERAL_APP_DESKTOP_PATH "/usr/share/applications" #define ANDROID_APP_DESKTOP_PATH QDir::homePath() + "/.local/share/applications" @@ -15,6 +34,7 @@ #define LOCALE_NAME_VALUE "CurrentLocaleName" #define APP_DATABASE_VERSION_CONFIG QDir::homePath() + "/.config/org.ukui/ukui-search/appdata/app-database-version.conf" #define APP_DATABASE_VERSION_VALUE "AppDatabaseVersion" +static const QString AUTOSTART_APP_DESKTOP_PATH = "/etc/xdg/autostart"; using namespace UkuiSearch; static AppDBManager *global_instance; @@ -32,6 +52,9 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa { //链接数据库 if (openDataBase()) { + //建数据库 + buildAppInfoDB(); + //监听系统语言变化 m_lastLocaleNameQsettings = new QSettings(LAST_LOCALE_NAME, QSettings::IniFormat); m_localeChanged = false; @@ -52,7 +75,7 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa QString dbVersion = m_dbVersionQsettings->value(APP_DATABASE_VERSION_VALUE).toString(); if (dbVersion.isEmpty()) { m_dbVersionNeedUpdate = true; - }else if (dbVersion != APP_DATABASE_VERSION) { + } else if (dbVersion != APP_DATABASE_VERSION) { if (dbVersion.toDouble() < APP_DATABASE_VERSION.toDouble()) { m_dbVersionNeedUpdate = true; } else { @@ -65,8 +88,18 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa qDebug() << "app db version need update! old version:" << dbVersion.toDouble() << "new version:" << APP_DATABASE_VERSION.toDouble(); } - //初始化数据库 - refreshAllData2DB(); + //版本号改变更新数据库字段 + if (m_dbVersionNeedUpdate) { + for (auto iter = m_namesOfAppinfoTable.constBegin(); iter!= m_namesOfAppinfoTable.constEnd(); iter++) { + this->addItem2BackIfNotExist(iter.key(), iter.value()); + } + } + + //刷新应用数据 + QStringList appPaths; + appPaths << GENERAL_APP_DESKTOP_PATH << ANDROID_APP_DESKTOP_PATH + << SNAPD_APP_DESKTOP_PATH << AUTOSTART_APP_DESKTOP_PATH; + refreshAllData2DB(appPaths, m_dbVersionNeedUpdate); if (m_dbVersionNeedUpdate) { m_dbVersionQsettings->beginGroup(APP_DATABASE_VERSION_VALUE); @@ -76,97 +109,7 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa } //初始化FileSystemWatcher - m_watcher = new FileSystemWatcher; - m_watcher->addWatch(GENERAL_APP_DESKTOP_PATH); - QDir androidDir(ANDROID_APP_DESKTOP_PATH); - if(!androidDir.exists()) { - androidDir.mkpath(ANDROID_APP_DESKTOP_PATH); - } - m_watcher->addWatch(ANDROID_APP_DESKTOP_PATH); - - m_snapdDir = new QDir(SNAPD_APP_DESKTOP_PATH); - if(!m_snapdDir->exists()) { - m_snapdWatcher = new FileSystemWatcher(false); - QDir dir("/var/lib/snapd"); - if (!dir.exists()) { - dir.setPath("/var/lib"); - } - m_snapdPath = dir.absolutePath(); - m_snapdWatcher->addWatch(m_snapdPath); - } else { - m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); - } - - connect(m_snapdWatcher, &FileSystemWatcher::created, this, [ = ] (const QString &path, bool isDir) { - if (isDir) { - //监测新增目录为/var/lib/snapd时,将其替换为snapdWatcher的watchpath - if (path == "/var/lib/snapd") { - m_snapdWatcher->removeWatch(m_snapdPath); - m_snapdWatcher->addWatch(path); - qDebug() << "~~~~~~~add watch" << path << "~~~~~remove watch" << m_snapdPath; - m_snapdPath = path; - //snapd下的desktop目录可能在还没替换监听目录为/var/lib/snapd时就已经被创建,因此需要特别判断 - QDir dir("/var/lib/snapd/desktop"); - if (dir.exists()) { - if (m_snapdDir->exists()) { - m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); - m_snapdWatcher->removeWatch(m_snapdPath); - qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; - } - } - } - //检测到/var/lib/snapd/desktop被创建,则将监听目录替换为/var/lib/snapd/desktop/applications - if (path == "/var/lib/snapd/desktop" and m_snapdDir->exists()) { - m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); - m_snapdWatcher->removeWatch(m_snapdPath); - qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; - } - - } - }); - - connect(m_watcher, &FileSystemWatcher::created, this, [ = ] (const QString &desktopfp, bool isDir) { - //event is IN_CREATE or IN_MOVED_TO - if (!isDir and desktopfp.endsWith(".desktop")) { - this->insertDBItem(desktopfp); - } - }); - - connect(m_watcher, &FileSystemWatcher::modified, this, [ = ] (const QString &desktopfp) { - //event is IN_MODIFY - if (desktopfp.endsWith(".desktop")) { - this->updateDBItem(desktopfp); - } - }); - - connect(m_watcher, &FileSystemWatcher::moved, this, [ = ] (const QString &desktopfp, bool isDir) { - //event is IN_MOVED_FROM - if (!isDir) { - if (desktopfp.endsWith(".desktop")) { - this->deleteDBItem(desktopfp); - } - } else { - //event is IN_MOVE_SELF - qWarning() << "Dir:" << desktopfp << "has been moved to other place! Stop the watching of the desktop files in it!"; - } - }); - - connect(m_watcher, &FileSystemWatcher::deleted, this, [ = ] (const QString &desktopfp, bool isDir) { - //event is IN_DELETE - if (!isDir) { - if (desktopfp.endsWith(".desktop")) { - this->deleteDBItem(desktopfp); - } - } else { - //event is IN_DELETE_SELF - qWarning() << "Dir:" << desktopfp << "has been deleted! Stop the watching of the desktop files in it!"; - } - }); - - connect(m_watcher, &FileSystemWatcher::unmounted, this, [ = ] (const QString &desktopfp) { - //event is IN_UNMOUNT - qWarning() << "Dir:" << desktopfp << "has been unmounted! Stop the watching of the desktop files in it!"; - }); + initFileSystemWatcher(); /* //初始化FileSystemWatcher @@ -227,11 +170,13 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa //监控应用进程开启 connect(KWindowSystem::self(), &KWindowSystem::windowAdded, [ = ](WId id) { - QString desktopfp = ConvertWinidToDesktop::getConverter().tranIdToDesktop(id); - if (!desktopfp.isEmpty()) { - this->updateLaunchTimes(desktopfp); + QDBusVariant dbusVariant(id); + QString desktopFilePath = this->tranWinIdToDesktopFilePath(dbusVariant); + if (!desktopFilePath.isEmpty()) { + this->updateLaunchTimes(desktopFilePath); } }); + new AppDBManagerAdaptor(this); } else { qDebug() << "App-db-manager does nothing."; } @@ -260,9 +205,9 @@ void AppDBManager::buildAppInfoDB() { qDebug() << "I'm going to build app info database."; QSqlQuery sql(m_database); - QString cmd = QString("CREATE TABLE IF NOT EXISTS appInfo(%1, %2, %3, %4, %5, %6, %7, %8,%9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21)") + QString cmd = QString("CREATE TABLE IF NOT EXISTS appInfo(%1, %2, %3, %4, %5, %6, %7, %8,%9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22)") // .arg("ID INT")//自增id - .arg("DESKTOP_FILE_PATH TEXT")//desktop文件路径 + .arg("DESKTOP_FILE_PATH TEXT PRIMARY KEY NOT NULL")//desktop文件路径 .arg("MODIFYED_TIME TEXT")//YYYYMMDDHHmmSS 修改日期 .arg("INSERT_TIME TEXT")//YYYYMMDDHHmmSS 插入日期 .arg("LOCAL_NAME TEXT")//本地名称,跟随系统语言 @@ -270,7 +215,7 @@ void AppDBManager::buildAppInfoDB() .arg("NAME_ZH TEXT")//应用中文名称 .arg("PINYIN_NAME TEXT")//中文拼音 .arg("FIRST_LETTER_OF_PINYIN TEXT")//中文拼音首字母 - .arg("FIRST_LETTER_ALL")//拼音和英文全拼 + .arg("FIRST_LETTER_ALL TEXT")//拼音和英文全拼 .arg("ICON TEXT")//图标名称(或路径) .arg("TYPE TEXT")//应用类型 .arg("CATEGORY TEXT")//应用分类 @@ -282,93 +227,112 @@ void AppDBManager::buildAppInfoDB() .arg("LAUNCHED INT")//应用安装后是否打开过0:未打开过;1:打开过 .arg("TOP INT")//置顶顺序 0:未置顶;>0的数字表示置顶顺序 .arg("LOCK INT")//应用是否锁定(管控),0未锁定,1锁定 - .arg("PRIMARY KEY (DESKTOP_FILE_PATH)"); - + .arg("DONT_DISPLAY INT")//应用隐藏(NoDisplay, NotShowIn) + .arg("AUTO_START INT");//自启应用 if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; return; } } -void AppDBManager::updateAppInfoDB() +void AppDBManager::initFileSystemWatcher() { - -} - -void AppDBManager::getFilePathList(QStringList &pathList) -{ -// for (auto i=m_installAppMap.begin(); i!=m_installAppMap.end(); ++i) { -// pathList.append(i.value().at(0)); -// } -} - -/** - * @brief AppMatch::getAllDesktopFilePath 遍历所有desktop文件 - * @param path 存放desktop文件夹 - */ -void AppDBManager::getAllDesktopFilePath(QString path) -{ - /* - QDir dir(path); - if(!dir.exists()) { - return; + m_watcher = new FileSystemWatcher; + m_watcher->addWatch(GENERAL_APP_DESKTOP_PATH); + QDir androidDir(ANDROID_APP_DESKTOP_PATH); + if(!androidDir.exists()) { + androidDir.mkpath(ANDROID_APP_DESKTOP_PATH); } - dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); - dir.setSorting(QDir::DirsFirst); - QFileInfoList list = dir.entryInfoList(); - list.removeAll(QFileInfo("/usr/share/applications/screensavers")); - if(list.size() < 1) { - return; - } - XdgDesktopFile desktopfile; - int i = 0; - while(i < list.size()) { - QFileInfo fileInfo = list.at(i); - //如果是文件夹,递归 - bool isDir = fileInfo.isDir(); - if(isDir) { - getAllDesktopFilePath(fileInfo.filePath()); - qDebug() << fileInfo.filePath(); - ++i; - } else { - QString filePathStr = fileInfo.filePath(); - if(m_excludedDesktopfiles.contains(filePathStr)) { - ++i; - continue; - } + m_watcher->addWatch(ANDROID_APP_DESKTOP_PATH); - //过滤后缀不是.desktop的文件 - if(!filePathStr.endsWith(".desktop")) { - ++i; - continue; - } - - desktopfile.load(filePathStr); - if(desktopfile.value("NoDisplay").toString().contains("true") || desktopfile.value("NotShowIn").toString().contains("UKUI")) { - ++i; - continue; - } - - QString name = desktopfile.localizedValue("Name").toString(); - if(name.isEmpty()) { - ++i; - qDebug() << filePathStr << "name!!"; - continue; - } - - QString icon = desktopfile.iconName(); - NameString appname; - QStringList appInfolist; - - appname.app_name = name; - appInfolist << filePathStr << icon; - appInfolist.append(desktopfile.value("Name").toString()); - appInfolist.append(desktopfile.value("Name[zh_CN]").toString()); - m_installAppMap.insert(appname, appInfolist); - ++i; + m_snapdDir = new QDir(SNAPD_APP_DESKTOP_PATH); + if(!m_snapdDir->exists()) { + m_snapdWatcher = new FileSystemWatcher(false); + QDir dir("/var/lib/snapd"); + if (!dir.exists()) { + dir.setPath("/var/lib"); } + m_snapdPath = dir.absolutePath(); + m_snapdWatcher->addWatch(m_snapdPath); + } else { + m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); } - */ + + m_watcher->addWatch(AUTOSTART_APP_DESKTOP_PATH); + + connect(m_snapdWatcher, &FileSystemWatcher::created, this, [ = ] (const QString &path, bool isDir) { + if (isDir) { + //监测新增目录为/var/lib/snapd时,将其替换为snapdWatcher的watchpath + if (path == "/var/lib/snapd") { + m_snapdWatcher->removeWatch(m_snapdPath); + m_snapdWatcher->addWatch(path); + qDebug() << "~~~~~~~add watch" << path << "~~~~~remove watch" << m_snapdPath; + m_snapdPath = path; + //snapd下的desktop目录可能在还没替换监听目录为/var/lib/snapd时就已经被创建,因此需要特别判断 + QDir dir("/var/lib/snapd/desktop"); + if (dir.exists()) { + if (m_snapdDir->exists()) { + m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); + m_snapdWatcher->removeWatch(m_snapdPath); + qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; + } + } + } + //检测到/var/lib/snapd/desktop被创建,则将监听目录替换为/var/lib/snapd/desktop/applications + if (path == "/var/lib/snapd/desktop" and m_snapdDir->exists()) { + m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); + m_snapdWatcher->removeWatch(m_snapdPath); + qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; + } + + } + }); + + connect(m_watcher, &FileSystemWatcher::created, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_CREATE + if (!isDir and desktopfp.endsWith(".desktop")) { + this->insertDBItem(desktopfp); + } + }); + + connect(m_watcher, &FileSystemWatcher::moveTo, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_MOVED_TO + if (!isDir and desktopfp.endsWith(".desktop")) { + QStringList appPaths(desktopfp.left(desktopfp.lastIndexOf("/"))); + this->refreshAllData2DB(appPaths); + } + }); + + connect(m_watcher, &FileSystemWatcher::modified, this, [ = ] (const QString &desktopfp) { + //event is IN_MODIFY + if (desktopfp.endsWith(".desktop")) { + this->updateDBItem(desktopfp); + } + }); + + connect(m_watcher, &FileSystemWatcher::moved, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_MOVED_FROM + if (!isDir) { + if (desktopfp.endsWith(".desktop")) { + this->deleteDBItem(desktopfp); + } + } else { + //event is IN_MOVE_SELF + qWarning() << "Dir:" << desktopfp << "has been moved to other place! Stop the watching of the desktop files in it!"; + } + }); + + connect(m_watcher, &FileSystemWatcher::deleted, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_DELETE + if (!isDir) { + if (desktopfp.endsWith(".desktop")) { + this->deleteDBItem(desktopfp); + } + } else { + //event is IN_DELETE_SELF + qWarning() << "Dir:" << desktopfp << "has been deleted! Stop the watching of the desktop files in it!"; + } + }); } void AppDBManager::loadDesktopFilePaths(QString path, QFileInfoList &infolist) @@ -383,19 +347,20 @@ bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType { bool res(true); QSqlQuery sql(m_database); - QString cmd = QString("SELECT * FROM sqlite_master WHERE name = 'appInfo' AND sql like '% %1 %' ").arg(itemName); + sql.setForwardOnly(true); + QString cmd = QString("SELECT * FROM sqlite_master WHERE name = 'appInfo' AND sql like '%%1%' ").arg(itemName); if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; res = false; return res; } if (sql.next()) { - qDebug() << cmd << "is exist!"; + qDebug() << itemName << "is exist!"; return res; } - cmd = QString("ALTER TABLE appInfo ADD '%0' '%1' ").arg(itemName) - .arg(itemDataType); + cmd = QString("ALTER TABLE appInfo ADD '%0' %1 ").arg(itemName) + .arg(itemDataType); if (defult != QVariant()) { //TODO 根据数据类型将初始值转化为对应格式数据 if (itemDataType == "INT(4)") { @@ -407,6 +372,8 @@ bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; res = false; + } else { + qDebug() << "Add item" << itemName << "successful."; } if (!res) { qDebug() << "Fail to addItem2Back :" << itemName; @@ -414,98 +381,20 @@ bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType return res; } -void AppDBManager::refreshAllData2DB() +void AppDBManager::refreshAllData2DB(const QStringList &appPaths, bool dbVersionNeedUpdate) { - bool firstExec = false; - QSqlQuery sql(m_database); - QString cmd = "SELECT DESKTOP_FILE_PATH,MD5 FROM APPINFO"; - QMap dataMap; - if (!sql.exec(cmd)) { - qDebug() << "Fail to read database, because: " << m_database.lastError(); - this->buildAppInfoDB(); - firstExec = true; - } else { - sql.exec(cmd); - while (sql.next()) { - dataMap.insert(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("MD5").toString()); - } - } - - //遍历desktop文件 - QFileInfoList infos; - this->loadDesktopFilePaths(GENERAL_APP_DESKTOP_PATH, infos); - this->loadDesktopFilePaths(ANDROID_APP_DESKTOP_PATH, infos); - this->loadDesktopFilePaths(SNAPD_APP_DESKTOP_PATH, infos); - if(infos.size() < 1) { - return; - } - XdgDesktopFile desktopfile; - for (int i = 0; i < infos.length(); i++) { - QFileInfo fileInfo = infos.at(i); - QString path = fileInfo.filePath(); - //对目录递归 - if (fileInfo.isDir()) { - loadDesktopFilePaths(path, infos); - continue; - } - //排除非法路径(黑名单 + 非desktop文件) - if (m_excludedDesktopfiles.contains(path) or !path.endsWith(".desktop")) { - continue; - } - - desktopfile.load(path); - //排除NoDisplay和NotShowIn字段,排除loaclized名字为空 - if (desktopfile.value("NoDisplay").toString().contains("true") or - desktopfile.value("NotShowIn").toString().contains("UKUI") or - desktopfile.localizedValue("Name").toString().isEmpty()) { - continue; - } - - if (!firstExec) { - //数据库有记录 - if (dataMap.contains(path)) { - if (!QString::compare(dataMap.value(path), getAppDesktopMd5(path)) - and !m_dbVersionNeedUpdate) { - //判断系统语言是否改变 - if (m_localeChanged) { - this->updateLocaleData(path); - } - dataMap.remove(path); - continue; - } else { - //数据库有记录但md5值改变或数据库版本需要更新则update - this->updateDBItem(path); - dataMap.remove(path); - continue; - } - } else { - //数据库中没有记录则insert - this->insertDBItem(path); - dataMap.remove(path); - continue; - } - } - //数据库为空则全部insert - this->insertDBItem(path); - dataMap.remove(path); - } - - //遍历完成后重置标志位 - m_localeChanged = false; - - //数据库冗余项直接delete - if (!dataMap.isEmpty()) { - for (auto i = dataMap.constBegin(); i != dataMap.constEnd(); i++) { - this->deleteDBItem(i.key()); - } - } + PendingAppInfo items; + items.setHandleType(PendingAppInfo::RefreshDataBase); + items.setPathsNeedRefreshData(appPaths); + items.setDBUpdate(dbVersionNeedUpdate); + PendingAppInfoQueue::getAppInfoQueue().enqueue(items); } -bool AppDBManager::handleLocaleDataUpdate(const QString &desktopPath) +bool AppDBManager::handleLocaleDataUpdate(const QString &desktopFilePath) { bool res(true); XdgDesktopFile desktopFile; - desktopFile.load(desktopPath); + desktopFile.load(desktopFilePath); QString localName = desktopFile.localizedValue("Name", "NULL").toString(); QString firstLetter2All = localName; @@ -514,26 +403,31 @@ bool AppDBManager::handleLocaleDataUpdate(const QString &desktopPath) } - QSqlQuery sql(m_database); - QString cmd = QString("UPDATE appInfo SET " - "LOCAL_NAME = '%0', FIRST_LETTER_ALL = '%1'" - "WHERE DESKTOP_FILE_PATH='%2'") - .arg(localName) - .arg(firstLetter2All) - .arg(desktopPath); + QSqlQuery query(m_database); + query.prepare("UPDATE appInfo SET LOCAL_NAME=:localName, FIRST_LETTER_ALL=:firstOfLetter2All WHERE DESKTOP_FILE_PATH=:desktopFilePath"); + query.bindValue(":localName", localName); + query.bindValue(":firstOfLetter2All", firstLetter2All); + query.bindValue(":desktopFilePath", desktopFilePath); - if (!sql.exec(cmd)) { - qWarning() << m_database.lastError() << cmd; - res = false; + if (!this->startTransaction()) { + return false; } - if (res) { - AppInfoResult result; - result.appLocalName = localName; - result.firstLetter = firstLetter2All; - Q_EMIT this->appDBItemUpdate(result); - qDebug() << "Already to update the locale app-data of " << desktopPath; + + if (query.exec()) { + if (this->startCommit()) { + ApplicationInfoMap appInfo; + appInfo[desktopFilePath].insert(ApplicationProperty::LocalName, QVariant(localName)); + appInfo[desktopFilePath].insert(ApplicationProperty::FirstLetterAll, QVariant(firstLetter2All)); + Q_EMIT this->appDBItemUpdate(appInfo); + qDebug() << "Update the locale data of " << desktopFilePath; + } else { + res = false; + } } else { - qDebug() << "Fail to update the locale app-data of " << desktopPath; + qDebug() << "Fail to update the locale data of " << desktopFilePath; + qWarning() << query.lastError() << query.lastQuery(); + m_database.rollback(); + res = false; } return res; } @@ -603,7 +497,7 @@ bool AppDBManager::startTransaction() if (m_database.transaction()) { return true; } else { - qWarning() << "Failed to start transaction mode!!!"; + qWarning() << "Failed to start transaction mode!!!" << m_database.lastError(); return false; } } @@ -611,7 +505,7 @@ bool AppDBManager::startTransaction() bool AppDBManager::startCommit() { if (!m_database.commit()) { - qWarning() << "Failed to commit !"; + qWarning() << "Failed to commit !" << m_database.lastError(); m_database.rollback(); return false; } else { @@ -619,21 +513,12 @@ bool AppDBManager::startCommit() } } -void AppDBManager::getInstallAppMap(QMap &installAppMap) -{ -// QMutexLocker locker(&s_mutex); -// for (auto i=m_installAppMap.begin(); i!=m_installAppMap.end(); ++i) { -// installAppMap[i.key().app_name] = i.value(); -// } -// installAppMap.detach(); -} - -bool AppDBManager::handleDBItemInsert(const QString &desktopfd) +bool AppDBManager::handleDBItemInsert(const QString &desktopFilePath) { bool res(true); QSqlQuery sql(m_database); XdgDesktopFile desktopfile; - desktopfile.load(desktopfd); + desktopfile.load(desktopFilePath); QString hanzi, pinyin, firstLetterOfPinyin; QString localName = desktopfile.localizedValue("Name", "NULL").toString(); QString firstLetter2All = localName; @@ -663,105 +548,179 @@ bool AppDBManager::handleDBItemInsert(const QString &desktopfd) } } - QString cmd = QString("INSERT INTO appInfo " - "(DESKTOP_FILE_PATH, MODIFYED_TIME, INSERT_TIME, " - "LOCAL_NAME, NAME_EN, NAME_ZH, PINYIN_NAME, " - "FIRST_LETTER_OF_PINYIN, FIRST_LETTER_ALL, " - "ICON, TYPE, CATEGORY, EXEC, COMMENT, MD5, " - "LAUNCH_TIMES, FAVORITES, LAUNCHED, TOP, LOCK) " - "VALUES('%1','%2','%3','%4','%5','%6','%7','%8','%9','%10','%11','%12','%13','%14','%15',%16,%17,%18,%19,%20)") - .arg(desktopfd) - .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) - .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) - .arg(localName) - .arg(desktopfile.value("Name").toString()) - .arg(hanzi) - .arg(pinyin) - .arg(firstLetterOfPinyin) - .arg(firstLetter2All) - .arg(desktopfile.value("Icon").toString()) - .arg(desktopfile.value("Type").toString()) - .arg(desktopfile.value("Categories").toString()) - .arg(desktopfile.value("Exec").toString()) - .arg(desktopfile.value("Comment").toString().replace("'", "''")) - .arg(getAppDesktopMd5(desktopfd)) - .arg(0) - .arg(0) - .arg(0) - .arg(0) - .arg(0); - if (!sql.exec(cmd)) { - qWarning() << m_database.lastError() << cmd; - res = false; + int dontDisplay = 0; + if (desktopfile.value("NoDisplay").toString().contains("true") || desktopfile.value("NotShowIn").toString().contains("UKUI")) { + dontDisplay = 1; } - if (res) { - AppInfoResult result; - result.desktopPath = desktopfd; - result.iconName = desktopfile.value("Icon").toString(); - result.appLocalName = localName; - result.firstLetter = firstLetter2All; - result.category = desktopfile.value("Categories").toString(); - Q_EMIT this->appDBItemAdd(result); - qDebug() << "app database add " << desktopfd << "success!"; + + int isAutoStartApp = 0; + if (desktopFilePath.startsWith(AUTOSTART_APP_DESKTOP_PATH + "/")) { + isAutoStartApp = 1; + } + + sql.prepare(QString("INSERT INTO appInfo " + "(DESKTOP_FILE_PATH, MODIFYED_TIME, INSERT_TIME, " + "LOCAL_NAME, NAME_EN, NAME_ZH, PINYIN_NAME, " + "FIRST_LETTER_OF_PINYIN, FIRST_LETTER_ALL, " + "ICON, TYPE, CATEGORY, EXEC, COMMENT, MD5, " + "LAUNCH_TIMES, FAVORITES, LAUNCHED, TOP, LOCK, DONT_DISPLAY, AUTO_START, START_UP_WMCLASS) " + "VALUES(:desktopFilePath, '%0', '%1', :localName, :enName, :zhName, :pinyinName, :firstLetterOfPinyin, :firstLetter2All, " + ":icon, :type, :categories, :exec, :comment,'%2',%3,%4,%5,%6,%7,%8,%9, :wmClass)") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(getAppDesktopMd5(desktopFilePath)) + .arg(0) + .arg(0) + .arg(0) + .arg(0) + .arg(0) + .arg(dontDisplay) + .arg(isAutoStartApp)); + sql.bindValue(":desktopFilePath", desktopFilePath); + sql.bindValue(":localName", localName); + sql.bindValue(":enName", desktopfile.value("Name").toString()); + sql.bindValue(":zhName", hanzi); + sql.bindValue(":pinyinName", pinyin); + sql.bindValue(":firstLetterOfPinyin", firstLetterOfPinyin); + sql.bindValue(":firstLetter2All", firstLetter2All); + sql.bindValue(":icon", desktopfile.value("Icon").toString()); + sql.bindValue(":type", desktopfile.value("Type").toString()); + sql.bindValue(":categories", desktopfile.value("Categories").toString()); + sql.bindValue(":exec", desktopfile.value("Exec").toString()); + sql.bindValue(":comment", desktopfile.value("Comment").toString()); + sql.bindValue(":wmClass", desktopfile.value("StartupWMClass").toString()); + + if (!this->startTransaction()) { + return false; + } + + if (sql.exec()) { + if (this->startCommit()) { + Q_EMIT this->appDBItemAdd(desktopFilePath); + qDebug() << "app database add " << desktopFilePath << "success!"; + } else { + res = false; + } } else { - qDebug() << "app database add " << desktopfd << "failed!"; + qDebug() << "app database add " << desktopFilePath << "failed!"; + qWarning() << m_database.lastError() << sql.lastQuery(); + m_database.rollback(); + res = false; } return res; } -bool AppDBManager::handleDBItemDelete(const QString &desktopfd) +bool AppDBManager::handleDBItemDelete(const QString &desktopFilePath) { + if (!this->startTransaction()) { + return false; + } + bool res(true); - QSqlQuery sql(m_database); - QString cmd = QString("SELECT FAVORITES, TOP FROM APPINFO WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfd); + QSqlQuery query(m_database); + query.setForwardOnly(true); + QString cmd = "SELECT FAVORITES, TOP FROM APPINFO WHERE DESKTOP_FILE_PATH=:desktopFilePath"; + query.prepare(cmd); + query.bindValue(":desktopFilePath", desktopFilePath); //查询要删除信息的应用是否被收藏或顶置过 - if (!sql.exec(cmd)) { - qWarning() << m_database.lastError() << cmd; - } else if (sql.next()) { - int favorites = sql.value("FAVORITES").toInt(); - int top = sql.value("TOP").toInt(); + if (!query.exec()) { + res = false; + qWarning() << m_database.lastError() << query.lastQuery(); + } else if (query.next()) { + int favorites = query.value("FAVORITES").toInt(); + int top = query.value("TOP").toInt(); if (favorites) { - cmd = QString("UPDATE appInfo SET FAVORITES = FAVORITES -1 WHERE FAVORITES > %1").arg(favorites); - if (!sql.exec(cmd)) { - qWarning() << "I'm going to delete item in db, fail to update the FAVORITES because:" << m_database.lastError() << cmd; + query.prepare(QString("UPDATE appInfo SET FAVORITES = FAVORITES -1 WHERE FAVORITES > %1").arg(favorites)); + if (query.exec()) { + cmd = QString("SELECT DESKTOP_FILE_PATH,FAVORITES FROM APPINFO WHERE FAVORITES >= %1").arg(favorites); + if (query.exec(cmd)) { + ApplicationInfoMap infos; + while (query.next()) { + if (query.value("DESKTOP_FILE_PATH").toString() == desktopFilePath) { + continue; + } + infos[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Favorites, query.value("FAVORITES")); + } + if (!infos.isEmpty()) { + Q_EMIT this->appDBItemUpdate(infos); + } + } else { + qWarning() << query.lastError() << query.lastQuery(); + } + } else { + res = false; + qWarning() << "I'm going to delete item in db, fail to update the FAVORITES because:" << query.lastError() << cmd; } } if (top) { - cmd = QString("UPDATE appInfo SET TOP = TOP -1 WHERE TOP > %1").arg(top); - if (!sql.exec(cmd)) { - qWarning() << "I'm going to delete item in db, fail to update the TOP because:" << m_database.lastError() << cmd; + query.prepare(QString("UPDATE appInfo SET TOP = TOP -1 WHERE TOP > %1").arg(top)); + if (query.exec()) { + cmd = QString("SELECT DESKTOP_FILE_PATH,TOP FROM APPINFO WHERE TOP >= %1").arg(top); + if (query.exec(cmd)) { + ApplicationInfoMap infos; + while (query.next()) { + if (query.value("DESKTOP_FILE_PATH").toString() == desktopFilePath) { + continue; + } + infos[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Top, query.value("TOP")); + } + if (!infos.isEmpty()) { + Q_EMIT this->appDBItemUpdate(infos); + } + } else { + qWarning() << query.lastError() << query.lastQuery(); + } + } else { + res = false; + qWarning() << "I'm going to delete item in db, fail to update the TOP because:" << query.lastError() << cmd; } } } else { - qWarning() << "Fail to exec next, because" << m_database.lastError() << "while executing " << cmd; + qWarning() << "Fail to exec next, because" << query.lastError() << "while executing " << query.lastQuery(); + } + + if (!res) { + m_database.rollback(); + return res; } //执行删除操作 - cmd = QString("DELETE FROM APPINFO WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfd); - if (!sql.exec(cmd)) { - qWarning() << m_database.lastError() << cmd; - res = false; - } - - if (res) { - Q_EMIT this->appDBItemDelete(desktopfd); - qDebug() << "app database delete " << desktopfd << "success!"; + cmd = "DELETE FROM APPINFO WHERE DESKTOP_FILE_PATH=:desktopFilePath"; + query.prepare(cmd); + query.bindValue(":desktopFilePath", desktopFilePath); + if (query.exec()) { + if (this->startCommit()) { + Q_EMIT this->appDBItemDelete(desktopFilePath); + qDebug() << "app database delete " << desktopFilePath << "success!"; + } else { + res = false; + } } else { - qDebug() << "app database delete " << desktopfd << "failed!"; + qDebug() << "app database delete " << desktopFilePath << "failed!"; + qWarning() << query.lastError() << cmd; + m_database.rollback(); + res = false; } return res; } -bool AppDBManager::handleDBItemUpdate(const QString &desktopfd) +bool AppDBManager::handleDBItemUpdate(const QString &desktopFilePath) { bool res(true); XdgDesktopFile desktopfile; - desktopfile.load(desktopfd); + desktopfile.load(desktopFilePath); + + int dontDisplay = 0; if (desktopfile.value("NoDisplay").toString().contains("true") || desktopfile.value("NotShowIn").toString().contains("UKUI")) { - qDebug() << "app" << desktopfd << "is changed, but NoDisplay or NotShowIn is working!"; - return this->handleDBItemDelete(desktopfd); + dontDisplay = 1; } + + int isAutoStartApp = 0; + if (desktopFilePath.startsWith(AUTOSTART_APP_DESKTOP_PATH + "/")) { + isAutoStartApp = 1; + } + QString hanzi, pinyin, firstLetterOfPinyin; QString localName = desktopfile.localizedValue("Name", "NULL").toString(); QString firstLetter2All = localName; @@ -793,204 +752,843 @@ bool AppDBManager::handleDBItemUpdate(const QString &desktopfd) } QSqlQuery sql(m_database); - QString cmd = QString("UPDATE appInfo SET " - "MODIFYED_TIME='%0'," - "LOCAL_NAME='%1'," - "NAME_EN='%2'," - "NAME_ZH='%3'," - "PINYIN_NAME='%4'," - "FIRST_LETTER_OF_PINYIN='%5'," - "FIRST_LETTER_ALL='%6'," - "ICON='%7'," - "TYPE='%8'," - "CATEGORY='%9'," - "EXEC='%10'," - "COMMENT='%11'," - "MD5='%12' " - "WHERE DESKTOP_FILE_PATH='%13'") - .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) - .arg(localName) - .arg(desktopfile.value("Name").toString()) - .arg(hanzi) - .arg(pinyin) - .arg(firstLetterOfPinyin) - .arg(firstLetter2All) - .arg(desktopfile.value("Icon").toString()) - .arg(desktopfile.value("Type").toString()) - .arg(desktopfile.value("Categories").toString()) - .arg(desktopfile.value("Exec").toString()) - .arg(desktopfile.value("Comment").toString().replace("'", "''")) - .arg(getAppDesktopMd5(desktopfd)) - .arg(desktopfd); - if (!sql.exec(cmd)) { - qWarning() << m_database.lastError() << cmd; - res = false; - } - if (res) { - AppInfoResult result; - result.desktopPath = desktopfd; - result.iconName = desktopfile.value("Icon").toString(); - result.appLocalName = localName; - result.firstLetter = firstLetter2All; - result.category = desktopfile.value("Categories").toString(); - Q_EMIT this->appDBItemUpdate(result); - qDebug() << "app database update " << desktopfd << "success!"; - } else { - qDebug() << "app database update " << desktopfd << "failed!"; - } - return res; -} + sql.prepare(QString("UPDATE appInfo SET " + "MODIFYED_TIME='%0'," + "LOCAL_NAME=:localName," + "NAME_EN=:enName," + "NAME_ZH=:zhName," + "PINYIN_NAME=:pinyinName," + "FIRST_LETTER_OF_PINYIN=:firstLetterOfPinyin," + "FIRST_LETTER_ALL=:firstLetter2All," + "ICON=:icon," + "TYPE=:type," + "CATEGORY=:categories," + "EXEC=:exec," + "COMMENT=:comment," + "START_UP_WMCLASS=:wmClass," + "MD5='%1'," + "DONT_DISPLAY=%2," + "AUTO_START=%3 " + "WHERE DESKTOP_FILE_PATH=:desktopFilePath") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(getAppDesktopMd5(desktopFilePath)) + .arg(dontDisplay) + .arg(isAutoStartApp)); + sql.bindValue(":desktopFilePath", desktopFilePath); + sql.bindValue(":localName", localName); + sql.bindValue(":enName", desktopfile.value("Name").toString()); + sql.bindValue(":zhName", hanzi); + sql.bindValue(":pinyinName", pinyin); + sql.bindValue(":firstLetterOfPinyin", firstLetterOfPinyin); + sql.bindValue(":firstLetter2All", firstLetter2All); + sql.bindValue(":icon", desktopfile.value("Icon").toString()); + sql.bindValue(":type", desktopfile.value("Type").toString()); + sql.bindValue(":categories", desktopfile.value("Categories").toString()); + sql.bindValue(":exec", desktopfile.value("Exec").toString()); + sql.bindValue(":comment", desktopfile.value("Comment").toString()); + sql.bindValue(":wmClass", desktopfile.value("StartupWMClass").toString()); -bool AppDBManager::handleLaunchTimesUpdate(const QString &desktopfp, int num) -{ - qDebug() << "launch times will add:" << num; - bool res(true); - QSqlQuery sql(m_database); - QString cmd = QString("SELECT LAUNCH_TIMES FROM APPINFO WHERE DESKTOP_FILE_PATH='%1'").arg(desktopfp); - if (sql.exec(cmd)) { - if (sql.next()) { - int launchTimes = sql.value(0).toInt() + num; - cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', LAUNCH_TIMES=%1, LAUNCHED=%2 WHERE DESKTOP_FILE_PATH='%3'") - .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) - .arg(launchTimes) - .arg(1) - .arg(desktopfp); - if (!sql.exec(cmd)) { - qWarning() << "Set app favorites state failed!" << m_database.lastError(); - res = false; - } else { - AppInfoResult result; - result.desktopPath = desktopfp; - result.launchTimes = launchTimes; - Q_EMIT this->appDBItemUpdate(result); - qDebug() << "app database update:" << desktopfp << "launch times:" << launchTimes << "success!"; - } + if (!this->startTransaction()) { + return false; + } + + if (sql.exec()) { + if (this->startCommit()) { + Q_EMIT this->appDBItemUpdateAll(desktopFilePath); + qDebug() << "app database update all data of" << desktopFilePath << "success!"; } else { - qWarning() << "Failed to exec next!" << cmd; res = false; } } else { - qWarning() << "Failed to exec:" << cmd; + qDebug() << "app database update " << desktopFilePath << "failed!"; + qWarning() << m_database.lastError() << sql.lastQuery(); + m_database.rollback(); res = false; } return res; } -bool AppDBManager::handleFavoritesStateUpdate(const QString &desktopfp, int num) +bool AppDBManager::handleLaunchTimesUpdate(const QString &desktopFilePath, int num) { - if (num < 0) { - qWarning() << "Invalid favorite num, I quit!!!"; - return false; - } - + qDebug() << "launch times will add:" << num; bool res(true); - QSqlQuery sql(m_database); - - //查询要设置的favorites标志位是否被占用 - QString cmd = QString("SELECT DESKTOP_FILE_PATH, FAVORITES FROM APPINFO WHERE FAVORITES = %1").arg(num); - if (!sql.exec(cmd)) { - qWarning() << "Fail to exec:" << cmd << "because:" << m_database.lastError(); - } else { - while (sql.next()) { - if (sql.value("FAVORITES").toInt() == num) { + QSqlQuery query(m_database); + query.setForwardOnly(true); + query.prepare("SELECT LAUNCH_TIMES FROM APPINFO WHERE DESKTOP_FILE_PATH=:desktopFilePath"); + query.bindValue(":desktopFilePath", desktopFilePath); + if (query.exec()) { + if (query.next()) { + int launchTimes = query.value(0).toInt() + num; + if (!this->startTransaction()) { res = false; - if (sql.value("DESKTOP_FILE_PATH").toString() == desktopfp) { - qWarning() << "favorites state has no changes, I quit!"; - return res; + return res; + } + query.prepare(QString("UPDATE appInfo SET MODIFYED_TIME='%0', LAUNCH_TIMES=%1, LAUNCHED=%2 WHERE DESKTOP_FILE_PATH=:desktopFilePath") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(launchTimes) + .arg(1)); + query.bindValue(":desktopFilePath", desktopFilePath); + if (!query.exec()) { + qWarning() << "Set app launch times failed!" << m_database.lastError(); + res = false; + m_database.rollback(); + } else { + if (this->startCommit()) { + ApplicationInfoMap appInfo; + appInfo[desktopFilePath].insert(ApplicationProperty::LaunchTimes, QVariant(launchTimes)); + appInfo[desktopFilePath].insert(ApplicationProperty::Launched, QVariant(1)); + Q_EMIT this->appDBItemUpdate(appInfo); + qDebug() << "app database update " << desktopFilePath << "launch times: " << launchTimes << "success!"; } else { - qWarning() << "the favorites num:" << num << "has been used, fail to update favorites state of" << desktopfp; - return res; + res = false; } } + } else { + qWarning() << "Failed to exec next!" << query.lastQuery() << query.lastError(); + res = false; + } + } else { + qWarning() << "Failed to exec:" << query.lastQuery(); + res = false; + } + + return res; +} + +bool AppDBManager::handleFavoritesStateUpdate(const QString &desktopFilePath, const uint num) +{ + bool res(true); + QSqlQuery query(m_database); + query.setForwardOnly(true); + QString cmd; + ApplicationInfoMap infos; + + //获取应用在数据库中的favorites标志位 + uint previousPos = 0; + bool getPrevious(false); + cmd = "SELECT FAVORITES FROM APPINFO WHERE DESKTOP_FILE_PATH =:desktopFilePath"; + query.prepare(cmd); + query.bindValue(":desktopFilePath", desktopFilePath); + if (query.exec()) { + if (query.next()) { + previousPos = query.value("FAVORITES").toUInt(); + getPrevious = true; + } else { + qWarning() << query.lastQuery() << query.lastError(); + } + } else { + qWarning() << query.lastQuery() << query.lastError(); + } + + //收藏位未改变 + if (getPrevious && previousPos == num) { + res = false; + qWarning() << "favorites state has no changes, I quit!"; + return res; + } + + //查询目前favorites最大值 + uint maxFavorite = 0; + query.prepare("SELECT max(FAVORITES) as max FROM APPINFO"); + if (query.exec()) { + if (query.next()) { + maxFavorite = query.value("max").toUInt(); + if (maxFavorite + 1 < num) { + qWarning() << QString("Max favorites pos is %0.To be moved to a invalid pos, I quit!!").arg(query.value("max").toInt()); + res = false; + } + } + } else { + qWarning() << query.lastError() << query.lastQuery(); + res = false; + } + if (!res) { + return res; + } + + //取消收藏时,将对应应用前移 + if (!num) { + if (previousPos < 1) { + res = false; + } + if (res) { + if (!this->startTransaction()) { + res = false; + return res; + } + cmd = QString("UPDATE APPINFO SET MODIFYED_TIME='%0', FAVORITES=FAVORITES-1 WHERE FAVORITES > %1;") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(previousPos); + if (query.exec(cmd)) { + cmd = QString("SELECT DESKTOP_FILE_PATH,FAVORITES FROM APPINFO WHERE FAVORITES >= %0;").arg(previousPos); + if (query.exec(cmd)) { + qDebug() << "Prepare to cancel the favorite state of" << desktopFilePath; + while (query.next()) { + infos[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Favorites, query.value("FAVORITES")); + } + } else { + qWarning() << query.lastQuery() << query.lastError(); + } + } else { + res = false; + qWarning() << query.lastQuery() << query.lastError(); + m_database.rollback(); + } + } + } else { + //直接设置时(要设置的应用未被收藏),查询要设置的favorites标志位是否被占用,占用则将该应用及其之后的应用的favorites标志位后移 + if (getPrevious && !previousPos) { + cmd = QString("SELECT DESKTOP_FILE_PATH FROM APPINFO WHERE FAVORITES = %1").arg(num); + if (!query.exec(cmd)) { + qWarning() << "Fail to exec:" << cmd << "because:" << query.lastError(); + res = false; + } else { + if (!this->startTransaction()) { + return false; + } + if (query.next()) { + //默认收藏后顶到第一个,其余后移,若想直接收藏到对应位置则将该位置后的收藏应用后移 + query.prepare(QString("UPDATE APPINFO SET MODIFYED_TIME='%0', FAVORITES=FAVORITES+1 WHERE FAVORITES >= %1;") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(num)); + if (!query.exec()) { + res = false; + qWarning() << query.lastError() << query.lastQuery(); + m_database.rollback(); + } else { + cmd = QString("SELECT DESKTOP_FILE_PATH, FAVORITES FROM APPINFO WHERE FAVORITES >= %1").arg(num); + if (!query.exec(cmd)) { + qWarning() << query.lastError() << query.lastQuery(); + res = false; + } else { + while (query.next()) { + infos[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Favorites, query.value("FAVORITES")); + } + } + } + } + } + } else { + //触发修改位置逻辑 + res = maxFavorite < num? false : this->handleChangeFavoritesPos(desktopFilePath, num, previousPos, infos); + qDebug() << "change favorites pos:" << res; } } + //移动位置执行不成功则不去更新对应应用的favorites标志位 + if (!res) { + return res; + } + //更新favorites状态 - cmd = QString("UPDATE APPINFO SET MODIFYED_TIME='%0', FAVORITES=%1 WHERE DESKTOP_FILE_PATH='%2'") + cmd = QString("UPDATE APPINFO SET MODIFYED_TIME='%0', FAVORITES=%1 WHERE DESKTOP_FILE_PATH=:desktopFilePath") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) - .arg(num) - .arg(desktopfp); - if (!sql.exec(cmd)) { + .arg(num); + query.prepare(cmd); + query.bindValue(":desktopFilePath", desktopFilePath); + if (!query.exec()) { qWarning() << "Set app favorites state failed!" << m_database.lastError(); res = false; + m_database.rollback(); } else { - AppInfoResult info; - info.desktopPath = desktopfp; - info.favorite = num; - Q_EMIT this->appDBItemUpdate(info); - qDebug() << "app database update " << desktopfp << "favorites state: " << num << "success!"; + if (this->startCommit()) { + infos[desktopFilePath].insert(ApplicationProperty::Favorites, QVariant(num)); + Q_EMIT this->appDBItemUpdate(infos); + qDebug() << "app database update " << desktopFilePath << "favorites state: " << num << "success!"; + } else { + res = false; + } } return res; } -bool AppDBManager::handleTopStateUpdate(const QString &desktopfp, int num) +bool AppDBManager::handleChangeFavoritesPos(const QString &desktopFilePath, const uint pos, const uint previousPos, ApplicationInfoMap &updatedInfo) { - if (num < 0) { - qWarning() << "Invalid top num, I quit!!!"; + if (pos < 1) { + qWarning() << "To be moved to a invalid favorites pos , I quit!!"; + return false; + } + + if (previousPos < 1) { + qWarning() << QString("app: %1 is not a favorites app, I quit!!").arg(desktopFilePath); return false; } bool res(true); - QSqlQuery sql(m_database); + QSqlQuery query(m_database); + query.setForwardOnly(true); - //查询要设置的top标志位是否被占用 - QString cmd = QString("SELECT DESKTOP_FILE_PATH, TOP FROM APPINFO WHERE TOP = %1").arg(num); - if (!sql.exec(cmd)) { - qWarning() << "Fail to exec:" << cmd << "because:" << m_database.lastError(); + QString condition; + if (previousPos > pos) { + condition = "FAVORITES=FAVORITES+1"; } else { - while (sql.next()) { - if (sql.value("TOP").toInt() == num) { - res = false; - if (sql.value("DESKTOP_FILE_PATH").toString() == desktopfp) { - qWarning() << "top state has no changes, I quit!"; - return res; - } else { - qWarning() << "the top num:" << num << "has been used, fail to update top state of" << desktopfp; - return res; - } - } - } + condition = "FAVORITES=FAVORITES-1"; } - //更新top状态 - cmd = QString("UPDATE APPINFO SET MODIFYED_TIME='%0', TOP=%1 WHERE DESKTOP_FILE_PATH='%2'") - .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) - .arg(num) - .arg(desktopfp); - if (!sql.exec(cmd)) { - qWarning() << "Set app favorites state failed!" << m_database.lastError(); - res = false; + query.prepare(QString("UPDATE APPINFO SET %0 WHERE FAVORITES BETWEEN MIN(%1, %2) AND MAX(%1, %2)") + .arg(condition) + .arg(previousPos) + .arg(pos)); + + if (!this->startTransaction()) { + return false; + } + + //更新原位置和新位置之间的应用的位置 + if (query.exec()) { + query.prepare(QString("SELECT DESKTOP_FILE_PATH,FAVORITES FROM APPINFO WHERE FAVORITES BETWEEN MIN(%1, %2) AND MAX(%1, %2)") + .arg(previousPos) + .arg(pos)); + if (query.exec()) { + while (query.next()) { + updatedInfo[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Favorites, query.value("FAVORITES")); + } + } } else { - AppInfoResult info; - info.desktopPath = desktopfp; - info.top = num; - Q_EMIT this->appDBItemUpdate(info); - qDebug() << "app database update " << desktopfp << "top state: " << num << "success!"; + res = false; + qWarning() << "Fail to change favorite-app pos, because: " << query.lastError() << " when exec :" << query.lastQuery(); + m_database.rollback(); + } + + return res; +} + +bool AppDBManager::handleTopStateUpdate(const QString &desktopFilePath, const uint num) +{ + bool res(true); + QSqlQuery query(m_database); + query.setForwardOnly(true); + QString cmd; + ApplicationInfoMap infos; + + //获取应用在数据库中的top标志位 + uint previousPos = 0; + bool getPrevious(false); + cmd = "SELECT TOP FROM APPINFO WHERE DESKTOP_FILE_PATH =:desktopFilePath"; + query.prepare(cmd); + query.bindValue(":desktopFilePath", desktopFilePath); + if (query.exec()) { + if (query.next()) { + previousPos = query.value("TOP").toUInt(); + getPrevious = true; + } else { + qWarning() << query.lastQuery() << query.lastError(); + } + } else { + qWarning() << query.lastQuery() << query.lastError(); + } + + //top位未改变 + if (getPrevious && previousPos == num) { + res = false; + qWarning() << "Top state has no changes, I quit!"; + return res; + } + + //查询目前top最大值 + uint maxTop = 0; + query.prepare("SELECT max(TOP) as max FROM APPINFO"); + if (query.exec()) { + if (query.next()) { + maxTop = query.value("max").toUInt(); + if (maxTop + 1 < num) { + qWarning() << QString("Max top pos is %0.To be moved to a invalid pos, I quit!!").arg(query.value("max").toInt()); + res = false; + } + } else { + res = false; + } + } else { + qWarning() << query.lastError() << query.lastQuery(); + res = false; + } + if (!res) { + return res; + } + + //取消置顶时,将对应应用前移 + if (!num) { + if (previousPos < 1) { + res = false; + } + if (res) { + if (!this->startTransaction()) { + res = false; + return res; + } + cmd = QString("UPDATE APPINFO SET MODIFYED_TIME='%0', TOP=TOP-1 WHERE TOP > %1;") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(previousPos); + if (query.exec(cmd)) { + cmd = QString("SELECT DESKTOP_FILE_PATH,TOP FROM APPINFO WHERE TOP >= %0;").arg(previousPos); + if (query.exec(cmd)) { + qDebug() << "Prepare to cancel the top state of" << desktopFilePath; + while (query.next()) { + infos[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Top, query.value("TOP")); + } + } else { + qWarning() << query.lastQuery() << query.lastError(); + } + } else { + res = false; + qWarning() << query.lastQuery() << query.lastError(); + m_database.rollback(); + } + } + } else { + //直接设置时,查询要设置的top标志位是否被占用,占用则将该应用及其之后的应用的top标志位后移 + if (getPrevious && !previousPos) { + cmd = QString("SELECT DESKTOP_FILE_PATH FROM APPINFO WHERE TOP = %1").arg(num); + if (!query.exec(cmd)) { + qWarning() << "Fail to exec:" << cmd << "because:" << query.lastError(); + } else { + if (!this->startTransaction()) { + return false; + } + if (query.next()) { + //默认置顶后顶到第一个,其余后移,若想直接置顶到对应位置则将该位置后的置顶应用后移 + query.prepare(QString("UPDATE APPINFO SET MODIFYED_TIME='%0', TOP=TOP+1 WHERE TOP >= %1;") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(num)); + if (!query.exec()) { + qWarning() << query.lastError() << query.lastQuery(); + res = false; + m_database.rollback(); + } else { + cmd = QString("SELECT DESKTOP_FILE_PATH, TOP FROM APPINFO WHERE TOP >= %1").arg(num); + if (!query.exec(cmd)) { + qWarning() << query.lastError() << query.lastQuery(); + res = false; + } else { + while (query.next()) { + infos[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Top, query.value("TOP")); + } + } + } + } + } + } else { + //触发修改位置逻辑 + res = maxTop < num ? false : this->handleChangeTopPos(desktopFilePath, num, previousPos, infos); + qDebug() << "Change top pos:" << res; + } + } + //移动位置执行不成功则不去更新对应应用的top标志位 + if (!res) { + return res; + } + + + //更新top状态 + cmd = QString("UPDATE APPINFO SET MODIFYED_TIME='%0', TOP=%1 WHERE DESKTOP_FILE_PATH=:desktopFilePath") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(num); + query.prepare(cmd); + query.bindValue(":desktopFilePath", desktopFilePath); + if (!query.exec()) { + qWarning() << "Set app top state failed!" << query.lastError(); + res = false; + m_database.rollback(); + } else { + if (this->startCommit()) { + infos[desktopFilePath].insert(ApplicationProperty::Top, QVariant(num)); + Q_EMIT this->appDBItemUpdate(infos); + qDebug() << "app database update " << desktopFilePath << "top state: " << num << "success!"; + } else { + res = false; + } } return res; } -bool AppDBManager::handleLockStateUpdate(const QString &desktopfp, int num) +bool AppDBManager::handleChangeTopPos(const QString &desktopFilePath, uint pos, const uint previousPos, ApplicationInfoMap &updatedInfo) { + if (pos < 1) { + qWarning() << "To be moved to a invalid top pos , I quit!!"; + return false; + } + + if (previousPos < 1) { + qWarning() << QString("app: %1 is not a top app, I quit!!").arg(desktopFilePath); + return false; + } + + bool res(true); + QSqlQuery query(m_database); + query.setForwardOnly(true); + + QString condition; + if (previousPos > pos) { + condition = "TOP=TOP+1"; + } else { + condition = "TOP=TOP-1"; + } + + query.prepare(QString("UPDATE APPINFO SET %0 WHERE TOP BETWEEN MIN(%1, %2) AND MAX(%1, %2)") + .arg(condition) + .arg(previousPos) + .arg(pos)); + + if (!this->startTransaction()) { + res = false; + return res; + } + + //更新原位置和新位置之间的应用的位置 + if (query.exec()) { + query.prepare(QString("SELECT DESKTOP_FILE_PATH,TOP FROM APPINFO WHERE TOP BETWEEN MIN(%1, %2) AND MAX(%1, %2)") + .arg(previousPos) + .arg(pos)); + if (query.exec()) { + while (query.next()) { + updatedInfo[query.value("DESKTOP_FILE_PATH").toString()].insert(ApplicationProperty::Top, query.value("TOP")); + } + } + } else { + qWarning() << "Fail to change favorite-app pos, because: " << query.lastError() << " when exec :" << query.lastQuery(); + res = false; + m_database.rollback(); + } + + return res; +} + +bool AppDBManager::handleLockStateUpdate(const QString &desktopFilePath, int num) +{ + if (!this->startTransaction()) { + return false; + } bool res(true); QSqlQuery sql(m_database); - QString cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', LOCK=%1 WHERE DESKTOP_FILE_PATH='%2'") - .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) - .arg(num) - .arg(desktopfp); - if (!sql.exec(cmd)) { - qWarning() << "Set app favorites state failed!" << m_database.lastError(); + sql.prepare(QString("UPDATE appInfo SET MODIFYED_TIME='%0', LOCK=%1 WHERE DESKTOP_FILE_PATH=:desktopFilePath") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(num)); + sql.bindValue(":desktopFilePath", desktopFilePath); + if (!sql.exec()) { + qWarning() << "Set app lock state failed!" << m_database.lastError(); res = false; + m_database.rollback(); } else { - AppInfoResult info; - info.desktopPath = desktopfp; - info.lock = num; - Q_EMIT this->appDBItemUpdate(info); - qDebug() << "app database update " << desktopfp << "lock state: " << num << "success!"; + if (this->startCommit()) { + ApplicationInfoMap appInfo; + appInfo[desktopFilePath].insert(ApplicationProperty::Lock, QVariant(num)); + Q_EMIT this->appDBItemUpdate(appInfo); + qDebug() << "app database update " << desktopFilePath << "lock state: " << num << "success!"; + } else { + res = false; + } } return res; } +void AppDBManager::handleDataBaseRefresh(const QStringList &appPaths, bool dbVersionNeedUpdate) +{ + QMap dataMap; + QSqlQuery query(m_database); + query.setForwardOnly(true); + QString condition; + for (int i = 0; i < appPaths.size(); i++) { + condition.append("DESKTOP_FILE_PATH LIKE ? OR "); + } + condition = condition.left(condition.lastIndexOf(" OR ")); + query.prepare(QString("SELECT DESKTOP_FILE_PATH,MD5 FROM APPINFO WHERE %0").arg(condition)); + for (int t = 0; t < appPaths.size(); t++) { + query.bindValue(t, appPaths.at(t) + "/%"); + } + + if (!query.exec()) { + qWarning() << m_database.lastError() << query.lastError(); + } else { + query.exec(); + while (query.next()) { + dataMap.insert(query.value("DESKTOP_FILE_PATH").toString(), query.value("MD5").toString()); + } + } + + //遍历desktop文件 + QFileInfoList infos; + for (const QString &path : appPaths) { + this->loadDesktopFilePaths(path, infos); + } + + if(infos.size() < 1) { + return; + } + XdgDesktopFile desktopfile; + for (int i = 0; i < infos.length(); i++) { + QFileInfo fileInfo = infos.at(i); + QString path = fileInfo.filePath(); + //对目录递归 + if (fileInfo.isDir()) { + loadDesktopFilePaths(path, infos); + continue; + } + //排除非法路径(非desktop文件) + if (!path.endsWith(".desktop")) { + continue; + } + + desktopfile.load(path); + //排除loaclized名字为空 + if (desktopfile.localizedValue("Name").toString().isEmpty()) { + continue; + } + + if (!dataMap.isEmpty()) { + //数据库有记录 + if (dataMap.contains(path)) { + if (!QString::compare(dataMap.value(path), getAppDesktopMd5(path)) && !dbVersionNeedUpdate) { + //判断系统语言是否改变 + if (m_localeChanged) { + this->handleLocaleDataUpdate(path); + } + dataMap.remove(path); + continue; + } else { + //数据库有记录但md5值改变或数据库版本需要更新则update + this->handleDBItemUpdate(path); + dataMap.remove(path); + continue; + } + } else { + //数据库中没有记录则insert + this->handleDBItemInsert(path); + dataMap.remove(path); + continue; + } + } + //数据库为空则全部insert + this->handleDBItemInsert(path); + dataMap.remove(path); + } + + //遍历完成后重置标志位 + m_localeChanged = false; + + //数据库冗余项直接delete + if (!dataMap.isEmpty()) { + for (auto i = dataMap.constBegin(); i != dataMap.constEnd(); i++) { + this->handleDBItemDelete(i.key()); + } + } +} + +bool AppDBManager::handleValueSet(const ApplicationInfoMap appInfoMap) +{ + bool res(true); + QSqlQuery query(m_database); + + for (auto iter = appInfoMap.constBegin(); iter != appInfoMap.constEnd(); iter++) { + QString desktopFilePath = iter.key(); + ApplicationPropertyMap propMap = iter.value(); + for (auto propIter = propMap.constBegin(); propIter != propMap.constEnd(); ++propIter) { + QString field = ApplicationPropertyHelper(propIter.key()).dataBaseField(); + + query.prepare(QString("UPDATE appInfo SET MODIFYED_TIME='%0', %1=:value WHERE DESKTOP_FILE_PATH=:desktopFilePath") + .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) + .arg(field)); + query.bindValue(":value", propIter.value()); + query.bindValue(":desktopFilePath", desktopFilePath); + + if (!this->startTransaction()) { + return false; + } + + if (!query.exec()) { + qWarning() << "Set state failed!" << query.lastError(); + res = false; + m_database.rollback(); + } else { + if (this->startCommit()) { + ApplicationInfoMap infos2BSend; + infos2BSend[desktopFilePath].insert(propIter.key(), propIter.value()); + Q_EMIT this->appDBItemUpdate(infos2BSend); + qDebug() << "app database update " << desktopFilePath << field << propIter.value() << "success!"; + } else { + res = false; + } + } + } + } + return res; +} + +QString AppDBManager::tranPidToDesktopFp(uint pid) +{ + QFile file("/proc/" + QString::number(pid) + "/cmdline"); + file.open(QFile::ReadOnly); + QList cmdlist = file.readAll().split('\0'); + file.close(); + + cmdlist.removeAll(""); + QString exePath; + for (int i = cmdlist.size() - 1; i >= 0; i--) { + if (cmdlist.at(i).startsWith("-") || cmdlist.at(i).contains("%")) { + continue; + } + if (!QUrl(cmdlist.at(i)).isRelative()) { + continue; + } + exePath = cmdlist.at(i); + break; + } + + QString desktopFilePath; + if (exePath.isEmpty()) { + qWarning() << "Can not find the desktop file by pid:" << pid << "because of empty exePath."; + return desktopFilePath; + } + + QSqlQuery query(m_database); + query.setForwardOnly(true); + query.prepare("SELECT DESKTOP_FILE_PATH, EXEC FROM APPINFO WHERE EXEC LIKE :exePath"); + query.bindValue(":exePath", "%" + exePath.section('/', -1) + "%"); + + if (query.exec()) { + QMap execInfos; + while (query.next()) { + execInfos[query.value("DESKTOP_FILE_PATH").toString()] = query.value("EXEC").toString(); + desktopFilePath = query.value("DESKTOP_FILE_PATH").toString(); + } + //筛选后有多个结果时进一步过滤 + if (execInfos.size() > 1) { + desktopFilePath.clear(); + for (auto it = execInfos.constBegin(); it != execInfos.constEnd(); it++) { + if (it.key().startsWith(AUTOSTART_APP_DESKTOP_PATH + "/")) { + continue; + } + QStringList execlist = it.value().split(" ", QString::SkipEmptyParts); + for (QString &partOfExec : execlist) { + //remove the cmd option + if (partOfExec.contains("%")) { + continue; + } + //remove the " in cmd + if (partOfExec.contains("\"")) { + partOfExec.remove("\""); + } + //compare the binary path + if (partOfExec.contains("/") && exePath.contains("/")) { + if (partOfExec == exePath) { + desktopFilePath = it.key(); + break; + } + } else { + if ((partOfExec == exePath.section("/", -1)) || (partOfExec.section("/", -1) == exePath)) { + desktopFilePath = it.key(); + break; + } + } + } + if (!desktopFilePath.isEmpty()) { + break; + } + } + } + + if (!desktopFilePath.isEmpty()) { + qDebug() << "PID: " << pid << "Desktop file path: " << desktopFilePath; + } else { + qWarning() << "Can not find the desktop file of" << exePath << "by pid:" << pid; + } + } else { + qWarning() << "Fail to exec cmd" << query.lastQuery() << m_database.lastError(); + } + return desktopFilePath; +} + +QString AppDBManager::desktopFilePathFromName(const QString &desktopFileName) +{ + QString desktopFilePath; + QSqlQuery query(m_database); + query.setForwardOnly(true); + query.prepare("SELECT DESKTOP_FILE_PATH FROM APPINFO WHERE DESKTOP_FILE_PATH LIKE :desktopFilePath"); + query.bindValue(":desktopFilePath", "%/" + desktopFileName + ".desktop"); + + if (query.exec()) { + QStringList results; + while (query.next()) { + desktopFilePath = query.value("DESKTOP_FILE_PATH").toString(); + results.append(desktopFilePath); + } + //筛选后有多个结果时进一步过滤 + if (results.size() > 1) { + desktopFilePath.clear(); + for (const QString &path : results) { + if (path.startsWith(AUTOSTART_APP_DESKTOP_PATH + "/")) { + continue; + } else { + desktopFilePath = path; + } + + if (!desktopFilePath.isEmpty()) { + break; + } + } + } + + if (!desktopFilePath.isEmpty()) { + qDebug() << "Desktop file path is" << desktopFilePath; + } else { + qWarning() << "Can not find the desktop file by Name:" << desktopFileName; + } + } else { + qWarning() << "Fail to exec cmd" << query.lastQuery(); + } + return desktopFilePath; +} + +QString AppDBManager::tranWinIdToDesktopFilePath(const QDBusVariant &id) +{ + KWindowInfo info(id.variant().toULongLong(), NET::Properties(), NET::WM2AllProperties); + QString desktopFilePath; + if (info.valid()) { + QString classClass = info.windowClassClass(); //the 2nd part of WM_CLASS, specified by the application writer + QSqlQuery query(m_database); + query.setForwardOnly(true); + query.prepare("SELECT DESKTOP_FILE_PATH, START_UP_WMCLASS FROM APPINFO WHERE EXEC LIKE :classClass OR DESKTOP_FILE_PATH LIKE :classClass " + "OR LOWER(START_UP_WMCLASS)=:windowClassClass OR LOWER(LOCAL_NAME)=:windowClassClass"); + query.bindValue(":classClass", "%" + classClass + "%"); + query.bindValue(":windowClassClass", classClass.toLower()); + + if (query.exec()) { + QMap wmClassInfos; + while (query.next()) { + wmClassInfos[query.value("DESKTOP_FILE_PATH").toString()] = query.value("START_UP_WMCLASS").toString(); + desktopFilePath = query.value("DESKTOP_FILE_PATH").toString(); + } + //筛选后有多个结果时进一步过滤 + if (wmClassInfos.size() > 1) { + desktopFilePath.clear(); + for (auto it = wmClassInfos.constBegin(); it != wmClassInfos.constEnd(); it++) { + if (it.key().startsWith(AUTOSTART_APP_DESKTOP_PATH)) { + continue; + } + if (it.key().section("/", -1) == (classClass + ".desktop") || it.value().toLower() == classClass.toLower()) { + desktopFilePath = it.key(); + break; + } + } + } + + if (!desktopFilePath.isEmpty()) { + qDebug() << "WId:" << id.variant() << "Classclass of window:" << classClass << "Desktop file path:" << desktopFilePath; + } else { + qWarning() << "Can not find the desktop file by windowClassClass:" << classClass; + } + } else { + qWarning() << "Fail to exec cmd" << query.lastQuery(); + } + + if (desktopFilePath.isEmpty()) { + desktopFilePath = this->tranPidToDesktopFp(info.pid()); + } + } else { + qWarning() << "Cannot find desktop flie by WinId:" << id.variant() << "it is invalid" << id.variant().toULongLong(); + } + return desktopFilePath; +} + void AppDBManager::insertDBItem(const QString &desktopfd) { PendingAppInfo item(desktopfd, PendingAppInfo::HandleType::Insert); @@ -1009,285 +1607,39 @@ void AppDBManager::deleteDBItem(const QString &desktopfd) PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } -void AppDBManager::updateLocaleData(const QString &desktopfp) +void AppDBManager::updateLocaleData(const QString &desktopFilePath) { - PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateLocaleData); + PendingAppInfo item(desktopFilePath, PendingAppInfo::HandleType::UpdateLocaleData); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } -void AppDBManager::updateLaunchTimes(const QString &desktopfp) +void AppDBManager::updateLaunchTimes(const QString &desktopFilePath) { - PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateLaunchTimes); + PendingAppInfo item(desktopFilePath, PendingAppInfo::HandleType::UpdateLaunchTimes); item.setLaunchWillAdd(true); item.setLaunchTimes(1); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } -void AppDBManager::updateFavoritesState(const QString &desktopfp, int num) +void AppDBManager::updateFavoritesState(const QString &desktopFilePath, uint num) { - PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateFavorites); + PendingAppInfo item(desktopFilePath, PendingAppInfo::HandleType::UpdateFavorites); item.setFavorites(num); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } -void AppDBManager::updateTopState(const QString &desktopfp, int num) +void AppDBManager::updateTopState(const QString &desktopFilePath, uint num) { - PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateTop); + PendingAppInfo item(desktopFilePath, PendingAppInfo::HandleType::UpdateTop); item.setTop(num); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } -void AppDBManager::udpateLockState(const QString &desktopfp, int num) +void AppDBManager::setValue(const ApplicationInfoMap &infos2BSet) { - PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateTop); - item.setLock(num); - PendingAppInfoQueue::getAppInfoQueue().enqueue(item); -} - -bool AppDBManager::changeFavoriteAppPos(const QString &desktopfp, int pos) -{ - if (pos < 1) { - qWarning() << "To be moved to a invalid favorites pos , I quit!!"; - return false; - } - - bool res(true); - QSqlQuery sql(m_database); - QString cmd = QString("SELECT FAVORITES FROM APPINFO WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfp); - int previousPos = 0; - - //记录应用原位置 - if (!sql.exec(cmd)) { - qWarning() << "Fail to change favorite-app pos, because: " << m_database.lastError() << " when exec :" << cmd; - res = false; - } else { - if (sql.next()) { - previousPos = sql.value(0).toInt(); - - if (previousPos < 1) { - qWarning() << QString("app: %1 is not a favorites app, I quit!!").arg(desktopfp); - } - - if (previousPos == pos) { - qDebug() << "favorite app's pos has no changes!"; - return res; - } - - cmd = QString("SELECT DESKTOP_FILE_PATH, FAVORITES FROM APPINFO WHERE FAVORITES BETWEEN MIN(%1, %2) AND MAX(%1, %2)") - .arg(previousPos) - .arg(pos); - } else { - qWarning() << "Fail to change favorite-app pos when exec next, because: " << m_database.lastError(); - } - } - - //更新原位置和新位置之间的应用的位置 - if (!sql.exec(cmd)) { - qWarning() << "Fail to change favorite-app pos, because: " << m_database.lastError() << " when exec :" << cmd; - res = false; - } else { - while (sql.next()) { - if (sql.value("FAVORITES").toInt() == previousPos) { - this->updateFavoritesState(desktopfp, pos); - continue; - } - if (previousPos > pos) { - this->updateFavoritesState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("FAVORITES").toInt() + 1); - } else { - this->updateFavoritesState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("FAVORITES").toInt() - 1); - } - - } - } - - return res; -} - -bool AppDBManager::changeTopAppPos(const QString &desktopfp, int pos) -{ - if (pos < 1) { - qWarning() << "To be moved to a invalid top pos, I quit!!"; - return false; - } - - bool res(true); - QSqlQuery sql(m_database); - QString cmd = QString("SELECT TOP FROM APPINFO WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfp); - int previousPos = 0; - - //记录应用原位置 - if (!sql.exec(cmd)) { - qWarning() << "Fail to change top-app pos, because: " << m_database.lastError() << " when exec :" << cmd; - res = false; - } else { - if (sql.next()) { - previousPos = sql.value(0).toInt(); - - if (previousPos < 1) { - qWarning() << QString("app: %1 is not a favorites app, I quit!!").arg(desktopfp); - res = false; - return res; - } - - if (previousPos == pos) { - qDebug() << "top app's pos has no changes!"; - res = false; - return res; - } - - cmd = QString("SELECT DESKTOP_FILE_PATH, TOP FROM APPINFO WHERE TOP BETWEEN MIN(%1, %2) AND MAX(%1, %2)") - .arg(previousPos) - .arg(pos); - } else { - qWarning() << "Fail to change top-app pos when exec next, because: " << m_database.lastError(); - } - } - - //更新原位置和新位置之间的应用的位置 - if (!sql.exec(cmd)) { - qWarning() << "Fail to change top-app pos, because: " << m_database.lastError() << " when exec :" << cmd; - res = false; - } else { - while (sql.next()) { - if (sql.value("TOP").toInt() == previousPos) { - this->updateTopState(desktopfp, pos); - continue; - } - if (previousPos > pos) { - this->updateTopState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("TOP").toInt() + 1); - } else { - this->updateTopState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("TOP").toInt() - 1); - } - - } - } - - return res; -} - -QVector AppDBManager::getAppInfoResults() -{ - QVector appInfoResults; - QSqlQuery sql(m_database); - QString cmd = QString("SELECT DESKTOP_FILE_PATH,LOCAL_NAME,ICON,CATEGORY,TOP,FAVORITES,LAUNCH_TIMES,LOCK,FIRST_LETTER_ALL FROM APPINFO"); - - if (sql.exec(cmd)) { - while (sql.next()) { - AppInfoResult result; - result.desktopPath = sql.value("DESKTOP_FILE_PATH").toString(); - result.appLocalName = sql.value("LOCAL_NAME").toString(); - result.iconName = sql.value("ICON").toString(); - result.category = sql.value("CATEGORY").toString(); - result.top = sql.value("TOP").toInt(); - result.favorite = sql.value("FAVORITES").toInt(); - result.launchTimes = sql.value("LAUNCH_TIMES").toInt(); - result.lock = sql.value("LOCK").toInt(); - result.firstLetter = sql.value("FIRST_LETTER_ALL").toString(); - appInfoResults.append(std::move(result)); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - - return appInfoResults; -} - -int AppDBManager::getAppLockState(const QString &desktopfp) -{ - int lockState = -1; - QSqlQuery sql(m_database); - QString cmd = QString("SELECT LOCK FROM APPINFO WHERE DESKTOP_FILE_PATH='%0'") - .arg(desktopfp); - - if (sql.exec(cmd)) { - if (sql.next()) { - lockState = sql.value(0).toInt(); - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - - return lockState; -} - -int AppDBManager::getAppTopState(const QString &desktopfp) -{ - int topState = -1; - QSqlQuery sql(m_database); - QString cmd = QString("SELECT TOP FROM APPINFO WHERE DESKTOP_FILE_PATH='%0'") - .arg(desktopfp); - - if (sql.exec(cmd)) { - if (sql.next()) { - topState = sql.value(0).toInt(); - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - - return topState; -} - -int AppDBManager::getAppLaunchedState(const QString &desktopfp) -{ - int launchedState = -1; - QSqlQuery sql(m_database); - QString cmd = QString("SELECT LAUNCHED FROM APPINFO WHERE DESKTOP_FILE_PATH='%0'") - .arg(desktopfp); - - if (sql.exec(cmd)) { - if (sql.next()) { - launchedState = sql.value(0).toInt(); - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - - return launchedState; -} - -int AppDBManager::getAppFavoriteState(const QString &desktopfp) -{ - int favoriteState = -1; - QSqlQuery sql(m_database); - QString cmd = QString("SELECT FAVORITES FROM APPINFO WHERE DESKTOP_FILE_PATH='%0'") - .arg(desktopfp); - - if (sql.exec(cmd)) { - if (sql.next()) { - favoriteState = sql.value(0).toInt(); - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - - return favoriteState; -} - -QString AppDBManager::getAppCategory(const QString &desktopfp) -{ - QString category; - QSqlQuery sql(m_database); - QString cmd = QString("SELECT CATEGORY FROM APPINFO WHERE DESKTOP_FILE_PATH='%0'") - .arg(desktopfp); - - if (sql.exec(cmd)) { - if (sql.next()) { - category = sql.value(0).toString(); - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - } else { - qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); - } - - return category; + for (const QString &desktopFilePath : infos2BSet.keys()) { + PendingAppInfo item(desktopFilePath, PendingAppInfo::SetValue); + item.setValue(infos2BSet); + PendingAppInfoQueue::getAppInfoQueue().enqueue(item); + } } diff --git a/ukui-search-app-data-service/app-db-manager.h b/ukui-search-app-data-service/app-db-manager.h index f0ae476..2fd1269 100644 --- a/ukui-search-app-data-service/app-db-manager.h +++ b/ukui-search-app-data-service/app-db-manager.h @@ -1,10 +1,24 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef APPDBMANAGER_H #define APPDBMANAGER_H - -#include "app-db-common.h" -#include "pending-app-info-queue.h" -#include "file-system-watcher.h" - #include #include #include @@ -16,11 +30,18 @@ #include #include #include -//#include -//#include +#include +#include "pending-app-info-queue.h" +#include "file-system-watcher.h" +#include "application-property.h" +#define APP_DATABASE_PATH QDir::homePath()+"/.config/org.ukui/ukui-search/appdata/" +#define APP_DATABASE_NAME "app-info.db" #define CONNECTION_NAME QLatin1String("ukss-appdb-connection") -static const QString APP_DATABASE_VERSION = QStringLiteral("1.0"); +/** + * changelog(1.2 to 1.3): Add the START_UP_WMCLASS field in order to find desktop file path by the windowClassClass. + */ +static const QString APP_DATABASE_VERSION = QStringLiteral("1.3"); namespace UkuiSearch { /** @@ -28,18 +49,6 @@ namespace UkuiSearch { * 功能:1.遍历并且监听desktop文件目录,建立并且维护应用信息数据库。 * 2.监听应用安装,打开事件,收藏等事件,更新数据库 */ -class NameString { -public: - explicit NameString(const QString &str_) : app_name(str_) {} - NameString() = default; - QString app_name; - bool operator<(const NameString& name) const { - return this->app_name.length() <= name.app_name.length(); - } - bool operator==(const NameString& name) const { - return this->app_name == name.app_name; - } -}; class AppDBManager : public QThread { @@ -56,7 +65,7 @@ public: static AppDBManager *getInstance(); //刷新数据库数据 - void refreshAllData2DB(); + void refreshAllData2DB(const QStringList &appPaths, bool dbVersionNeedUpdate = false); //获取desktop文件的md5值 QString getAppDesktopMd5(const QString &desktopfd); @@ -64,42 +73,37 @@ public: bool startTransaction(); bool startCommit(); - bool handleDBItemInsert(const QString &desktopfd); - bool handleDBItemUpdate(const QString &desktopfd); - bool handleDBItemDelete(const QString &desktopfd); + bool handleDBItemInsert(const QString &desktopFilePath); + bool handleDBItemUpdate(const QString &desktopFilePath); + bool handleDBItemDelete(const QString &desktopFilePath); - bool handleLocaleDataUpdate(const QString &desktopPath); - bool handleLaunchTimesUpdate(const QString &desktopfp, int num); - bool handleFavoritesStateUpdate(const QString &desktopfp, int num); - bool handleTopStateUpdate(const QString &desktopfp, int num); - bool handleLockStateUpdate(const QString &desktopfp, int num); + bool handleLocaleDataUpdate(const QString &desktopFilePath); + bool handleLaunchTimesUpdate(const QString &desktopFilePath, int num = 1); + bool handleFavoritesStateUpdate(const QString &desktopFilePath, const uint num); + bool handleTopStateUpdate(const QString &desktopFilePath, const uint num); + bool handleLockStateUpdate(const QString &desktopFilePath, int num); + void handleDataBaseRefresh(const QStringList &appPaths, bool dbVersionNeedUpdate); + + bool handleValueSet(const ApplicationInfoMap appInfoMap); public Q_SLOTS: + //通过pid查找对应的desktop文件 + QString tranPidToDesktopFp(uint pid); + QString desktopFilePathFromName(const QString &desktopFileName); + QString tranWinIdToDesktopFilePath(const QDBusVariant &id); + //对数据库单条所有信息进行增删改 void insertDBItem(const QString &desktopfd); void updateDBItem(const QString &desktopfd); void deleteDBItem(const QString &desktopfd); //对数据库某字段进行update - void updateLocaleData(const QString &desktopfp); - void updateLaunchTimes(const QString &desktopfp); - void updateFavoritesState(const QString &desktopfp, int num); - void updateTopState(const QString &desktopfp, int num); - void udpateLockState(const QString &desktopfp, int num); + void updateLocaleData(const QString &desktopFilePath); + void updateLaunchTimes(const QString &desktopFilePath); + void updateFavoritesState(const QString &desktopFilePath, uint num = 1); + void updateTopState(const QString &desktopFilePath, uint num = 1); - //拖动改变置顶和收藏应用位置 - bool changeFavoriteAppPos(const QString &desktopfp, int pos); - bool changeTopAppPos(const QString &desktopfp, int pos); - - //获取数据库中全部信息 - QVector getAppInfoResults(); - - //查询某应用的某个字段的值 - int getAppLockState(const QString &desktopfp); - int getAppTopState(const QString &desktopfp); - int getAppLaunchedState(const QString &desktopfp); - int getAppFavoriteState(const QString &desktopfp); - QString getAppCategory(const QString &desktopfp); + void setValue(const ApplicationInfoMap &infos2BSet); protected: void run() override; @@ -114,7 +118,6 @@ private: //数据库查找指定字段不存在则添加到最后并设置初始值 bool addItem2BackIfNotExist(QString itemName, QString itemDataType, QVariant defult = QVariant()); - //链接数据库 bool openDataBase(); //刷新数据库 @@ -125,11 +128,12 @@ private: //创建数据库字段 void buildAppInfoDB(); - //暂时弃用 - void updateAppInfoDB(); - void getAllDesktopFilePath(QString path); - void getFilePathList(QStringList &pathList); - void getInstallAppMap(QMap &installAppMap); + //初始化fileSystemWatcher + void initFileSystemWatcher(); + + //处理置顶收藏移动位置 + bool handleChangeFavoritesPos(const QString &desktopFilePath, const uint pos, const uint previousPos, ApplicationInfoMap &updatedInfo); + bool handleChangeTopPos(const QString &desktopFilePath, uint pos, const uint previousPos, ApplicationInfoMap &updatedInfo); private: static QMutex s_mutex; @@ -150,6 +154,33 @@ private: QString m_snapdPath; FileSystemWatcher *m_snapdWatcher = nullptr; + //数据库当前所有字段 + QMap m_namesOfAppinfoTable = { + {"DESKTOP_FILE_PATH", "TEXT"}, + {"MODIFYED_TIME", "TEXT"}, + {"INSERT_TIME","TEXT"}, + {"LOCAL_NAME", "TEXT"}, + {"NAME_EN", "TEXT"}, + {"NAME_ZH", "TEXT"}, + {"PINYIN_NAME", "TEXT"}, + {"FIRST_LETTER_OF_PINYIN", "TEXT"}, + {"FIRST_LETTER_ALL", "TEXT"}, + {"ICON", "TEXT"}, + {"TYPE", "TEXT"}, + {"CATEGORY", "TEXT"}, + {"EXEC", "TEXT"}, + {"COMMENT", "TEXT"}, + {"MD5", "TEXT"}, + {"LAUNCH_TIMES", "INT"}, + {"FAVORITES", "INT"}, + {"LAUNCHED", "INT"}, + {"TOP", "INT"}, + {"LOCK", "INT"}, + {"DONT_DISPLAY", "INT"}, + {"AUTO_START", "INT"}, + {"START_UP_WMCLASS", "TEXT"} + }; + //应用黑名单 QStringList m_excludedDesktopfiles = { "/usr/share/applications/software-properties-livepatch.desktop", @@ -199,13 +230,11 @@ private: "/usr/share/applications/screensavers" }; - //暂时弃用 - QMap m_installAppMap; - Q_SIGNALS: //操作数据库 - void appDBItemUpdate(const AppInfoResult&); - void appDBItemAdd(const AppInfoResult&); + void appDBItemUpdate(const ApplicationInfoMap&); + void appDBItemUpdateAll(const QString&); + void appDBItemAdd(const QString&); void appDBItemDelete(const QString&); void finishHandleAppDB(); diff --git a/ukui-search-app-data-service/convert-winid-to-desktop.cpp b/ukui-search-app-data-service/convert-winid-to-desktop.cpp index eaa32c3..cf5a614 100755 --- a/ukui-search-app-data-service/convert-winid-to-desktop.cpp +++ b/ukui-search-app-data-service/convert-winid-to-desktop.cpp @@ -22,6 +22,8 @@ #include #include "convert-winid-to-desktop.h" +static const char* GET_DESKTOP_EXEC_NAME_MAIN = "cat %s | awk '{if($1~\"Exec=\")if($2~\"\%\"){print $1} else print}' | cut -d '=' -f 2"; + ConvertWinidToDesktop::ConvertWinidToDesktop(QObject *parent) : QObject(parent) { } @@ -176,7 +178,7 @@ QString ConvertWinidToDesktop::compareCmdExec(QFileInfoList list) if (!fileInfo.filePath().endsWith(".desktop")) { continue; } - cmd.sprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data()); + cmd.asprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data()); QString desktopFileExeName = getDesktopFileName(cmd).remove("\n"); if (desktopFileExeName.isEmpty()) { @@ -219,7 +221,7 @@ QString ConvertWinidToDesktop::compareCmdName(QFileInfoList list) if (!fileInfo.filePath().endsWith(".desktop")) { continue; } - cmd.sprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data()); + cmd.asprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data()); QString desktopFileExeName = getDesktopFileName(cmd).remove("\n"); if (desktopFileExeName.isEmpty()) { @@ -265,7 +267,7 @@ QString ConvertWinidToDesktop::containsName(QFileInfoList list) continue; } - cmd.sprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data()); + cmd.asprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data()); QString desktopFileExeName = getDesktopFileName(cmd).remove("\n"); pathDesktopName = pathDesktopName.mid(pathDesktopName.lastIndexOf("/") + 1); diff --git a/ukui-search-app-data-service/convert-winid-to-desktop.h b/ukui-search-app-data-service/convert-winid-to-desktop.h index 38c30ca..383d6a4 100755 --- a/ukui-search-app-data-service/convert-winid-to-desktop.h +++ b/ukui-search-app-data-service/convert-winid-to-desktop.h @@ -31,7 +31,6 @@ #define PEONY_HOME "/usr/share/applications/peony-home.desktop" #define PEONY_MAIN "/usr/share/applications/peony.desktop" -#define GET_DESKTOP_EXEC_NAME_MAIN "cat %s | awk '{if($1~\"Exec=\")if($2~\"\%\"){print $1} else print}' | cut -d '=' -f 2" #define ANDROID_FILE_PATH "/.local/share/applications/" #define ANDROID_APP_CURRENT "/.local/share/applications/." #define ANDROID_APP_UPER "/.local/share/applications/.." diff --git a/ukui-search-app-data-service/dbus/org.ukui.AppDatabase.xml b/ukui-search-app-data-service/dbus/org.ukui.AppDatabase.xml new file mode 100644 index 0000000..84f8636 --- /dev/null +++ b/ukui-search-app-data-service/dbus/org.ukui.AppDatabase.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ukui-search-app-data-service/main.cpp b/ukui-search-app-data-service/main.cpp index ca8eff3..acaef86 100644 --- a/ukui-search-app-data-service/main.cpp +++ b/ukui-search-app-data-service/main.cpp @@ -1,57 +1,31 @@ -#include -#include -#include -#include +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + #include "ukui-search-app-data-service.h" +#include "log-utils.h" using namespace UkuiSearch; -void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) -{ - QByteArray localMsg = msg.toLocal8Bit(); - QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit(); - - bool showDebug = true; - QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search-app-data-service.log"; - if (!QFile::exists(logFilePath)) { - showDebug = false; - } - FILE *log_file = nullptr; - - if (showDebug) { - log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+"); - } - - const char *file = context.file ? context.file : ""; - const char *function = context.function ? context.function : ""; - switch (type) { - case QtDebugMsg: - if (!log_file) { - break; - } - fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtInfoMsg: - fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtWarningMsg: - fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtCriticalMsg: - fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtFatalMsg: - fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - } - - if (log_file) - fclose(log_file); -} - int main(int argc, char *argv[]) { // Output log to file - qInstallMessageHandler(messageOutput); + LogUtils::initLogFile("ukui-search-app-data-service"); + qInstallMessageHandler(LogUtils::messageOutput); #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); diff --git a/ukui-search-app-data-service/pending-app-info-queue.cpp b/ukui-search-app-data-service/pending-app-info-queue.cpp index 48d5442..87ee644 100644 --- a/ukui-search-app-data-service/pending-app-info-queue.cpp +++ b/ukui-search-app-data-service/pending-app-info-queue.cpp @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #include "pending-app-info-queue.h" #include "app-db-manager.h" @@ -19,6 +37,10 @@ void PendingAppInfoQueue::enqueue(const PendingAppInfo &appInfo) if (index == -1) { m_cache << appInfo; } else { + //刷新数据库操作直接插入 + if (appInfo.handleType() == PendingAppInfo::RefreshDataBase) { + m_cache << appInfo; + } //要插入项操作类型为删除,清除之前所有操作,替换为删除 if (appInfo.handleType() == PendingAppInfo::Delete) { m_cache.removeAll(appInfo); @@ -28,6 +50,8 @@ void PendingAppInfoQueue::enqueue(const PendingAppInfo &appInfo) if (appInfo.handleType() == PendingAppInfo::Insert) { m_cache << appInfo; } + } else if (appInfo.handleType() == PendingAppInfo::SetValue) { + m_cache << appInfo; } else if (m_cache[index].handleType() <= PendingAppInfo::UpdateLocaleData and appInfo.handleType() <= PendingAppInfo::UpdateLocaleData) { //类型为insert, updateall, updatelocaledata时,设置为优先级高的操作类型 @@ -124,57 +148,55 @@ void PendingAppInfoQueue::processCache() return; } - if (AppDBManager::getInstance()->startTransaction()) { - for (const PendingAppInfo &info : m_pendingAppInfos) { - PendingAppInfo::HandleTypes handleTypes = info.handleType(); - if (handleTypes <= PendingAppInfo::UpdateLocaleData) { - switch (handleTypes) { - case PendingAppInfo::Delete: - AppDBManager::getInstance()->handleDBItemDelete(info.path()); - break; - case PendingAppInfo::Insert: - AppDBManager::getInstance()->handleDBItemInsert(info.path()); - break; - case PendingAppInfo::UpdateAll: - AppDBManager::getInstance()->handleDBItemUpdate(info.path()); - break; - case PendingAppInfo::UpdateLocaleData: - AppDBManager::getInstance()->handleLocaleDataUpdate(info.path()); - break; - default: - break; - } - } else { - if (handleTypes & PendingAppInfo::Insert) { - AppDBManager::getInstance()->handleDBItemInsert(info.path()); - } - if (handleTypes & PendingAppInfo::UpdateAll) { - AppDBManager::getInstance()->handleDBItemUpdate(info.path()); - } - if (handleTypes & PendingAppInfo::UpdateLocaleData) { - AppDBManager::getInstance()->handleLocaleDataUpdate(info.path()); - } - if (handleTypes & PendingAppInfo::UpdateLaunchTimes) { - AppDBManager::getInstance()->handleLaunchTimesUpdate(info.path(), info.launchTimes()); - } - if (handleTypes & PendingAppInfo::UpdateFavorites) { - AppDBManager::getInstance()->handleFavoritesStateUpdate(info.path(), info.favoritesState()); - } - if (handleTypes & PendingAppInfo::UpdateTop) { - AppDBManager::getInstance()->handleTopStateUpdate(info.path(), info.topState()); - } - if (handleTypes & PendingAppInfo::UpdateLock) { - AppDBManager::getInstance()->handleLockStateUpdate(info.path(), info.lockState()); - } + for (const PendingAppInfo &info : m_pendingAppInfos) { + PendingAppInfo::HandleTypes handleTypes = info.handleType(); + if (handleTypes <= PendingAppInfo::UpdateLocaleData || handleTypes == PendingAppInfo::RefreshDataBase || handleTypes == PendingAppInfo::SetValue) { + switch (handleTypes) { + case PendingAppInfo::Delete: + AppDBManager::getInstance()->handleDBItemDelete(info.path()); + break; + case PendingAppInfo::Insert: + AppDBManager::getInstance()->handleDBItemInsert(info.path()); + break; + case PendingAppInfo::UpdateAll: + AppDBManager::getInstance()->handleDBItemUpdate(info.path()); + break; + case PendingAppInfo::UpdateLocaleData: + AppDBManager::getInstance()->handleLocaleDataUpdate(info.path()); + break; + case PendingAppInfo::RefreshDataBase: + AppDBManager::getInstance()->handleDataBaseRefresh(info.pathsNeedRefreshData(), info.dbVersionNeedUpdate()); + break; + case PendingAppInfo::SetValue: + AppDBManager::getInstance()->handleValueSet(info.value2BSet()); + break; + default: + break; + } + } else { + if (handleTypes & PendingAppInfo::Insert) { + AppDBManager::getInstance()->handleDBItemInsert(info.path()); + } + if (handleTypes & PendingAppInfo::UpdateAll) { + AppDBManager::getInstance()->handleDBItemUpdate(info.path()); + } + if (handleTypes & PendingAppInfo::UpdateLocaleData) { + AppDBManager::getInstance()->handleLocaleDataUpdate(info.path()); + } + if (handleTypes & PendingAppInfo::UpdateLaunchTimes) { + AppDBManager::getInstance()->handleLaunchTimesUpdate(info.path(), info.launchTimes()); + } + if (handleTypes & PendingAppInfo::UpdateFavorites) { + AppDBManager::getInstance()->handleFavoritesStateUpdate(info.path(), info.favoritesState()); + } + if (handleTypes & PendingAppInfo::UpdateTop) { + AppDBManager::getInstance()->handleTopStateUpdate(info.path(), info.topState()); } } - - if (AppDBManager::getInstance()->startCommit()) { - Q_EMIT AppDBManager::getInstance()->finishHandleAppDB(); - } - - m_pendingAppInfos.clear(); - m_pendingAppInfos.squeeze(); } + Q_EMIT AppDBManager::getInstance()->finishHandleAppDB(); + + m_pendingAppInfos.clear(); + m_pendingAppInfos.squeeze(); } diff --git a/ukui-search-app-data-service/pending-app-info-queue.h b/ukui-search-app-data-service/pending-app-info-queue.h index fa1e242..fc2b4b8 100644 --- a/ukui-search-app-data-service/pending-app-info-queue.h +++ b/ukui-search-app-data-service/pending-app-info-queue.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef PENDINGAPPINFOQUEUE_H #define PENDINGAPPINFOQUEUE_H diff --git a/ukui-search-app-data-service/pending-app-info.h b/ukui-search-app-data-service/pending-app-info.h index 51e11c7..503c66f 100644 --- a/ukui-search-app-data-service/pending-app-info.h +++ b/ukui-search-app-data-service/pending-app-info.h @@ -1,8 +1,29 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef PENDINGAPPINFO_H #define PENDINGAPPINFO_H #include +#include #include +#include "application-property.h" namespace UkuiSearch { @@ -17,36 +38,43 @@ public: UpdateLaunchTimes = 1u << 3, UpdateFavorites = 1u << 4, UpdateTop = 1u << 5, - UpdateLock = 1u << 6 + RefreshDataBase = 1u << 6, + SetValue = 1u << 7 }; Q_DECLARE_FLAGS(HandleTypes, HandleType) PendingAppInfo() = default; - PendingAppInfo(QString desktopfp, HandleTypes type, int favorites = -1, int top = -1, int lock = -1, bool addLaunch = false, int launchTimes = 0) + PendingAppInfo(QString desktopfp, HandleTypes type, + int favorites = -1, int top = -1, + bool addLaunch = false, int launchTimes = 0) : m_desktopfp(desktopfp), m_handleType(type), m_favoritesState(favorites), m_topState(top), - m_lockState(lock), m_willAddLaunch(addLaunch), m_launchTimes(launchTimes) {} QString path() const {return m_desktopfp;} + QStringList pathsNeedRefreshData() const {return m_pathsNeedRefreshData;} HandleTypes handleType() const {return m_handleType;} int favoritesState() const {return m_favoritesState;} int topState() const {return m_topState;} - int lockState() const {return m_lockState;} int launchTimes() const {return m_launchTimes;} bool willAddLunchTimes() const {return m_willAddLaunch;} + bool dbVersionNeedUpdate() const {return m_dbVersionNeedUpdate;} + ApplicationInfoMap value2BSet() const {return m_appInfoMap;} - void setHandleType(const PendingAppInfo & info) {m_handleType = info.handleType();} + void setDesktopFp(const QString& desktopfp) {m_desktopfp = desktopfp;} + void setHandleType(const PendingAppInfo& info) {m_handleType = info.handleType();} void setHandleType(HandleTypes type) {m_handleType = type;} void setFavorites(int favoritesState) {m_favoritesState = favoritesState;} void setTop(int top) {m_topState = top;} - void setLock(int lock) {m_lockState = lock;} void setLaunchWillAdd(bool willAdd) {m_willAddLaunch = willAdd;} void setLaunchTimes(int times) {m_launchTimes = times;} - void merge(const PendingAppInfo &info) + void setPathsNeedRefreshData (const QStringList& paths) {m_pathsNeedRefreshData = paths;} + void setDBUpdate(bool versionNeedUpdate) {m_dbVersionNeedUpdate = versionNeedUpdate;} + void setValue(const ApplicationInfoMap infoMap) {m_appInfoMap = infoMap;} + void merge(const PendingAppInfo& info) { m_handleType |= info.handleType(); @@ -58,9 +86,6 @@ public: m_topState = info.topState(); } - if (info.lockState() != -1) { - m_lockState = info.lockState(); - } if (info.willAddLunchTimes()) { m_launchTimes++; } @@ -72,11 +97,13 @@ public: private: QString m_desktopfp; HandleTypes m_handleType; - int m_favoritesState; - int m_topState; - int m_lockState; - bool m_willAddLaunch; - int m_launchTimes; + int m_favoritesState = -1; + int m_topState = -1; + bool m_willAddLaunch = false; + int m_launchTimes = 0; + QStringList m_pathsNeedRefreshData; + bool m_dbVersionNeedUpdate = false; + ApplicationInfoMap m_appInfoMap; }; } diff --git a/ukui-search-app-data-service/signal-transformer.cpp b/ukui-search-app-data-service/signal-transformer.cpp index 6cc081e..7068dcf 100644 --- a/ukui-search-app-data-service/signal-transformer.cpp +++ b/ukui-search-app-data-service/signal-transformer.cpp @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #include "signal-transformer.h" QMutex SignalTransformer::s_mutex; @@ -8,33 +26,105 @@ SignalTransformer *SignalTransformer::getTransformer() return instance; } -void SignalTransformer::handleItemInsert(const AppInfoResult &item) +void SignalTransformer::transform() { - QMutexLocker locker(&s_mutex); - m_items2BInsert.append(item); + switch (m_signalType) { + case Delete: + if (!m_items2BDelete.isEmpty()) { + Q_EMIT this->appDBItemsDelete(m_items2BDelete); + m_items2BDelete.clear(); + } + break; + case Insert: + if (!m_items2BInsert.isEmpty()) { + Q_EMIT this->appDBItemsAdd(m_items2BInsert); + m_items2BInsert.clear(); + } + break; + case UpdateAll: + if (!m_items2BUpdateAll.isEmpty()) { + Q_EMIT this->appDBItemsUpdateAll(m_items2BUpdateAll); + m_items2BUpdateAll.clear(); + } + break; + case Update: + if (!m_items2BUpdate.isEmpty()) { + Q_EMIT this->appDBItemsUpdate(m_items2BUpdate); + m_items2BUpdate.clear(); + } + break; + default: + break; + } } -void SignalTransformer::handleItemUpdate(const AppInfoResult &item) +void SignalTransformer::handleItemInsert(const QString &desktopFilePath) { QMutexLocker locker(&s_mutex); - m_items2BUpdate.append(item); + if ((m_signalType ^ SignalType::Invalid) && (m_signalType ^ SignalType::Insert)) { + transform(); + } + m_signalType = SignalType::Insert; + m_items2BInsert.append(desktopFilePath); } -void SignalTransformer::handleItemDelete(const QString &desktopfp) +void SignalTransformer::handleItemUpdate(const ApplicationInfoMap &item) { QMutexLocker locker(&s_mutex); - m_items2BDelete.append(desktopfp); + if ((m_signalType ^ SignalType::Invalid) && (m_signalType ^ SignalType::Update)) { + transform(); + } + m_signalType = SignalType::Update; + for(auto it = item.constBegin(); it != item.constEnd(); it++) { + ApplicationPropertyMap propertyinfo = it.value(); + for (auto i = propertyinfo.constBegin(); i != propertyinfo.constEnd(); i++) { + m_items2BUpdate[it.key()].insert(i.key(), i.value()); + } + } +} + +void SignalTransformer::handleItemUpdateAll(const QString &desktopFilePath) +{ + QMutexLocker locker(&s_mutex); + if ((m_signalType ^ SignalType::Invalid) && (m_signalType ^ SignalType::UpdateAll)) { + transform(); + } + m_signalType = SignalType::UpdateAll; + m_items2BUpdateAll.append(desktopFilePath); +} + +void SignalTransformer::handleItemDelete(const QString &desktopFilePath) +{ + QMutexLocker locker(&s_mutex); + if ((m_signalType ^ SignalType::Invalid) && (m_signalType ^ SignalType::Delete)) { + transform(); + } + m_signalType = SignalType::Delete; + m_items2BDelete.append(desktopFilePath); } void SignalTransformer::handleSignalTransform() { QMutexLocker locker(&s_mutex); - Q_EMIT this->appDBItemsAdd(m_items2BInsert); - Q_EMIT this->appDBItemsUpdate(m_items2BUpdate); - Q_EMIT this->appDBItemsDelete(m_items2BDelete); - m_items2BInsert.clear(); - m_items2BUpdate.clear(); - m_items2BDelete.clear(); + if (!m_items2BInsert.isEmpty()) { + Q_EMIT this->appDBItemsAdd(m_items2BInsert); + m_items2BInsert.clear(); + } + + if (!m_items2BUpdate.isEmpty()) { + Q_EMIT this->appDBItemsUpdate(m_items2BUpdate); + m_items2BUpdate.clear(); + } + + if (!m_items2BUpdateAll.isEmpty()) { + Q_EMIT this->appDBItemsUpdateAll(m_items2BUpdateAll); + m_items2BUpdateAll.clear(); + } + + if (!m_items2BDelete.isEmpty()) { + Q_EMIT this->appDBItemsDelete(m_items2BDelete); + m_items2BDelete.clear(); + } } SignalTransformer::SignalTransformer(QObject *parent) : QObject(parent) @@ -42,6 +132,7 @@ SignalTransformer::SignalTransformer(QObject *parent) : QObject(parent) connect(AppDBManager::getInstance(), &AppDBManager::appDBItemAdd, this, &SignalTransformer::handleItemInsert); connect(AppDBManager::getInstance(), &AppDBManager::appDBItemUpdate, this, &SignalTransformer::handleItemUpdate); connect(AppDBManager::getInstance(), &AppDBManager::appDBItemDelete, this, &SignalTransformer::handleItemDelete); + connect(AppDBManager::getInstance(), &AppDBManager::appDBItemUpdateAll, this, &SignalTransformer::handleItemUpdateAll); connect(AppDBManager::getInstance(), &AppDBManager::finishHandleAppDB, this, &SignalTransformer::handleSignalTransform); } diff --git a/ukui-search-app-data-service/signal-transformer.h b/ukui-search-app-data-service/signal-transformer.h index 6bb4ef4..e513a64 100644 --- a/ukui-search-app-data-service/signal-transformer.h +++ b/ukui-search-app-data-service/signal-transformer.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + */ #ifndef SIGNALTRANSFORMER_H #define SIGNALTRANSFORMER_H @@ -15,29 +34,40 @@ class SignalTransformer : public QObject Q_OBJECT public: + enum SignalType{ + Invalid = -1, + Delete = 0, + Insert, + UpdateAll, + Update + }; static SignalTransformer *getTransformer(); static QMutex s_mutex; - public Q_SLOTS: - void handleItemInsert(const AppInfoResult &item); - void handleItemUpdate(const AppInfoResult &item); - void handleItemDelete(const QString &desktopfp); + void handleItemUpdate(const ApplicationInfoMap &item); + void handleItemUpdateAll(const QString &desktopFilePath); + void handleItemInsert(const QString &desktopFilePath); + void handleItemDelete(const QString &desktopFilePath); void handleSignalTransform(); private: SignalTransformer(QObject *parent = nullptr); SignalTransformer(const SignalTransformer &) = delete; SignalTransformer& operator = (const SignalTransformer&) = delete; + void transform(); - QVector m_items2BUpdate; - QVector m_items2BInsert; + ApplicationInfoMap m_items2BUpdate; + QStringList m_items2BUpdateAll; + QStringList m_items2BInsert; QStringList m_items2BDelete; + SignalType m_signalType = SignalType::Invalid; Q_SIGNALS: - void appDBItemsUpdate(QVector); - void appDBItemsAdd(QVector); - void appDBItemsDelete(QStringList); + void appDBItemsUpdateAll(const QStringList&); + void appDBItemsUpdate(const ApplicationInfoMap&); + void appDBItemsAdd(const QStringList&); + void appDBItemsDelete(const QStringList&); }; #endif // SIGNALTRANSFORMER_H diff --git a/ukui-search-app-data-service/ukui-search-app-data-service.cpp b/ukui-search-app-data-service/ukui-search-app-data-service.cpp index 592a1c8..054c36b 100644 --- a/ukui-search-app-data-service/ukui-search-app-data-service.cpp +++ b/ukui-search-app-data-service/ukui-search-app-data-service.cpp @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #include "ukui-search-app-data-service.h" #include "app-db-manager.h" #include "signal-transformer.h" @@ -20,11 +38,11 @@ UkuiSearchAppDataService::UkuiSearchAppDataService(int &argc, char *argv[], cons if (!this->isRunning()) { qDebug() << "First running, I'm in app-db manager dbus rigister."; - qRegisterMetaType("AppInfoResult"); - qRegisterMetaType>("QVector"); + qRegisterMetaType("ApplicationPropertyMap"); + qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType>(); + qRegisterMetaType("ApplicationInfoMap"); + qDBusRegisterMetaType(); AppDBManager::getInstance(); @@ -33,7 +51,7 @@ UkuiSearchAppDataService::UkuiSearchAppDataService(int &argc, char *argv[], cons qCritical() << "QDbus register service failed reason:" << sessionBus.lastError(); } - if(!sessionBus.registerObject("/org/ukui/search/appDataBase/dbManager", AppDBManager::getInstance(), QDBusConnection::ExportAllSlots)) { + if(!sessionBus.registerObject("/org/ukui/search/appDataBase/dbManager", AppDBManager::getInstance(), QDBusConnection::ExportAdaptors)) { qCritical() << "ukui-search-app-db-manager dbus register object failed reason:" << sessionBus.lastError(); } diff --git a/ukui-search-app-data-service/ukui-search-app-data-service.h b/ukui-search-app-data-service/ukui-search-app-data-service.h index e50fe71..9512ae7 100644 --- a/ukui-search-app-data-service/ukui-search-app-data-service.h +++ b/ukui-search-app-data-service/ukui-search-app-data-service.h @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #ifndef UkuiSearchAppDataService_H #define UkuiSearchAppDataService_H diff --git a/ukui-search-app-data-service/ukui-search-app-data-service.pro b/ukui-search-app-data-service/ukui-search-app-data-service.pro deleted file mode 100644 index 03ffc09..0000000 --- a/ukui-search-app-data-service/ukui-search-app-data-service.pro +++ /dev/null @@ -1,63 +0,0 @@ -QT += core gui dbus sql KWindowSystem - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - - -TARGET = ukui-search-app-data-service -VERSION = 1.0.0 -DEFINES += VERSION='\\"$${VERSION}\\"' -CONFIG += c++11 no_keywords - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS -QMAKE_CXXFLAGS += -Werror=return-type -Werror=return-local-addr -Werror=uninitialized - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -#include(../libsearch/appdata/appdata.pri) -include(../3rd-parties/qtsingleapplication/qtsingleapplication.pri) - -LIBS += -lQt5Xdg - -SOURCES += \ - main.cpp \ - convert-winid-to-desktop.cpp \ - app-db-manager.cpp \ - pending-app-info-queue.cpp \ - signal-transformer.cpp \ - ukui-search-app-data-service.cpp \ - -HEADERS += \ - convert-winid-to-desktop.h \ - app-db-manager.h \ - pending-app-info-queue.h \ - pending-app-info.h \ - signal-transformer.h \ - ukui-search-app-data-service.h \ - -inst1.files += conf/com.ukui.search.appdb.service -inst1.path = /usr/share/dbus-1/services/ - -target.path = /usr/bin -INSTALLS += \ - target \ - inst1 - -desktop.path = /etc/xdg/autostart -desktop.files += ../data/ukui-search-app-data-service.desktop -INSTALLS += desktop - -LIBS += -L$$OUT_PWD/../libchinese-segmentation/ -lchinese-segmentation -INCLUDEPATH += $$PWD/../libchinese-segmentation -DEPENDPATH += $$PWD/../libchinese-segmentation - -LIBS += -L$$OUT_PWD/../libsearch/ -lukui-search -INCLUDEPATH += $$PWD/../libsearch \ - $$PWD/../libsearch/filesystemwatcher -DEPENDPATH += $$PWD/../libsearch diff --git a/ukui-search-service-dir-manager/CMakeLists.txt b/ukui-search-service-dir-manager/CMakeLists.txt new file mode 100644 index 0000000..8f634c0 --- /dev/null +++ b/ukui-search-service-dir-manager/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.14) +project(ukui-search-service-dir-manager VERSION 1.0.0 LANGUAGES CXX) + +set(VERSION_MAJOR 1) +set(VERSION_MINOR 0) +set(VERSION_MICRO 0) +set(UKUI_SEARCH_SERVICE_DIR_MANAGER_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus Network Widgets REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus Network Widgets REQUIRED) +find_package(PkgConfig REQUIRED) + +set(UKUI_SEARCH_SERVICE_DIR_MANAGER_EXTERNAL_LIBS "") +set(UKUI_SEARCH_SERVICE_DIR_MANAGER_PC_PKGS gio-2.0 gio-unix-2.0) + +foreach(PC_LIB IN ITEMS ${UKUI_SEARCH_SERVICE_DIR_MANAGER_PC_PKGS}) + pkg_check_modules(${PC_LIB} REQUIRED IMPORTED_TARGET ${PC_LIB}) + if(${${PC_LIB}_FOUND}) + include_directories(${${PC_LIB}_INCLUDE_DIRS}) + link_directories(${${PC_LIB}_LIBRARY_DIRS}) + list(APPEND UKUI_SEARCH_SERVICE_DIR_MANAGER_EXTERNAL_LIBS PkgConfig::${PC_LIB}) + endif() +endforeach() + +set(UKUI_SEARCH_SERVICE_DIR_MANAGER_SRC + dirwatcher/config.cpp dirwatcher/config.h + dirwatcher/dir-watcher.cpp dirwatcher/dir-watcher.h + dirwatcher/search-dir.cpp dirwatcher/search-dir.h + dirwatcher/volume-manager.cpp dirwatcher/volume-manager.h + main.cpp + ukui-search-dir-manager-dbus.cpp ukui-search-dir-manager-dbus.h) + +if(COMMAND qt_add_dbus_adaptor) + qt_add_dbus_adaptor(UKUI_SEARCH_SERVICE_DIR_MANAGER_SRC dirwatcher/com.ukui.search.FileIndexService.xml dir-watcher.h DirWatcher) +else() + qt5_add_dbus_adaptor(UKUI_SEARCH_SERVICE_DIR_MANAGER_SRC dirwatcher/com.ukui.search.FileIndexService.xml dir-watcher.h DirWatcher) +endif() + +add_executable(ukui-search-service-dir-manager + ${UKUI_SEARCH_SERVICE_DIR_MANAGER_SRC} +) +target_include_directories(ukui-search-service-dir-manager PRIVATE + ../3rd-parties/qtsingleapplication/src + dirwatcher + ../libsearch + ) + +target_compile_definitions(ukui-search-service-dir-manager PRIVATE + QT_DEPRECATED_WARNINGS + VERSION="${UKUI_SEARCH_SERVICE_DIR_MANAGER_VERSION}" +) + +target_link_libraries(ukui-search-service-dir-manager PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Network + Qt${QT_VERSION_MAJOR}::Widgets + qtsingleapplication + libukui-search + ${UKUI_SEARCH_SERVICE_DIR_MANAGER_EXTERNAL_LIBS} +) +install(FILES conf/com.ukui.search.fileindex.service DESTINATION /usr/share/dbus-1/services/) +install(FILES ../data/ukui-search-service-dir-manager.desktop DESTINATION /etc/xdg/autostart) +install(TARGETS ukui-search-service-dir-manager DESTINATION /usr/bin) \ No newline at end of file diff --git a/ukui-search-service-dir-manager/dirwatcher/com.ukui.search.fileindex.server.xml b/ukui-search-service-dir-manager/dirwatcher/com.ukui.search.FileIndexService.xml similarity index 68% rename from ukui-search-service-dir-manager/dirwatcher/com.ukui.search.fileindex.server.xml rename to ukui-search-service-dir-manager/dirwatcher/com.ukui.search.FileIndexService.xml index 014cdfc..7bce4ea 100644 --- a/ukui-search-service-dir-manager/dirwatcher/com.ukui.search.fileindex.server.xml +++ b/ukui-search-service-dir-manager/dirwatcher/com.ukui.search.FileIndexService.xml @@ -9,5 +9,12 @@ + + + + + + + diff --git a/ukui-search-service-dir-manager/dirwatcher/config.cpp b/ukui-search-service-dir-manager/dirwatcher/config.cpp new file mode 100644 index 0000000..1af8b68 --- /dev/null +++ b/ukui-search-service-dir-manager/dirwatcher/config.cpp @@ -0,0 +1,357 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static const QString HOME_PATH = QDir::homePath(); +static const QString OLD_BLOCK_DIR_SETTINGS = HOME_PATH + "/.config/org.ukui/ukui-search/ukui-search-block-dirs.conf"; +static const QString OLD_INDEXABLE_DIR_SETTINGS = HOME_PATH + "/.config/org.ukui/ukui-search/ukui-search-current-indexable-dir.conf"; +static const QString SEARCH_DIRS_SETTINGS = HOME_PATH + "/.config/org.ukui/ukui-search/ukui-search-dirs.json"; +static const QString SEARCH_DIRS_SETTINGS_DIR = HOME_PATH + "/.config/org.ukui/ukui-search"; +static const QString INDEXABLE_DIR_KEY = "IndexableDir"; //兼容历史版本 +static const QString CONFIG_VERSION_KEY = "ConfigVersion"; +static const QString CONFIG_VERSION = "1.0"; +static const QString BLOCK_DIRS_FOR_USER_KEY = "BlockDirsForUser"; +static const QString GLOBAL_BLACK_LIST_KEY = "GlobalBlackList"; +static const QStringList GLOBAL_BLACK_LIST{"/proc", "/sys", "/dev", "/tmp", "/run"}; +static const QString GLOBAL_SETTINGS_GROUP = "GlobalSettings"; +static const QString SEARCH_DIRS_GROUP = "SearchDirs"; + +static std::once_flag flag; +static Config *global_instance = nullptr; +Config *Config::self() +{ + std::call_once(flag, [ & ] { + global_instance = new Config(); + }); + return global_instance; +} + +void Config::addDir(const SearchDir &dir) +{ + QJsonObject searchDirData = m_settingsData.value(SEARCH_DIRS_GROUP).toObject(); + QJsonArray blackList; + for(const QString& path : dir.getBlackList()) { + blackList.append(path); + } + searchDirData.insert(dir.getPath(), blackList); + m_settingsData.insert(SEARCH_DIRS_GROUP, searchDirData); + save(m_settingsData); +} + +QStringList Config::removeDir(const SearchDir &dir) +{ + QJsonObject searchDirData = m_settingsData.value(SEARCH_DIRS_GROUP).toObject(); + QStringList blackDirs = searchDirData.take(dir.getPath()).toVariant().toStringList(); + m_settingsData.insert(SEARCH_DIRS_GROUP, searchDirData); + save(m_settingsData); + return blackDirs; +} + +int Config::addBlockDirOfUser(const QString &dir) +{ + if (!QFile::exists(dir)) { + return SearchDir::NotExists; + } + + QJsonObject globalSettings = m_settingsData.value(GLOBAL_SETTINGS_GROUP).toObject(); + QJsonArray blockDirsOfUser = globalSettings.value(BLOCK_DIRS_FOR_USER_KEY).toArray(); + + for (auto it = blockDirsOfUser.begin(); it !=blockDirsOfUser.end();) { + QString blockDir = (*it).toString(); + if (dir == blockDir || dir.startsWith(blockDir + "/") || blockDir == "/") { + return SearchDir::Duplicated; + } + //有子文件夹已被添加,删除这些子文件夹 + if (blockDir.startsWith(dir + "/") || dir == "/") { + it = blockDirsOfUser.erase(it); + } else { + it++; + } + } + + blockDirsOfUser.append(dir); + globalSettings.insert(BLOCK_DIRS_FOR_USER_KEY, blockDirsOfUser); + m_settingsData.insert(GLOBAL_SETTINGS_GROUP, globalSettings); + save(m_settingsData); + return SearchDir::Successful; +} + +void Config::removeBlockDirOfUser(const QString &dir) +{ + QJsonObject globalSettings = m_settingsData.value(GLOBAL_SETTINGS_GROUP).toObject(); + QJsonArray blockDirs = globalSettings.value(BLOCK_DIRS_FOR_USER_KEY).toArray(); + bool removeItem(false); + + for (auto it = blockDirs.begin(); it != blockDirs.end();) { + if ((*it).toString() == dir) { + it = blockDirs.erase(it); + removeItem = true; + } else { + it++; + } + } + if (removeItem) { + globalSettings.insert(BLOCK_DIRS_FOR_USER_KEY, blockDirs); + m_settingsData.insert(GLOBAL_SETTINGS_GROUP, globalSettings); + save(m_settingsData); + } +} + +bool Config::isCompatibilityMode() +{ + return m_compatibilityMode; +} + +void Config::save(const QJsonObject &jsonDocData) +{ + QDir dir; + QString configFileDir(SEARCH_DIRS_SETTINGS_DIR); + if (!dir.exists(configFileDir)) { + if (!dir.mkdir(configFileDir)) { + qWarning() << "Unable to create settings config file."; + return; + } + } + + QFile settingsFile(SEARCH_DIRS_SETTINGS); + if(!settingsFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "Fail to open file " << SEARCH_DIRS_SETTINGS; + } + + if (settingsFile.write(QJsonDocument(jsonDocData).toJson()) == -1) { + qWarning() << "Error saving configuration file."; + } + settingsFile.flush(); + settingsFile.close(); +} + +void Config::initSettingsData(QJsonObject &data) +{ + //全局配置 + QJsonObject globalSettings; + + QJsonArray blackList; + for(const QString& path : GLOBAL_BLACK_LIST) { + blackList.append(path); + } + globalSettings.insert(GLOBAL_BLACK_LIST_KEY, blackList); + + data.insert(CONFIG_VERSION_KEY, CONFIG_VERSION); + data.insert(GLOBAL_SETTINGS_GROUP, globalSettings); +} + +QStringList Config::searchDirs() +{ + QStringList tmp; + bool needSave = false; + QJsonObject searchDirData = m_settingsData.value(SEARCH_DIRS_GROUP).toObject(); + for(const QString& path : searchDirData.keys()) { + if(QFile::exists(path)) { + tmp.append(path); + } else { + searchDirData.remove(path); + needSave = true; + } + } + if(needSave) { + m_settingsData.insert(SEARCH_DIRS_GROUP, searchDirData); + save(m_settingsData); + } + return tmp; +} + +QStringList Config::blackDirs() +{ + QStringList tmp; + bool needSave = false; + QJsonObject searchDir = m_settingsData.value(SEARCH_DIRS_GROUP).toObject(); + for(const QString& path : searchDir.keys()) { + if(QFile::exists(path)) { + tmp.append(searchDir.value(path).toVariant().toStringList()); + } else { + searchDir.remove(path); + needSave = true; + } + } + if(needSave) { + m_settingsData.insert(SEARCH_DIRS_GROUP, searchDir); + save(m_settingsData); + } + return tmp; +} + +QStringList Config::globalBlackList() const +{ + return m_settingsData.value(GLOBAL_SETTINGS_GROUP).toObject().value(GLOBAL_BLACK_LIST_KEY).toVariant().toStringList(); +} + +QStringList Config::blockDirsForUser() +{ + bool needSave; + QStringList blockDirs; + QJsonObject globalSettings = m_settingsData.value(GLOBAL_SETTINGS_GROUP).toObject(); + for (const QString& dir : globalSettings.value(BLOCK_DIRS_FOR_USER_KEY).toVariant().toStringList()) { + if (QFile::exists(dir)) { + blockDirs << dir; + } else { + needSave = true; + } + } + + if (needSave) { + QJsonArray array; + for (const QString& dir : blockDirs) { + array << dir; + } + globalSettings.insert(BLOCK_DIRS_FOR_USER_KEY, array); + m_settingsData.insert(GLOBAL_SETTINGS_GROUP, globalSettings); + save(m_settingsData); + } + return blockDirs; +} + +Config::Config() +{ + QJsonArray blockDirsForUser; + bool oldBlockSettingsExists(false); + if (QFile::exists(OLD_BLOCK_DIR_SETTINGS)) { + oldBlockSettingsExists = true; + QSettings oldBlockSettings(OLD_BLOCK_DIR_SETTINGS, QSettings::IniFormat); + for(const QString& blockDir : oldBlockSettings.allKeys()) { + QString wholePath = "/" + blockDir; + if(QFile::exists(wholePath)) { + blockDirsForUser.append(wholePath); + } + } + QFile::remove(OLD_BLOCK_DIR_SETTINGS); + } + + QSettings oldSettings(OLD_INDEXABLE_DIR_SETTINGS, QSettings::IniFormat); + QFile settingsFile(SEARCH_DIRS_SETTINGS); + + if(!settingsFile.exists()) { + m_compatibilityMode = true; + qDebug() << oldSettings.value(INDEXABLE_DIR_KEY + "/" + INDEXABLE_DIR_KEY).toStringList(); + for(const QString& path : oldSettings.value(INDEXABLE_DIR_KEY + "/" + INDEXABLE_DIR_KEY).toStringList()) { + if(QFile::exists(path)) { + SearchDir dir(path, false); + qDebug() << "Found old config path" << path; + m_compatibleCache.append(dir); + } + } + + //老版本配置会在更新后被清空,如果allKeys为空说明已经运行过新版本,此时如果新版配置不存在则添加家目录作为默认搜索目录 + if(m_compatibleCache.isEmpty() && oldSettings.allKeys().isEmpty()) { + SearchDir dir(HOME_PATH, false); + m_compatibleCache.append(dir); + } + oldSettings.clear(); + oldSettings.sync(); + + initSettingsData(m_settingsData); + if (!blockDirsForUser.isEmpty()) { + QJsonObject globalSettings = m_settingsData.value(GLOBAL_SETTINGS_GROUP).toObject(); + globalSettings.insert(BLOCK_DIRS_FOR_USER_KEY, blockDirsForUser); + m_settingsData.insert(GLOBAL_SETTINGS_GROUP, globalSettings); + } + save(m_settingsData); + return; + } + + if (!settingsFile.open(QFile::ReadOnly)) { + qWarning() << "SettingsManagerPrivate: configuration file " << settingsFile.fileName() << "open failed !"; + return; + } + QByteArray byteArray = settingsFile.readAll(); + settingsFile.close(); + QJsonParseError errRpt; + QJsonDocument jsonDocument(QJsonDocument::fromJson(byteArray, &errRpt)); + if (errRpt.error != QJsonParseError::NoError) { + qWarning() << "Incorrect configuration files. JSON parse error"; + initSettingsData(m_settingsData); + save(m_settingsData); + return; + } + // 读取配置文件 + QJsonObject settingsData = jsonDocument.object(); + QString version = settingsData.value(CONFIG_VERSION_KEY).toString(); + if (version != QString(CONFIG_VERSION)) { + qWarning() << "Settings version check failed, old: " << version << " new:" << CONFIG_VERSION; + //TODO:这里做一些兼容处理 + } else { + m_settingsData.swap(settingsData); + //旧的配置文件存在则需要进行同步旧配置 + if (oldBlockSettingsExists) { + QJsonObject globalSettings = m_settingsData.value(GLOBAL_SETTINGS_GROUP).toObject(); + globalSettings.insert(BLOCK_DIRS_FOR_USER_KEY, blockDirsForUser); + m_settingsData.insert(GLOBAL_SETTINGS_GROUP, globalSettings); + save(m_settingsData); + } + } + + QStringList pathToRemove; + for(const QString& path : m_settingsData.value(SEARCH_DIRS_GROUP).toObject().keys()) { + if(!QFile::exists(path)) { + pathToRemove.append(path); + } + } + if(!pathToRemove.isEmpty()) { + removeDir(pathToRemove); + } +} + +void Config::removeDir(const QStringList &paths) +{ + QJsonObject searchDirData = m_settingsData.value(SEARCH_DIRS_GROUP).toObject(); + for(const QString& path : paths) { + searchDirData.remove(path); + } + m_settingsData.insert(SEARCH_DIRS_GROUP, searchDirData); + save(m_settingsData); +} + +void Config::processCompatibleCache() +{ + if(this->isCompatibilityMode() && !m_compatibleCache.isEmpty()) { + QJsonObject searchDirsdata; + for (SearchDir dir : m_compatibleCache) { + dir.generateBlackList(); + if (dir.error() == SearchDir::ErrorInfo::Successful) { + QJsonArray blackList; + for(const QString& path : dir.getBlackList()) { + blackList.append(path); + } + searchDirsdata.insert(dir.getPath(), blackList); + m_settingsData.insert(SEARCH_DIRS_GROUP, searchDirsdata); + } + } + save(m_settingsData); + m_compatibleCache.clear(); + m_compatibilityMode = false; + } +} diff --git a/ukui-search-service-dir-manager/dirwatcher/config.h b/ukui-search-service-dir-manager/dirwatcher/config.h new file mode 100644 index 0000000..97b6a29 --- /dev/null +++ b/ukui-search-service-dir-manager/dirwatcher/config.h @@ -0,0 +1,59 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef CONFIG_H +#define CONFIG_H +#include +#include +#include +#include +#include "search-dir.h" + +class Config +{ +public: + static Config *self(); + void addDir(const SearchDir& dir); + QStringList removeDir(const SearchDir& dir); + + int addBlockDirOfUser(const QString& dir); + void removeBlockDirOfUser(const QString& dir); + + /** + * @brief 处理老版本数据,需要调用 + */ + void processCompatibleCache(); + QStringList searchDirs(); + QStringList blackDirs(); + QStringList globalBlackList() const; + QStringList blockDirsForUser(); + +private: + Config(); + void removeDir(const QStringList& paths); + bool isCompatibilityMode(); + void save(const QJsonObject &jsonDocData); + void initSettingsData(QJsonObject &data); + + QJsonObject m_settingsData; + bool m_compatibilityMode = false; + QVector m_compatibleCache; +}; + +#endif // CONFIG_H diff --git a/ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.cpp b/ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.cpp deleted file mode 100644 index ae5b25e..0000000 --- a/ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file was generated by qdbusxml2cpp version 0.8 - * Command line was: qdbusxml2cpp com.ukui.search.fileindex.server.xml -a dir-watcher-adaptor - * - * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. - * - * This is an auto-generated file. - * Do not edit! All changes made to it will be lost. - */ - -#include "dir-watcher-adaptor.h" -#include -#include -#include -#include -#include -#include -#include - -/* - * Implementation of adaptor class FileindexAdaptor - */ - -DirWatcherAdaptor::DirWatcherAdaptor(QObject *parent) - : QDBusAbstractAdaptor(parent) -{ - // constructor - setAutoRelaySignals(true); -} - -DirWatcherAdaptor::~DirWatcherAdaptor() -{ - // destructor -} - -int DirWatcherAdaptor::appendIndexableListItem(const QString &path) -{ - // handle method call org.ukui.search.fileindex.appendIndexableListItem - int out0; - QMetaObject::invokeMethod(parent(), "appendIndexableListItem", Q_RETURN_ARG(int, out0), Q_ARG(QString, path)); - return out0; -} - -bool DirWatcherAdaptor::removeIndexableListItem(const QString &path) -{ - // handle method call org.ukui.search.fileindex.removeIndexableListItem - bool out0; - QMetaObject::invokeMethod(parent(), "removeIndexableListItem", Q_RETURN_ARG(bool, out0), Q_ARG(QString, path)); - return out0; -} - diff --git a/ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.h b/ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.h deleted file mode 100644 index be4c3d8..0000000 --- a/ukui-search-service-dir-manager/dirwatcher/dir-watcher-adaptor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file was generated by qdbusxml2cpp version 0.8 - * Command line was: qdbusxml2cpp com.ukui.search.fileindex.server.xml -a dir-watcher-adaptor - * - * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. - * - * This is an auto-generated file. - * This file may have been hand-edited. Look for HAND-EDIT comments - * before re-generating it. - */ - -#ifndef DIR_WATCHER_ADAPTOR_H -#define DIR_WATCHER_ADAPTOR_H - -#include -#include -QT_BEGIN_NAMESPACE -class QByteArray; -template class QList; -template class QMap; -class QString; -class QStringList; -class QVariant; -QT_END_NAMESPACE - -/* - * Adaptor class for interface org.ukui.search.fileindex - */ -class DirWatcherAdaptor: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.ukui.search.fileindex") - Q_CLASSINFO("D-Bus Introspection", "" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" - "") -public: - DirWatcherAdaptor(QObject *parent); - virtual ~DirWatcherAdaptor(); - -public: // PROPERTIES -public Q_SLOTS: // METHODS - int appendIndexableListItem(const QString &path); - bool removeIndexableListItem(const QString &path); -Q_SIGNALS: // SIGNALS -}; - -#endif diff --git a/ukui-search-service-dir-manager/dirwatcher/dir-watcher-dbus.pri b/ukui-search-service-dir-manager/dirwatcher/dir-watcher-dbus.pri deleted file mode 100644 index 9661b77..0000000 --- a/ukui-search-service-dir-manager/dirwatcher/dir-watcher-dbus.pri +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/dir-watcher-adaptor.h \ - $$PWD/dir-watcher.h - -SOURCES += \ - $$PWD/dir-watcher-adaptor.cpp \ - $$PWD/dir-watcher.cpp diff --git a/ukui-search-service-dir-manager/dirwatcher/dir-watcher.cpp b/ukui-search-service-dir-manager/dirwatcher/dir-watcher.cpp index 206a367..49fb989 100644 --- a/ukui-search-service-dir-manager/dirwatcher/dir-watcher.cpp +++ b/ukui-search-service-dir-manager/dirwatcher/dir-watcher.cpp @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "dir-watcher.h" #include @@ -7,6 +26,8 @@ #include #include #include +#include "config.h" +#include "fileindexserviceadaptor.h" #define CURRENT_INDEXABLE_DIR_SETTINGS QDir::homePath() + "/.config/org.ukui/ukui-search/ukui-search-current-indexable-dir.conf" #define INDEXABLE_DIR_VALUE "IndexableDir" @@ -14,35 +35,18 @@ static std::once_flag flag; static DirWatcher *global_intance = nullptr; -QMutex DirWatcher::s_mutex; DirWatcher::DirWatcher(QObject *parent) : QObject(parent) { - m_qSettings = new QSettings(CURRENT_INDEXABLE_DIR_SETTINGS, QSettings::IniFormat); - this->currentIndexableDir(); - if (m_indexableDirList.isEmpty()) { - qDebug() << QString("use the path: %1 as default indexable dir.").arg(DEFAULT_INDEXABLE_DIR); - m_qSettings->beginGroup(INDEXABLE_DIR_VALUE); - m_qSettings->setValue(INDEXABLE_DIR_VALUE, DEFAULT_INDEXABLE_DIR); - m_qSettings->endGroup(); - } + //兼容旧版配置 + Config::self()->processCompatibleCache(); - initDiskWatcher(); - initData(); - m_adaptor = new DirWatcherAdaptor(this); + new FileindexAdaptor(this); } DirWatcher::~DirWatcher() { - if (m_volumeMonitor) { - g_signal_handler_disconnect(m_volumeMonitor, m_mountAddHandle); - g_signal_handler_disconnect(m_volumeMonitor, m_mountRemoveHandle); - m_volumeMonitor = nullptr; - } - if(m_qSettings){ - delete m_qSettings; - } - m_qSettings = nullptr; + } DirWatcher *DirWatcher::getDirWatcher() @@ -55,90 +59,13 @@ DirWatcher *DirWatcher::getDirWatcher() QStringList DirWatcher::currentIndexableDir() { - QMutexLocker locker(&s_mutex); - this->updateIndexableDirs(); - return m_indexableDirList; + return currentSearchDirs(); } -void DirWatcher::updateIndexableDirs() -{ - m_qSettings->beginGroup(INDEXABLE_DIR_VALUE); - m_indexableDirList = m_qSettings->value(INDEXABLE_DIR_VALUE).toStringList(); - m_qSettings->endGroup(); - QStringList indexableDirs = m_indexableDirList; - bool changed(false); - for (const QString& dir : m_indexableDirList) { - if (!QFileInfo(dir).isDir()) { - indexableDirs.removeAll(dir); - changed = true; - } - } - - if (changed) { - m_qSettings->beginGroup(INDEXABLE_DIR_VALUE); - m_qSettings->setValue(INDEXABLE_DIR_VALUE, indexableDirs); - m_qSettings->endGroup(); - m_indexableDirList = indexableDirs; - Q_EMIT this->indexDirsChanged(); - } -} QStringList DirWatcher::currentBlackListOfIndex() { - QMutexLocker locker(&s_mutex); - QStringList blackListOfIndex = m_blackListOfIndex; - return blackListOfIndex; -} - -bool DirWatcher::handleIndexItemAppend(const QString &path, QStringList &blackList) -{ - //排除要添加的路径已被索引的情况 - if (m_indexableDirList.contains(path)) { - qDebug() << QString("index path %1 is already added.").arg(path); - return false; - } - - //处理添加路径非根目录时,要添加索引的路径与已索引路径为父子关系的情况 - if (path != "/") { - QString indexablePath; - QStringList tmp = m_indexableDirList; - for (int i = 0; i < m_indexableDirList.length(); i++) { - indexablePath = m_indexableDirList.at(i); - if (path.startsWith(indexablePath + "/")) { - qCritical() << QString("The parent of the path:%1 has been added.").arg(path); - return false; - } - if (indexablePath.startsWith(path + "/")) { - tmp.removeAll(indexablePath); - blackList.append(indexablePath); - } - } - m_indexableDirList = tmp; - } - - m_indexableDirList << path; - m_qSettings->beginGroup(INDEXABLE_DIR_VALUE); - m_qSettings->setValue(INDEXABLE_DIR_VALUE, m_indexableDirList); - m_qSettings->endGroup(); - blackList.removeDuplicates(); - Q_EMIT this->appendIndexItem(path, blackList); - qDebug() << "index path:" << path << "blacklist:" << blackList; - return true; -} - -bool DirWatcher::handleIndexItemRemove(const QString &path) -{ - this->currentIndexableDir(); - QMutexLocker locker(&s_mutex); - if (!m_indexableDirList.contains(path)) { - qWarning() << QString("The path: %1 is not indexed").arg(path); - return false; - } - m_indexableDirList.removeAll(path); - m_qSettings->beginGroup(INDEXABLE_DIR_VALUE); - m_qSettings->setValue(INDEXABLE_DIR_VALUE, m_indexableDirList); - m_qSettings->endGroup(); - return true; + return currentBlackList(); } /** @@ -147,67 +74,7 @@ bool DirWatcher::handleIndexItemRemove(const QString &path) */ QStringList DirWatcher::blackListOfDir(const QString &dirPath) { - //new TODO: Optimize the search algorithm. - //There is no processing for the subvolumes.May be a bug. - QStringList blackListOfDir; - QMutexLocker locker(&s_mutex); - for (auto t = m_repeatedlyMountedDeviceInfo.constBegin(); t != m_repeatedlyMountedDeviceInfo.constEnd(); t++) { - QString topRepeatedMountPoint; - for (QString mountPoint: t.value()) { - if (mountPoint.startsWith(dirPath)) { - if (topRepeatedMountPoint.isEmpty()) { - topRepeatedMountPoint = mountPoint; - continue; - } else if (topRepeatedMountPoint.startsWith(mountPoint)) { - blackListOfDir.append(topRepeatedMountPoint); - topRepeatedMountPoint = mountPoint; - } else { - blackListOfDir.append(mountPoint); - } - } - } - } - for (auto i = m_infoOfSubvolume.constBegin(); i != m_infoOfSubvolume.constEnd(); i++) { - QString mountPoint = i.value(); - QString spec = i.key(); - //排除搜索列表指定多个目录时子卷会重复包含的情况,比如同时指定/home和/data/home - QString tmp = dirPath; - if (dirPath.startsWith(mountPoint)) { - blackListOfDir.append(tmp.replace(0, mountPoint.length(), spec)); - } - if (dirPath.startsWith(spec)) { - blackListOfDir.append(tmp.replace(0, spec.length(), mountPoint)); - } - } - return blackListOfDir; -} - -void DirWatcher::appendBlackListItemOfIndex(const QString &path) -{ - QMutexLocker locker(&s_mutex); - m_blackListOfIndex.append(path); - m_blackListOfIndex = m_blackListOfIndex.toSet().toList(); -} - -void DirWatcher::appendBlackListItemOfIndex(const QStringList &pathList) -{ - QMutexLocker locker(&s_mutex); - m_blackListOfIndex.append(pathList); - m_blackListOfIndex = m_blackListOfIndex.toSet().toList(); -} - -void DirWatcher::removeBlackListItemOfIndex(const QString &path) -{ - QMutexLocker locker(&s_mutex); - m_blackListOfIndex.removeAll(path); -} - -void DirWatcher::removeBlackListItemOfIndex(const QStringList &pathList) -{ - QMutexLocker locker(&s_mutex); - for (QString path: pathList) { - m_blackListOfIndex.removeAll(path); - } + return SearchDir::blackListOfDir(dirPath); } void DirWatcher::initDbusService() @@ -220,431 +87,82 @@ void DirWatcher::initDbusService() QStringList DirWatcher::currentSearchableDir() { - QMutexLocker locker(&s_mutex); - return m_searchableDirList; + return currentSearchDirs(); } QStringList DirWatcher::searchableDirForSearchApplication() { - QMutexLocker locker(&s_mutex); - return m_searchableListForApplication; -} - -void DirWatcher::mountAddCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis) -{ - qDebug() << "Mount Added"; - GMount* mount = (GMount*)g_object_ref(gmount); - GVolume* volume = g_mount_get_volume(mount); - if (volume) { - bool canEject = g_volume_can_eject(volume); - QString devName = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); - if (canEject and devName.contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) { - QMutexLocker locker(&s_mutex); - pThis->m_currentUDiskDeviceList.append(devName.section("/", -1)); - } - qDebug() << "added device name:" << devName.section("/", -1); - g_object_unref(volume); - } else { - qWarning() << "GVolume(add) is NULL."; - } - pThis->handleDisk(); -} - -void DirWatcher::mountRemoveCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis) -{ - qDebug() << "Mount Removed"; - pThis->handleDisk(); - QMutexLocker locker(&s_mutex); - //处理u盘设备 - if (pThis->m_removedUDiskDevice != NULL) { - pThis->updateIndexableDirs();//更新索引名单,排除失效目录 - pThis->m_currentUDiskDeviceInfo.remove(pThis->m_removedUDiskDevice); - qDebug() << "m_currentUDiskDeviceInfo(after remove):" << pThis->m_currentUDiskDeviceInfo; - pThis->m_removedUDiskDevice = ""; - return; - } - - GMount* mount = (GMount*)g_object_ref(gmount); - GFile* rootFile; - rootFile = g_mount_get_root(mount); - if (!rootFile) { - return; - } - QString removedUri = g_file_get_uri(rootFile); - if (removedUri.isEmpty()) { - return; - } - //处理uri转码 - if (removedUri.startsWith("file:///")) { - QString removedMountPoint = g_filename_from_uri(removedUri.toUtf8().constData(), nullptr, nullptr); - pThis->m_blackListOfIndex.removeAll(removedMountPoint); - locker.unlock(); - QStringList indexableDirList = pThis->currentIndexableDir(); - //卸载目录下存在已索引目录时,通知索引服务删除对应目录 - for (const QString &indexableDir : indexableDirList) { - if (indexableDir.startsWith(removedMountPoint + "/") or !indexableDir.compare(removedMountPoint)) { - Q_EMIT pThis->removeIndexItem(indexableDir); - } - } - //处理子卷情况 - locker.relock(); - for (auto t = pThis->m_infoOfSubvolume.constBegin(); t != pThis->m_infoOfSubvolume.constEnd(); t++) { - if (removedMountPoint.startsWith(t.value() + "/")) { - pThis->m_blackListOfIndex.removeAll(removedMountPoint.replace(t.value(), t.key())); - } - if (removedMountPoint.startsWith(t.key() + "/")) { - pThis->m_blackListOfIndex.removeAll(removedMountPoint.replace(t.key(), t.value())); - } - } - qDebug() << "m_blackListOfIndex(after remove):" << pThis->m_blackListOfIndex; - } else { - qWarning() << QString("Removed uri:%1 is not starts with 'file:///', there's no handling of it.").arg(removedUri); - } - g_object_unref(rootFile); + return currentSearchDirs(); } int DirWatcher::appendIndexableListItem(const QString &path) { - int resultCode = 1; + return appendSearchDir(path); /* code: - * 1: successful - * -1: path or its parent dir has been added - * -2: path is or under blacklist - * -3: path is in repeat mounted devices and another path which is in the same device has been indexed - * -4: another path which is in the same device has been indexed - * -5: path is not exists + * 0: successful + * 1: path or its parent dir has been added + * 2: path is or under blacklist + * 3: path is in repeat mounted devices and another path which is in the same device has been indexed + * 4: another path which is in the same device has been indexed + * 5: path is not exists */ - - //排除path不存在的情况 - QFile file(path); - if (!file.exists()) { - qWarning() << QString("target path:%1 is not exists!").arg(path); - resultCode = -5; - return resultCode; - } - - //同步配置文件中的已索引目录 - this->currentIndexableDir(); - qDebug() << "current indexable dirs:" << m_indexableDirList; - - QStringList blackList; - QMutexLocker locker(&s_mutex); - - //根目录特殊处理 - if (path == "/") { - if (!this->handleIndexItemAppend(path, m_blackListOfIndex)) { - resultCode = -1; - } - return resultCode; - } - - //处理要添加索引的路径与索引黑名单中路径为父子关系的情况 - for (const QString& blackListPath : m_blackListOfIndex) { - if (path.startsWith(blackListPath + "/") or path == blackListPath) { - qCritical() << QString("path:%1 is or under the blacklistpath:%2.").arg(path, blackListPath); - resultCode = -2; - return resultCode; - } - - if (blackListPath.startsWith(path + "/")) { - blackList.append(blackListPath); - } - } - - //排除要添加的目录为某设备的重复挂载目录,并且之前已索引过该设备其他挂载目录或其父目录的情况 - for (auto i = m_repeatedlyMountedDeviceInfo.constBegin(); i != m_repeatedlyMountedDeviceInfo.constEnd(); i++) { - bool pathToBeAddedIsRepeatedDevice = false; - bool pathToBeAddedHasRepeatedDevice = false; - bool addedPathIsRepeatedDevice = false; - bool addedPathHasRepeatedDevice = false; - QString addedRelativeDir; - QString repeatedDir; - for (const QString &addedPath : m_indexableDirList) { - for (const QString &mountPoint : i.value()) { - - //要添加索引路径在重复挂载设备路径下(1) - if (path.startsWith(mountPoint + "/") or mountPoint == path) { - repeatedDir = mountPoint; - pathToBeAddedIsRepeatedDevice = true; - } - //重复挂载设备路径在要添加索引路径下(2) - if (mountPoint.startsWith(path + "/")) { - repeatedDir = mountPoint; - pathToBeAddedHasRepeatedDevice = true; - } - - //已索引路径在重复挂载设备路径下(3) - if (addedPath.startsWith(mountPoint + "/") or mountPoint == addedPath) { - addedRelativeDir = addedPath; - addedRelativeDir.remove(mountPoint); - addedPathIsRepeatedDevice = true; - } - //重复挂载设备路径在已索引路径下(4) - if (mountPoint.startsWith(addedPath + "/")) { - addedPathHasRepeatedDevice = true; - } - - //(1)(4)直接返回 - if (pathToBeAddedIsRepeatedDevice and addedPathHasRepeatedDevice) { - qCritical() << "current path is in repeat mounted devices and another path which is in the same device has been indexed!"; - resultCode = -3; - return resultCode; - } - //(2)(4)将要添加索引目录相应的重复挂载路径添加到黑名单 - if (pathToBeAddedHasRepeatedDevice and addedPathHasRepeatedDevice) { - blackList.append(repeatedDir); - break; - } - //(1)(3)将已索引路径的前缀替换为要添加路径的前缀(前缀为mountPoint),判断替换后路径是否在要索引路径下,如果是则返回,否则将替换后路径添加到黑名单 - if (pathToBeAddedIsRepeatedDevice and addedPathIsRepeatedDevice) { - QString pathAfterReplace = repeatedDir + addedRelativeDir; - if (path.startsWith(pathAfterReplace) or path == pathAfterReplace) { - qCritical() << QString("another path:%1 which is in the same device has been indexed").arg(pathAfterReplace); - resultCode = -4; - return resultCode; - } else { - blackList.append(pathAfterReplace); - break; - } - } - //(2)(3)将替换前缀后的已索引路径添加到黑名单 - if (pathToBeAddedHasRepeatedDevice and addedPathIsRepeatedDevice) { - blackList.append(repeatedDir + addedRelativeDir); - break; - } - } - } - } - - //排除重复挂载设备的目录 - for (auto i = m_repeatedlyMountedDeviceInfo.constBegin(); i != m_repeatedlyMountedDeviceInfo.constEnd(); i++) { - QString topRepeatedMountPoint; - for (const QString &mountPoint : i.value()) { - if (mountPoint.startsWith(path + "/") or mountPoint == path) { - if (topRepeatedMountPoint.isEmpty()) { - topRepeatedMountPoint = mountPoint; - continue; - } else if (topRepeatedMountPoint.startsWith(mountPoint)) { - blackList.append(topRepeatedMountPoint); - topRepeatedMountPoint = mountPoint; - } else { - blackList.append(mountPoint); - } - } - } - } - - //处理自动挂载子卷下的目录,目前方案将其合并为一个,只保留了mountpoint下的目录 - for (auto t = m_infoOfSubvolume.constBegin(); t != m_infoOfSubvolume.constEnd(); t++) { - QString mountPoint = t.value(); - QString spec = t.key(); - QString tmp = path; - - if (spec.startsWith(path + "/")) { - blackList << spec; - } - - if (path.startsWith(spec + "/") or path == spec) { - tmp.replace(0, spec.length(), mountPoint); - if (this->handleIndexItemAppend(tmp, blackList)) { - qDebug() << QString("The path:%1 has been replaced into %2").arg(path, tmp); - } else { - resultCode = -1; - } - return resultCode; - } - } - - if (!this->handleIndexItemAppend(path, blackList)) { - resultCode = -1; - } - return resultCode; } bool DirWatcher::removeIndexableListItem(const QString &path) { - bool res = this->handleIndexItemRemove(path); + removeSearchDir(path); + return true; +} + +int DirWatcher::appendSearchDir(const QString &path) +{ + SearchDir dir(path); + if (dir.error() == SearchDir::Successful) { + Q_EMIT this->appendIndexItem(path, dir.getBlackList()); + qDebug() << "Add search dir:" << path << "blacklist:" << dir.getBlackList(); + //要添加已索引目录的父目录,先添加索引,再同步配置文件,从而使得下次读取配置文件时不会将子目录排除掉 + for (const QString &searchDir : Config::self()->searchDirs()) { + if (searchDir.startsWith(path + "/") || path == "/") { + SearchDir subDir(searchDir); + Config::self()->removeDir(subDir); + } + } + dir.generateBlackList(); + Config::self()->addDir(dir); + } + qWarning() << dir.getPath() << dir.errorString(); + return dir.error(); +} + +void DirWatcher::removeSearchDir(const QString &path) +{ + SearchDir dir(path, false); + Config::self()->removeDir(dir); Q_EMIT this->removeIndexItem(path); - return res; + return; } -void DirWatcher::initData() +QStringList DirWatcher::currentSearchDirs() { - //适配需求,可索引目录为用户指定。 -// m_indexableDirList << "/data" << QDir::homePath(); - /* boot里面存放Linux核心文件,开机选单与开机所需配置文件等 - * backup里面是系统备份文件 - * bin放置的是在单人维护模式下还能够被操作的指令,在bin底下的指令可以被root与一般账号所使用。 - * dev里面存放设备文件 - * etc里面存放了几乎所有的系统主要配置文件,包括人员的账号密码文件,各种服务的起始档等 - * lib放置最基本的共享库和内核模块,lib32,lib64,libx32分别面向32位,64位以及x32 ABI。他们都分别连接到usr下的lib*中 - * media一般放置可移除的装置,包括软盘,光盘和一些移动存储设备都自动挂载到这里 - * mnt原本和media用途相同,现用来放置暂时挂载一些额外装置 - * usr是Unix操作系统软件资源所放置的目录,所有系统默认的软件(distribution发布者提供的软件)都会放置到usr底下 - * var目录主要针对常态性变动的文件,包括缓存(cache)、登录档(log file)以及某些软件运作所产生的文件,包括程序文件(lock file, run file),或者如MySQL数据库的文件等 - */ - //将磁盘分区后其他分区都会挂载到media下,多块硬盘也会挂到media,因此media放开,mnt同理; - //backup是备份文件,tmp是临时文件,也都放开 -// m_blackListOfIndex << "/boot" << "/bin" << "/dev" << "/etc" << "/usr" << "/var" -// << "/lib" << "/lib32" << "/lib64" << "/libx32" << "/cdrom" -// << "/sys" << "/proc" << "/srv" << "/sbin" << "/run" << "/opt"; - //专用机需求:只屏蔽/proc, /sys, /dev, /tmp, /run - m_blackListOfIndex << "/proc" << "/sys" << "/dev" << "/tmp" << "/run"; - - //目前方案:可搜索目录(服务)默认根目录,可搜索目录(应用)默认家目录和/data目录 - QDir dir("/data"); - if (dir.exists()) { - m_searchableListForApplication << "/data"; - } - m_searchableListForApplication << QDir::homePath(); - - m_searchableDirList << "/"; - - //init auto mounted device list - setfsent(); - while (1) { - fstab *myFstab = getfsent(); - if (!myFstab) { - endfsent(); - break; - } - QString automaticMountPoint = myFstab->fs_file; - QString spec = myFstab->fs_spec; - - //目前只索引data和home,因此只存这两个文件夹下的挂载点 - if (automaticMountPoint.contains("/data") || automaticMountPoint.contains("/home")) { - m_autoMountList.append(automaticMountPoint); - } - //存储所有子卷自动挂载 - if (!spec.startsWith("UUID")) { - m_infoOfSubvolume.insert(spec, automaticMountPoint); - } - } - - GList *list = g_volume_monitor_get_volumes(m_volumeMonitor); - if (!list) { - qDebug() << "Fail to init glist of volume monitor!"; - handleDisk(); - return; - } - for (guint i = 0; i < g_list_length(list); i++) { - GVolume *volume = (GVolume*)g_list_nth_data(list, i); - QString udiskDevName = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE); - bool canEject = g_volume_can_eject(volume); - if (canEject and udiskDevName.contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) { - qDebug() << "udiskDevName:" << udiskDevName.section("/",-1); - m_currentUDiskDeviceList.append(udiskDevName.section("/",-1)); - } - } - - //init disk data, refresh the black list - handleDisk(); + return Config::self()->searchDirs(); } -void DirWatcher::initDiskWatcher() +QStringList DirWatcher::currentBlackList() { - //use Dbus to monitor the hot plug of Udisk. - - - QDBusConnection dbc = QDBusConnection::systemBus(); - - qDebug() << "Connect The Signal:InterfacesAdded" << dbc.connect("org.freedesktop.UDisks2", - "/org/freedesktop/UDisks2", - "org.freedesktop.DBus.ObjectManager", - "InterfacesAdded", - this, SLOT(handleAddedUDiskDevice(QDBusMessage))); - qDebug() << dbc.lastError(); - qDebug() << "Connect The Signal:InterfacesRemove" << dbc.connect("org.freedesktop.UDisks2", - "/org/freedesktop/UDisks2", - "org.freedesktop.DBus.ObjectManager", - "InterfacesRemoved", - this, SLOT(handleRemovedUDiskDevice(QDBusMessage))); - - m_volumeMonitor = g_volume_monitor_get(); - if (!m_volumeMonitor) { - qDebug() << "Fail to init volume monitor"; - return; - } - m_mountAddHandle = g_signal_connect(m_volumeMonitor, "mount-added", G_CALLBACK(mountAddCallback), this); - m_mountRemoveHandle = g_signal_connect(m_volumeMonitor, "mount-removed", G_CALLBACK(mountRemoveCallback), this); + return Config::self()->blackDirs(); } -void DirWatcher::handleDisk() +QStringList DirWatcher::blockDirsForUser() { - //init current mounted device info - QMutexLocker locker(&s_mutex); - m_currentMountedDeviceInfo.clear(); - m_repeatedlyMountedDeviceInfo.clear(); - for (QStorageInfo &storage: QStorageInfo::mountedVolumes()) { - //遍历当前系统所有挂载的,且以sd*和nvme开头的存储设备 - if (storage.isValid() and storage.isReady() and QString(storage.device()).contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) { - m_currentMountedDeviceInfo[storage.device()].append(storage.rootPath()); - //存储非子卷的重复挂载设备 - if (m_currentMountedDeviceInfo.value(storage.device()).length() > 1 and storage.subvolume().isEmpty()) { - m_repeatedlyMountedDeviceInfo.insert(storage.device(), m_currentMountedDeviceInfo.value(storage.device())); - } - //排除挂载到data和home下挂载的所有其他设备,后面需要修改 -// if (storage.rootPath().startsWith("/data") || storage.rootPath().startsWith("/home")) { -// m_blackListOfIndex.append(storage.rootPath()); -// } - } - } - - //根据设备号(key)更新u盘信息 - if (!m_currentUDiskDeviceList.isEmpty()) { - for (const QString &udiskDevice: m_currentUDiskDeviceList) { - QStringList udiskMountPointList = m_currentMountedDeviceInfo.value("/dev/" + udiskDevice); - if (udiskMountPointList.isEmpty()) { - m_currentUDiskDeviceInfo.remove(udiskDevice); - } else { - m_currentUDiskDeviceInfo.insert(udiskDevice, udiskMountPointList); - } - - } - } - - //将u盘设备添加到索引黑名单 - if (!m_currentUDiskDeviceInfo.isEmpty()) { - for (auto t = m_currentUDiskDeviceInfo.constBegin(); t != m_currentUDiskDeviceInfo.constEnd(); t++) { - for (QString udiskDevice: t.value()) { -// if (udiskDevice.startsWith("/data") || udiskDevice.startsWith("/home")) { -// m_blackListOfIndex.append(udiskDevice); -// } - } - } - } - - //从索引黑名单中移除所有自动挂载设备(目前只包含自动挂载到/data和/home目录下的设备),m_infoOfSubvolume存储全部fstab文件中的子卷自动挂载 - for (const QString &autoMountDevice: m_autoMountList) { - m_blackListOfIndex.removeAll(autoMountDevice); - } - m_blackListOfIndex.removeDuplicates(); - - qDebug() << "m_infoOfSubvolume" << m_infoOfSubvolume; - qDebug() << "m_currentMountedDeviceInfo:" << m_currentMountedDeviceInfo; - qDebug() << "m_repeatedlyMountedDeviceInfo:" << m_repeatedlyMountedDeviceInfo; - qDebug() << "m_currentUDiskDeviceInfo:" << m_currentUDiskDeviceInfo; - qDebug() << "m_blackListOfIndex:" << m_blackListOfIndex; - + return Config::self()->blockDirsForUser(); } -void DirWatcher::handleAddedUDiskDevice(QDBusMessage msg) +int DirWatcher::addBlockDirOfUser(const QString &dir) { - QDBusObjectPath objPath = msg.arguments().at(0).value(); - if (objPath.path().contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) { - QMutexLocker locker(&s_mutex); - m_currentUDiskDeviceList.append(objPath.path().section("/",-1)); - qDebug() << "Add Udisk:" << m_currentUDiskDeviceList; - } + return Config::self()->addBlockDirOfUser(dir); } -void DirWatcher::handleRemovedUDiskDevice(QDBusMessage msg) +void DirWatcher::removeBlockDirOfUser(const QString &dir) { - Q_EMIT this->udiskRemoved(); - QDBusObjectPath objPath = msg.arguments().at(0).value(); - if (objPath.path().contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) { - QMutexLocker locker(&s_mutex); - m_removedUDiskDevice = objPath.path().section("/",-1); - m_currentUDiskDeviceList.removeAll(m_removedUDiskDevice); - } + Config::self()->removeBlockDirOfUser(dir); } diff --git a/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h b/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h index 2e12f09..9364808 100644 --- a/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h +++ b/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h @@ -1,25 +1,32 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #ifndef MOUNTDISKLISTENER_H #define MOUNTDISKLISTENER_H -#include "dir-watcher-adaptor.h" - #include -#include -#include +#include #include #include -#include -#include #include #include #include - -#undef slots -#undef signals -#undef emit - -#include -#include +#include class DirWatcher : public QObject { @@ -29,13 +36,6 @@ class DirWatcher : public QObject public: static DirWatcher *getDirWatcher(); - static void mountAddCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis); - static void mountRemoveCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis); - - void appendBlackListItemOfIndex(const QString &path); - void appendBlackListItemOfIndex(const QStringList &pathList); - void removeBlackListItemOfIndex(const QString &path); - void removeBlackListItemOfIndex(const QStringList &pathList); public Q_SLOTS: @@ -53,59 +53,38 @@ public Q_SLOTS: * add a item to indexable dirs * @param path: the path to be added to the index dirs list * @return int: the result code - * 1: successful - * -1: path or its parent dir has been added - * -2: path is or under blacklist - * -3: path is in repeat mounted devices and another path which is in the same device has been indexed - * -4: another path which is in the same device has been indexed - * -5: path is not exists + * 0: successful + * 1: path or its parent dir has been added + * 2: path is or under blacklist + * 3: path is in repeat mounted devices and another path which is in the same device has been indexed + * 4: another path which is in the same device has been indexed + * 5: path is not exists */ Q_SCRIPTABLE int appendIndexableListItem(const QString &path); Q_SCRIPTABLE bool removeIndexableListItem(const QString &path); + //新接口 + Q_SCRIPTABLE int appendSearchDir(const QString &path); + Q_SCRIPTABLE void removeSearchDir(const QString &path); + + QStringList currentSearchDirs(); + QStringList currentBlackList(); + + QStringList blockDirsForUser(); + int addBlockDirOfUser(const QString& dir); + void removeBlockDirOfUser(const QString& dir); + private: DirWatcher(QObject *parent = nullptr); ~DirWatcher(); - void initData(); - void initDiskWatcher(); - void updateIndexableDirs(); - - void handleDisk(); - - bool handleIndexItemAppend(const QString &path, QStringList &blackList); - bool handleIndexItemRemove(const QString &path); static QMutex s_mutex; - DirWatcherAdaptor *m_adaptor = nullptr; - - GVolumeMonitor *m_volumeMonitor = nullptr; - quint64 m_mountAddHandle; - quint64 m_mountRemoveHandle; - - QSettings *m_qSettings = nullptr; - QStringList m_blackListOfIndex; - QStringList m_indexableDirList; - - QStringList m_searchableDirList; - QStringList m_searchableListForApplication; - QStringList m_autoMountList; - QMultiMap m_infoOfSubvolume; - QMap m_currentMountedDeviceInfo; - QMap m_repeatedlyMountedDeviceInfo; - - QStringList m_currentUDiskDeviceList; - QString m_removedUDiskDevice; - QMap m_currentUDiskDeviceInfo; - -private Q_SLOTS: - void handleAddedUDiskDevice(QDBusMessage msg); - void handleRemovedUDiskDevice(QDBusMessage msg); - Q_SIGNALS: - void udiskRemoved(); void appendIndexItem(const QString&, const QStringList&); void removeIndexItem(const QString&); + //abondoned + void udiskRemoved(); void indexDirsChanged(); }; diff --git a/ukui-search-service-dir-manager/dirwatcher/search-dir.cpp b/ukui-search-service-dir-manager/dirwatcher/search-dir.cpp new file mode 100644 index 0000000..bcaa323 --- /dev/null +++ b/ukui-search-service-dir-manager/dirwatcher/search-dir.cpp @@ -0,0 +1,356 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#include "search-dir.h" +#include "config.h" +#include "volume-manager.h" +#include + +SearchDir::SearchDir(const QString &path, bool generateBlackList) +{ + if (!QFile::exists(path)) { + m_error = NotExists; + } else { + m_path = path; + if(generateBlackList) { + this->handleBlackListGenerate(); + } + } +} + +bool SearchDir::operator ==(const SearchDir &rhs) const +{ + return (m_path == rhs.m_path); +} + +SearchDir::ErrorInfo SearchDir::error() +{ + return m_error; +} + +QString SearchDir::errorString() +{ + switch (m_error) { + case ErrorInfo::Successful: + return "Add search dir successful"; + case ErrorInfo::Duplicated: + return "Path or its parent dir has been added"; + case ErrorInfo::UnderBlackList: + return "Path is or under blacklist"; + case ErrorInfo::RepeatMount1: + return "Path is in repeat mounted devices and another path which is in the same device has been indexed"; + case ErrorInfo::RepeatMount2: + return "Another path which is in the same device has been indexed"; + case ErrorInfo::NotExists: + return "Path is not exists"; + } + return QString(); +} + +QString SearchDir::getPath() const +{ + return m_path; +} + +void SearchDir::setBlackList(const QStringList &blackList) +{ + m_blackList = blackList; +} + +QStringList SearchDir::getBlackList() const +{ + return m_blackList; +} + +void SearchDir::generateBlackList() +{ + m_blackList.clear(); + this->handleBlackListGenerate(); +} + +QStringList SearchDir::blackListOfDir(const QString &dirPath) +{ + QStringList blackListOfDir; + for (const QStringList & mountPoints: VolumeManager::self()->getDuplicates()) { + QString topRepeatedMountPoint; + for (const QString &mountPoint : mountPoints) { + //该目录下是否有两个文件夹(有可能为父子关系)是重复挂载的关系 + if (mountPoint.startsWith(dirPath + "/") or mountPoint == dirPath) { + if (topRepeatedMountPoint.isEmpty()) { + topRepeatedMountPoint = mountPoint; + continue; + } + //重复挂载时保留最上层的挂载点 + if (topRepeatedMountPoint.startsWith(mountPoint + "/")) { + blackListOfDir.append(topRepeatedMountPoint); + topRepeatedMountPoint = mountPoint; + } else { + blackListOfDir.append(mountPoint); + } + } + } + } + + for (const Volume &volume : VolumeManager::self()->volumesHaveSubVolumes()) { + for (const QString &duplicateMountPoint : volume.mountPoints()) { + QMap subVolumeInfo = volume.subVolumes(); + if (subVolumeInfo.keys().contains(duplicateMountPoint)) { + continue; + } + for (auto it = subVolumeInfo.constBegin(); it != subVolumeInfo.constEnd(); it++) { + QString spec = it.key(); + QString subMountPoint = duplicateMountPoint + it.value(); + //排除搜索列表指定多个目录时子卷会重复包含的情况,比如同时指定/home和/data/home + QString tmp = dirPath; + if (dirPath.startsWith(subMountPoint)) { + blackListOfDir.append(tmp.replace(0, subMountPoint.length(), spec)); + } + if (dirPath.startsWith(spec)) { + blackListOfDir.append(tmp.replace(0, spec.length(), subMountPoint)); + } + } + } + } + return blackListOfDir; +} + +void SearchDir::handleBlackListGenerate() +{ + QStringList searchDirs = Config::self()->searchDirs(); + + //目录已被索引(根目录被添加过直接返回) + for (const QString searchDir : searchDirs) { + if (searchDir == m_path || searchDir == "/") { + m_error = Duplicated; + return; + } + } + + //根目录特殊处理 + if (m_path == "/") { + m_blackList << Config::self()->globalBlackList() << searchDirs; + for (const QStringList &mountPoints: VolumeManager::self()->getDuplicates()) { + QStringList repeatMountPoints = mountPoints; + if (mountPoints.contains("/")) { + repeatMountPoints.removeAll("/"); + m_blackList << repeatMountPoints; + continue; + } + bool excludeAll(false); + for (const QString &mountPoint : mountPoints) { + for (const QString &searchDir : searchDirs) { + //之前已索引重复挂载设备挂载点或其子目录,则排除其他目录 + if (searchDir.startsWith(mountPoint + "/") || searchDir == mountPoint) { + repeatMountPoints.removeAll(mountPoint); + break; + } + //重复挂载点在已索引目录下,该挂载点全排除 + if (mountPoint.startsWith(searchDir + "/")) { + excludeAll = true; + break; + } + } + if (excludeAll) { + m_blackList << repeatMountPoints; + break; + } + } + //不需要全排除且没有需要特别保留的挂载点,默认留第一个 + if (!excludeAll && repeatMountPoints == mountPoints) { + repeatMountPoints.removeFirst(); + } + m_blackList << repeatMountPoints; + } + m_blackList.removeDuplicates(); + return; + } + + //处理要添加索引的路径与全局黑名单中路径为父子关系的情况 + for (const QString& blackListPath : Config::self()->globalBlackList()) { + if (m_path.startsWith(blackListPath + "/") or m_path == blackListPath) { + m_error = UnderBlackList; + return; + } + if (blackListPath.startsWith(m_path + "/")) { + m_blackList.append(blackListPath); + } + } + + //重复挂载情况 + for (const QStringList & mountPoints: VolumeManager::self()->getDuplicates()) { + QString topRepeatedMountPoint; + for (const QString &mountPoint : mountPoints) { + if (mountPoint.startsWith(m_path + "/") or mountPoint == m_path) { + if (topRepeatedMountPoint.isEmpty()) { + topRepeatedMountPoint = mountPoint; + continue; + } else if (topRepeatedMountPoint.startsWith(mountPoint)) { + m_blackList.append(topRepeatedMountPoint); + topRepeatedMountPoint = mountPoint; + } else { + m_blackList.append(mountPoint); + } + } + } + + //排除要添加的目录为某设备的重复挂载目录,并且之前已索引过该设备其他挂载目录或其父目录的情况 + bool pathToBeAddedIsRepeatedDevice = false; + bool pathToBeAddedHasRepeatedDevice = false; + bool addedPathIsRepeatedDevice = false; + bool addedPathHasRepeatedDevice = false; + QString addedRelativeDir; + QString repeatedDir; + for (const QString &addedPath : searchDirs) { + for (const QString &mountPoint : mountPoints) { + + //要添加索引路径在重复挂载设备路径下(1) + if (m_path.startsWith(mountPoint + "/") or mountPoint == m_path) { + repeatedDir = mountPoint; + pathToBeAddedIsRepeatedDevice = true; + } + //重复挂载设备路径在要添加索引路径下(2) + if (mountPoint.startsWith(m_path + "/")) { + repeatedDir = mountPoint; + pathToBeAddedHasRepeatedDevice = true; + } + + //已索引路径在重复挂载设备路径下(3) + if (addedPath.startsWith(mountPoint + "/") or mountPoint == addedPath) { + addedRelativeDir = addedPath; + addedRelativeDir.remove(0, mountPoint.length()); + addedPathIsRepeatedDevice = true; + } + //重复挂载设备路径在已索引路径下(4) + if (mountPoint.startsWith(addedPath + "/")) { + addedPathHasRepeatedDevice = true; + } + + //(1)(4)直接返回 + if (pathToBeAddedIsRepeatedDevice and addedPathHasRepeatedDevice) { + m_error = RepeatMount1; + return; + } + //(2)(4)将要添加索引目录相应的重复挂载路径添加到黑名单 + if (pathToBeAddedHasRepeatedDevice and addedPathHasRepeatedDevice) { + m_blackList.append(repeatedDir); + break; + } + //(1)(3)将已索引路径的前缀替换为要添加路径的前缀(前缀为mountPoint),判断替换后路径是否在要索引路径下,如果是则返回,否则将替换后路径添加到黑名单 + if (pathToBeAddedIsRepeatedDevice and addedPathIsRepeatedDevice) { + QString pathAfterReplace = repeatedDir + addedRelativeDir; + if (m_path.startsWith(pathAfterReplace) or m_path == pathAfterReplace) { + m_error = RepeatMount2; + return; + } else { + m_blackList.append(pathAfterReplace); + break; + } + } + //(2)(3)将替换前缀后的已索引路径添加到黑名单 + if (pathToBeAddedHasRepeatedDevice and addedPathIsRepeatedDevice) { + m_blackList.append(repeatedDir + addedRelativeDir); + break; + } + } + } + } + + //处理自动挂载子卷下的目录 + for (const Volume &volume : VolumeManager::self()->volumesHaveSubVolumes()) { + QMap subVolumeInfo = volume.subVolumes(); + for (auto it = subVolumeInfo.constBegin(); it != subVolumeInfo.constEnd(); it++) { + QString subMountPoint = it.key(); + for (const QString &duplicateMountPoint : volume.mountPoints()) { + if (subVolumeInfo.keys().contains(duplicateMountPoint)) { + continue; + } + QString spec = duplicateMountPoint + it.value(); //子卷对应目录 + //要添加目录下存在子卷(要添加/data,但挂到/home的/data/home是子卷),若添加了/home则将/data/home排除 + if (spec.startsWith(m_path + "/")) { + for (QString &searchDir : searchDirs) { + if (searchDir == subMountPoint || subMountPoint.startsWith(searchDir + "/")) { + m_blackList << spec; + } + if (searchDir.startsWith(subMountPoint + "/")) { + m_blackList << searchDir.replace(0, subMountPoint.length(), spec); + } + } + + } + + //要添加的目录是子卷或在子卷下(/data/home or /data/home/xxx) + if (m_path.startsWith(spec + "/") || m_path == spec) { + for (QString &searchDir : searchDirs) { + //已添加挂载点或其上层目录 + if (subMountPoint.startsWith(searchDir + "/") || searchDir == subMountPoint) { + m_error = RepeatMount1; + return; + } + //已添加挂载点下其他目录 + if (searchDir.startsWith(subMountPoint + "/")) { + QString tmp = searchDir; + tmp.replace(0, subMountPoint.length(), spec); + if (tmp == m_path) { + m_error = RepeatMount2; + return; + } else if (tmp.startsWith(m_path + "/")) {//已添加的子卷子目录替换前缀后在要添加目录下 + m_blackList << tmp; + } + } + } + } + + //要添加的目录是挂载点或在挂载点下(/home or /home/xxx) + if (m_path.startsWith(subMountPoint + "/") || m_path == subMountPoint) { + for (QString &searchDir : searchDirs) { + //已添加子卷或其上层目录 + if (spec.startsWith(searchDir + "/") || searchDir == spec) { + m_error = RepeatMount1; + return; + } + //已添加子卷下其他目录 + if (searchDir.startsWith(spec + "/")) { + QString tmp = searchDir; + tmp.replace(0, spec.length(), subMountPoint); + if (tmp == m_path) { + m_error = RepeatMount2; + return; + } else if (tmp.startsWith(m_path + "/")) {//已添加的子卷子目录替换前缀后在要添加目录下 + m_blackList << tmp; + } + } + } + } + } + } + + } + + //要添加目录下存在已索引目录 + for (const QString &searchDir : searchDirs) { + if (m_path.startsWith(searchDir + "/")) { + m_error = Duplicated; + return; + } + if (searchDir.startsWith(m_path + "/")) { + m_blackList.append(searchDir); + } + } + m_blackList.removeDuplicates(); +} diff --git a/ukui-search-service-dir-manager/dirwatcher/search-dir.h b/ukui-search-service-dir-manager/dirwatcher/search-dir.h new file mode 100644 index 0000000..9af3171 --- /dev/null +++ b/ukui-search-service-dir-manager/dirwatcher/search-dir.h @@ -0,0 +1,54 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef SEARCHDIR_H +#define SEARCHDIR_H +#include +class SearchDir +{ +public: + enum ErrorInfo{ + Successful = 0, + Duplicated, + UnderBlackList, + RepeatMount1, + RepeatMount2, + NotExists + }; + SearchDir() = default; + SearchDir(const QString& path, bool generateBlackList = true); + bool operator == (const SearchDir& rhs) const; + ErrorInfo error(); + QString errorString(); + QString getPath() const; + void setBlackList(const QStringList& blackList); + QStringList getBlackList() const; + /** + * @brief 重新生成黑名单 + */ + void generateBlackList(); + static QStringList blackListOfDir(const QString &dirPath); +private: + void handleBlackListGenerate(); + QString m_path; + QStringList m_blackList; + ErrorInfo m_error = ErrorInfo::Successful; +}; + +#endif // SEARCHDIR_H diff --git a/ukui-search-service-dir-manager/dirwatcher/volume-manager.cpp b/ukui-search-service-dir-manager/dirwatcher/volume-manager.cpp new file mode 100644 index 0000000..dc1d6ff --- /dev/null +++ b/ukui-search-service-dir-manager/dirwatcher/volume-manager.cpp @@ -0,0 +1,177 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#include "volume-manager.h" +#include +#include +#include +static std::once_flag flag; +static VolumeManager *global_instance = nullptr; + +Volume::Volume() +{ +} + +Volume::Volume(const QString& device) +{ + m_device = device; +} + +QString Volume::device() +{ + return m_device; +} + +QStringList Volume::duplicatesMountPoints() const +{ + QStringList tmp; + for (auto iter = m_mountPoints.constBegin(); iter != m_mountPoints.constEnd(); ++iter) { + if(iter.value().isEmpty()) { + tmp.append(iter.key()); + } + } + if(tmp.size() == 1) { + tmp.clear(); + } + return tmp; +} + +QMap Volume::subVolumes() const +{ + QMap tmp; + for (auto iter = m_mountPoints.constBegin(); iter != m_mountPoints.constEnd(); ++iter) { + if(!iter.value().isEmpty()) { + tmp.insert(iter.key(), iter.value()); + } + } + return tmp; +} + +QStringList Volume::mountPoints() const +{ + return m_mountPoints.keys(); +} + +void Volume::setDevice(const QString& device) +{ + m_device = device; +} + +void Volume::addMountPoint(const QString &mountPoint, const QString &subVolume) +{ + m_mountPoints.insert(mountPoint, subVolume); +} + +VolumeManager *VolumeManager::self() +{ + std::call_once(flag, [ & ] { + global_instance = new VolumeManager(); + }); + return global_instance; +} + +VolumeManager::VolumeManager(QObject *parent) + : QObject{parent} +{ + this->refresh(); + m_volumeMonitor = g_volume_monitor_get(); + if (!m_volumeMonitor) { + qDebug() << "Fail to init volume monitor"; + return; + } + + m_mountAddHandle = g_signal_connect(m_volumeMonitor, "mount-added", G_CALLBACK(mountAddCallback), this); + m_mountRemoveHandle = g_signal_connect(m_volumeMonitor, "mount-removed", G_CALLBACK(mountRemoveCallback), this); +} + +VolumeManager::~VolumeManager() +{ + if(m_volumeMonitor){ + g_signal_handler_disconnect(m_volumeMonitor, m_mountAddHandle); + g_signal_handler_disconnect(m_volumeMonitor, m_mountRemoveHandle); + g_object_unref(m_volumeMonitor); + m_volumeMonitor = nullptr; + } +} + +QVector VolumeManager::getDuplicates() +{ + QMutexLocker locker(&m_mutex); + QVector tmp; + for (auto iter = m_volumes.constBegin(); iter != m_volumes.constEnd(); ++iter) { + QStringList duplicates = iter.value().duplicatesMountPoints(); + if(!duplicates.isEmpty()) { + tmp.append(duplicates); + } + } + return tmp; + +} + +QVector VolumeManager::volumesHaveSubVolumes() +{ + QMutexLocker locker(&m_mutex); + QVector tmp; + for (auto iter = m_volumes.constBegin(); iter != m_volumes.constEnd(); ++iter) { + if(!iter.value().subVolumes().isEmpty()) { + tmp.append(iter.value()); + } + } + return tmp; +} + +QVector VolumeManager::volumes() +{ + QMutexLocker locker(&m_mutex); + return m_volumes.values().toVector(); +} + +void VolumeManager::refresh() +{ + QMutexLocker locker(&m_mutex); + m_volumes.clear(); + //遍历当前系统所有挂载设备 + for (const QStorageInfo &storage: QStorageInfo::mountedVolumes()) { + if (storage.isValid() and storage.isReady()) { + Volume volume(storage.device()); + if(m_volumes.contains(storage.device())) { + volume = m_volumes.value(storage.device()); + } + volume.addMountPoint(storage.rootPath(), storage.subvolume()); + m_volumes.insert(storage.device(), volume); + } + } + Q_EMIT VolumeDataUpdated(); +} + +void VolumeManager::mountAddCallback(GVolumeMonitor *monitor, GMount *gmount, VolumeManager *pThis) +{ + Q_UNUSED(monitor) + Q_UNUSED(gmount) + //TODO 识别U盘等移动设备 + pThis->refresh(); +} + +void VolumeManager::mountRemoveCallback(GVolumeMonitor *monitor, GMount *gmount, VolumeManager *pThis) +{ + Q_UNUSED(monitor) + Q_UNUSED(gmount) + pThis->refresh(); +} + diff --git a/ukui-search-service-dir-manager/dirwatcher/volume-manager.h b/ukui-search-service-dir-manager/dirwatcher/volume-manager.h new file mode 100644 index 0000000..10e8792 --- /dev/null +++ b/ukui-search-service-dir-manager/dirwatcher/volume-manager.h @@ -0,0 +1,77 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ +#ifndef VOLUMEMANAGER_H +#define VOLUMEMANAGER_H + +#undef slots +#undef signals +#undef emit + +#include +#include +#include +#include +#include +#include +#include + +class Volume +{ +public: + Volume(); + Volume(const QString& device); + QString device(); + QStringList duplicatesMountPoints() const; + QMap subVolumes() const; + QStringList mountPoints() const; + + void setDevice(const QString& device); + void addMountPoint(const QString& mountPoint, const QString& subVolume = QString()); +private: + QString m_device; + QMap m_mountPoints; //挂载点->子卷路径 +}; + +class VolumeManager : public QObject +{ + Q_OBJECT +public: + static VolumeManager *self(); + ~VolumeManager(); + QVector getDuplicates(); + QVector volumesHaveSubVolumes(); + QVector volumes(); +Q_SIGNALS: + void VolumeDataUpdated(); + +private: + explicit VolumeManager(QObject *parent = nullptr); + void refresh(); + static void mountAddCallback(GVolumeMonitor *monitor, GMount *gmount, VolumeManager *pThis); + static void mountRemoveCallback(GVolumeMonitor *monitor, GMount *gmount, VolumeManager *pThis); + GVolumeMonitor* m_volumeMonitor = nullptr; + quint64 m_mountAddHandle; + quint64 m_mountRemoveHandle; + QMap m_volumes; //device -> Volume + QMutex m_mutex; +}; + + +#endif // VOLUMEMANAGER_H diff --git a/ukui-search-service-dir-manager/main.cpp b/ukui-search-service-dir-manager/main.cpp index 89cdd05..1f8eed6 100644 --- a/ukui-search-service-dir-manager/main.cpp +++ b/ukui-search-service-dir-manager/main.cpp @@ -1,10 +1,10 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* * - * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * Copyright (C) 2023, KylinSoft Co., Ltd. * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -13,61 +13,17 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . * + * Authors: iaom */ -#include -#include -#include -#include -#include + #include #include +#include #include +#include "log-utils.h" #include "ukui-search-dir-manager-dbus.h" -void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) -{ - QByteArray localMsg = msg.toLocal8Bit(); - QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit(); - - bool showDebug = true; - QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search-service-dir-manager.log"; - if (!QFile::exists(logFilePath)) { - showDebug = false; - } - FILE *log_file = nullptr; - - if (showDebug) { - log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+"); - } - - const char *file = context.file ? context.file : ""; - const char *function = context.function ? context.function : ""; - switch (type) { - case QtDebugMsg: - if (!log_file) { - break; - } - fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtInfoMsg: - fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtWarningMsg: - fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtCriticalMsg: - fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtFatalMsg: - fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - } - - if (log_file) - fclose(log_file); -} int main(int argc, char *argv[]) { @@ -92,7 +48,8 @@ int main(int argc, char *argv[]) } // Output log to file - qInstallMessageHandler(messageOutput); + LogUtils::initLogFile("ukui-search-service-dir-manager"); + qInstallMessageHandler(LogUtils::messageOutput); #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); diff --git a/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.cpp b/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.cpp index 6b6625b..45cc8aa 100644 --- a/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.cpp +++ b/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.cpp @@ -1,6 +1,25 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iaom + */ #include "ukui-search-dir-manager-dbus.h" #include "dir-watcher.h" - +#include #include #include #include diff --git a/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.h b/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.h index d8f7f96..ae38209 100644 --- a/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.h +++ b/ukui-search-service-dir-manager/ukui-search-dir-manager-dbus.h @@ -1,3 +1,21 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ #ifndef UKUISEARCHDIRWATCHERDBUS_H #define UKUISEARCHDIRWATCHERDBUS_H diff --git a/ukui-search-service-dir-manager/ukui-search-service-dir-manager.pro b/ukui-search-service-dir-manager/ukui-search-service-dir-manager.pro deleted file mode 100644 index 7e1f308..0000000 --- a/ukui-search-service-dir-manager/ukui-search-service-dir-manager.pro +++ /dev/null @@ -1,45 +0,0 @@ -QT += core dbus -QT -= gui - -TARGET = ukui-search-service-dir-manager -VERSION = 1.0.0 -DEFINES += VERSION='\\"$${VERSION}\\"' -TEMPLATE = app - -CONFIG += c++11 link_pkgconfig -#CONFIG -= app_bundle -PKGCONFIG += gio-2.0 gio-unix-2.0 - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -include(dirwatcher/dir-watcher-dbus.pri) -include(../3rd-parties/qtsingleapplication/qtsingleapplication.pri) - -inst1.files += conf/com.ukui.search.fileindex.service -inst1.path = /usr/share/dbus-1/services/ - -target.source += $$TARGET -target.path = /usr/bin -INSTALLS += \ - target \ - inst1 - -desktop.path = /etc/xdg/autostart -desktop.files += ../data/ukui-search-service-dir-manager.desktop -INSTALLS += desktop - -SOURCES += \ - main.cpp \ - ukui-search-dir-manager-dbus.cpp - -HEADERS += \ - ukui-search-dir-manager-dbus.h diff --git a/ukui-search-service/CMakeLists.txt b/ukui-search-service/CMakeLists.txt new file mode 100644 index 0000000..7d105ea --- /dev/null +++ b/ukui-search-service/CMakeLists.txt @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 3.14) +project(ukui-search-service VERSION 1.0.0 LANGUAGES C CXX) + +set(VERSION_MAJOR 1) +set(VERSION_MINOR 0) +set(VERSION_MICRO 0) +set(UKUI_SEARCH_SERVICE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus Gui Quick Widgets REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus Gui Quick Widgets REQUIRED) +find_package(PkgConfig REQUIRED) +set(UKUI_SEARCH_SERVICE_EXTERNAL_LIBS "") +set(UKUI_SEARCH_SERVICE_PC_PKGS gsettings-qt) + +foreach(PC_LIB IN ITEMS ${UKUI_SEARCH_SERVICE_PC_PKGS}) + pkg_check_modules(${PC_LIB} REQUIRED IMPORTED_TARGET ${PC_LIB}) + if(${${PC_LIB}_FOUND}) + include_directories(${${PC_LIB}_INCLUDE_DIRS}) + link_directories(${${PC_LIB}_LIBRARY_DIRS}) + list(APPEND UKUI_SEARCH_SERVICE_EXTERNAL_LIBS PkgConfig::${PC_LIB}) + endif() +endforeach() + +set(QRC_FILES qml/qml.qrc) +add_executable(ukui-search-service + main.cpp + ukui-search-service.cpp ukui-search-service.h + ${QRC_FILES} +) +target_include_directories(ukui-search-service PRIVATE + ../3rd-parties/qtsingleapplication/src + ../libsearch + ../libsearch/dirwatcher + ../libsearch/filesystemwatcher + ../libsearch/index + ../libsearch/parser +) + +target_compile_definitions(ukui-search-service PRIVATE + QT_DEPRECATED_WARNINGS + VERSION="UKUI_SEARCH_SERVICE_VERSION" + QT_NO_KEYWORDS + ) + +target_link_libraries(ukui-search-service PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Quick + Qt${QT_VERSION_MAJOR}::Widgets + libukui-search + qtsingleapplication + ${UKUI_SEARCH_SERVICE_EXTERNAL_LIBS} +) +install(FILES ../data/org.ukui.search.data.gschema.xml DESTINATION /usr/share/glib-2.0/schemas/) +install(FILES ../data/ukui-search-service.desktop DESTINATION /etc/xdg/autostart) +install(TARGETS ukui-search-service DESTINATION /usr/bin) diff --git a/ukui-search-service/main.cpp b/ukui-search-service/main.cpp index bddb052..55ef2f9 100644 --- a/ukui-search-service/main.cpp +++ b/ukui-search-service/main.cpp @@ -17,60 +17,12 @@ * Authors: iaom * */ -#include -#include -#include -#include -#include + #include #include -#include #include "ukui-search-service.h" +#include "log-utils.h" using namespace UkuiSearch; -void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) -{ - QByteArray localMsg = msg.toLocal8Bit(); - QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit(); - - bool showDebug = true; -// QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/ukui-search.log"; -// QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search/ukui-search.log"; - QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search-service.log"; - if (!QFile::exists(logFilePath)) { - showDebug = false; - } - FILE *log_file = nullptr; - - if (showDebug) { - log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+"); - } - - const char *file = context.file ? context.file : ""; - const char *function = context.function ? context.function : ""; - switch (type) { - case QtDebugMsg: - if (!log_file) { - break; - } - fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtInfoMsg: - fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtWarningMsg: - fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtCriticalMsg: - fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - case QtFatalMsg: - fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); - break; - } - - if (log_file) - fclose(log_file); -} int main(int argc, char *argv[]) { char *p_home = NULL; @@ -94,7 +46,8 @@ int main(int argc, char *argv[]) } // Output log to file - qInstallMessageHandler(messageOutput); + LogUtils::initLogFile("ukui-search-service"); + qInstallMessageHandler(LogUtils::messageOutput); #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); diff --git a/ukui-search-service/qml/qml.pri b/ukui-search-service/qml/qml.pri deleted file mode 100644 index 51168f2..0000000 --- a/ukui-search-service/qml/qml.pri +++ /dev/null @@ -1,9 +0,0 @@ -# 编译qrc资源 -qmlFile.files = $$files($$PWD/*.qml) -RESOURCES += qmlFile - -DISTFILES += \ - $$PWD/IndexMonitor.qml \ - $$PWD/IndexProgressBar.qml \ - $$PWD/StatusKeyValue.qml - diff --git a/ukui-search-service/qml/qml.qrc b/ukui-search-service/qml/qml.qrc new file mode 100644 index 0000000..27d8663 --- /dev/null +++ b/ukui-search-service/qml/qml.qrc @@ -0,0 +1,25 @@ + + + + + IndexMonitor.qml + IndexProgressBar.qml + StatusKeyValue.qml + + diff --git a/ukui-search-service/ukui-search-service.cpp b/ukui-search-service/ukui-search-service.cpp index 9eb6985..fef85ad 100644 --- a/ukui-search-service/ukui-search-service.cpp +++ b/ukui-search-service/ukui-search-service.cpp @@ -68,9 +68,6 @@ void UkuiSearchService::parseCmd(QString msg, bool isPrimary) QCommandLineOption quitOption(QStringList()<<"q"<<"quit", tr("Stop service")); parser.addOption(quitOption); - QCommandLineOption startOption(QStringList()<<"i"<<"index", tr("start or stop file index"), "option"); - parser.addOption(startOption); - QCommandLineOption monitorWindow(QStringList()<<"m"<<"monitor", tr("Show index monitor window")); parser.addOption(monitorWindow); @@ -80,15 +77,6 @@ void UkuiSearchService::parseCmd(QString msg, bool isPrimary) if (isPrimary) { const QStringList args = QString(msg).split(' '); parser.process(args); - if(parser.isSet(startOption)) { - qDebug() << "options!!!!" << parser.value(startOption); - if(parser.value(startOption) == "start") { - m_indexScheduler->start(); - } else if (parser.value(startOption) == "stop") { - m_indexScheduler->stop(); - } - } - if (parser.isSet(monitorWindow)) { loadMonitorWindow(); m_quickView->show(); diff --git a/ukui-search-service/ukui-search-service.h b/ukui-search-service/ukui-search-service.h index c0ee5ca..3fd274c 100644 --- a/ukui-search-service/ukui-search-service.h +++ b/ukui-search-service/ukui-search-service.h @@ -1,3 +1,22 @@ +/* + * + * Copyright (C) 2023, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * * Authors: iaom + */ #ifndef UKUISEARCHSERVICE_H #define UKUISEARCHSERVICE_H diff --git a/ukui-search-service/ukui-search-service.pro b/ukui-search-service/ukui-search-service.pro deleted file mode 100644 index a6b327a..0000000 --- a/ukui-search-service/ukui-search-service.pro +++ /dev/null @@ -1,47 +0,0 @@ -QT += core gui dbus quick - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - - -TARGET = ukui-search-service -VERSION = 1.0.0 -DEFINES += VERSION='\\"$${VERSION}\\"' -CONFIG += c++11 link_pkgconfig no_keywords lrelease -PKGCONFIG += gsettings-qt gio-unix-2.0 - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -include(../libsearch/libukui-search-headers.pri) -include(../3rd-parties/qtsingleapplication/qtsingleapplication.pri) -include(./qml/qml.pri) - -LIBS += -L$$OUT_PWD/../libchinese-segmentation -lchinese-segmentation \ - -L$$OUT_PWD/../libsearch -lukui-search - -SOURCES += \ - main.cpp \ - ukui-search-service.cpp - -schemes.path = /usr/share/glib-2.0/schemas/ -schemes.files += ../data/org.ukui.search.data.gschema.xml - -INSTALLS += schemes - -target.path = /usr/bin -INSTALLS += target - -desktop.path = /etc/xdg/autostart -desktop.files += ../data/ukui-search-service.desktop -INSTALLS += desktop - -HEADERS += \ - ukui-search-service.h diff --git a/ukui-search.pro b/ukui-search.pro deleted file mode 100644 index 9df4816..0000000 --- a/ukui-search.pro +++ /dev/null @@ -1,33 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += $$PWD/libchinese-segmentation \ - $$PWD/libsearch \ - $$PWD/frontend \ - $$PWD/ukuisearch-systemdbus \ - $$PWD/search-ukcc-plugin \ - $$PWD/ukui-search-service \ - $$PWD/ukui-search-app-data-service \ - $$PWD/ukui-search-service-dir-manager - -#SUBDIRS += tests - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -libsearch.depends += libchinese-segmentation -ukui-search-service.depends += libsearch -#src.depends = libsearch -frontend.depends = libsearch - -CONFIG += ordered - -QT += widgets - - diff --git a/ukuisearch-systemdbus/CMakeLists.txt b/ukuisearch-systemdbus/CMakeLists.txt new file mode 100644 index 0000000..5535ac8 --- /dev/null +++ b/ukuisearch-systemdbus/CMakeLists.txt @@ -0,0 +1,16 @@ +set(CMAKE_AUTOMOC ON) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core DBus REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus REQUIRED) + +add_executable(ukui-search-systemdbus + main.cpp + sysdbusregister.cpp sysdbusregister.h +) +target_link_libraries(ukui-search-systemdbus PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus +) +install(FILES conf/com.ukui.search.qt.systemdbus.service DESTINATION /usr/share/dbus-1/system-services/) +install(FILES conf/com.ukui.search.qt.systemdbus.conf DESTINATION /usr/share/dbus-1/system.d/) + +install(TARGETS ukui-search-systemdbus RUNTIME DESTINATION /usr/bin) diff --git a/ukuisearch-systemdbus/main.cpp b/ukuisearch-systemdbus/main.cpp index eae7df1..1195840 100644 --- a/ukuisearch-systemdbus/main.cpp +++ b/ukuisearch-systemdbus/main.cpp @@ -29,7 +29,6 @@ int main(int argc, char *argv[]) { app.setOrganizationName("Kylin Team"); app.setApplicationName("ukui-search-service"); - QDBusConnection systemBus = QDBusConnection::systemBus(); if(!systemBus.registerService("com.ukui.search.qt.systemdbus")) { qCritical() << "QDbus register service failed reason:" << systemBus.lastError(); diff --git a/ukuisearch-systemdbus/sysdbusregister.cpp b/ukuisearch-systemdbus/sysdbusregister.cpp index c11c4b5..e6b1841 100644 --- a/ukuisearch-systemdbus/sysdbusregister.cpp +++ b/ukuisearch-systemdbus/sysdbusregister.cpp @@ -20,10 +20,8 @@ #include "sysdbusregister.h" #include -#include #include -#include -#include +#include SysdbusRegister::SysdbusRegister() { } diff --git a/ukuisearch-systemdbus/sysdbusregister.h b/ukuisearch-systemdbus/sysdbusregister.h index a52d75d..1bcc83e 100644 --- a/ukuisearch-systemdbus/sysdbusregister.h +++ b/ukuisearch-systemdbus/sysdbusregister.h @@ -44,7 +44,7 @@ public: // Q_SCRIPTABLE void nameChanged(QString); // Q_SCRIPTABLE void computerinfo(QString); -public slots: +public Q_SLOTS: Q_SCRIPTABLE void exitService(); // Q_SCRIPTABLE QString GetComputerInfo(); diff --git a/ukuisearch-systemdbus/ukuisearch-systemdbus.pro b/ukuisearch-systemdbus/ukuisearch-systemdbus.pro deleted file mode 100644 index 7097cea..0000000 --- a/ukuisearch-systemdbus/ukuisearch-systemdbus.pro +++ /dev/null @@ -1,32 +0,0 @@ -QT += core dbus -QT -= gui -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -VERSION = 0.0.1 -TARGET = ukui-search-systemdbus -TEMPLATE = app - -CONFIG += console c++11 link_pkgconfig -CONFIG -= app_bundle - -DESTDIR = . -INCLUDEPATH += . - -inst1.files += conf/com.ukui.search.qt.systemdbus.service -inst1.path = /usr/share/dbus-1/system-services/ -inst2.files += conf/com.ukui.search.qt.systemdbus.conf -inst2.path = /usr/share/dbus-1/system.d - -target.source += $$TARGET -target.path = /usr/bin -INSTALLS += \ - target \ - inst1 \ - inst2 - -HEADERS += \ - sysdbusregister.h - -SOURCES += \ - main.cpp \ - sysdbusregister.cpp