mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 19:24:08 +00:00
Merge pull request #856 from xiaoyifang/fix/macos-ooi
fix: refactor editDictionary logic
This commit is contained in:
commit
2ee2271e91
239
.github/workflows/macos-homebrew-nobreakpad.yml
vendored
Normal file
239
.github/workflows/macos-homebrew-nobreakpad.yml
vendored
Normal file
|
@ -0,0 +1,239 @@
|
|||
name: macos-homebrew-nobreakpad
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- master
|
||||
# - staged
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- ".github/**"
|
||||
- "howto/**"
|
||||
- "*.md"
|
||||
- ".clang-format"
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-12,macos-13]
|
||||
qt_ver: [ 6.5.1 ]
|
||||
qt_arch: [clang_64]
|
||||
env:
|
||||
targetName: GoldenDict
|
||||
version: 23.06.02
|
||||
version-suffix: alpha
|
||||
prerelease: true
|
||||
steps:
|
||||
# macos 11.0 默认环境变了,要指定
|
||||
- name: prepare env
|
||||
if: ${{ matrix.os == 'macos-11' }}
|
||||
run: |
|
||||
softwareupdate --all --install --force
|
||||
sudo xcode-select --print-path
|
||||
sudo xcode-select --switch /Library/Developer/CommandLineTools
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
- name: Set outputs
|
||||
id: githash
|
||||
run: |
|
||||
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
||||
|
||||
- name: install deps on macos
|
||||
run: |
|
||||
brew install pcre2 harfbuzz freetype
|
||||
brew install cmake ninja python
|
||||
brew install automake
|
||||
brew install autoconf
|
||||
brew install libtool
|
||||
brew install opencc
|
||||
brew install speex
|
||||
brew install wavpack
|
||||
brew install automake fdk-aac git lame libass libtool libvorbis libvpx opus sdl shtool texi2html theora wget x264 x265 xvid nasm
|
||||
brew install speex
|
||||
|
||||
brew tap homebrew-ffmpeg/ffmpeg
|
||||
brew install homebrew-ffmpeg/ffmpeg/ffmpeg --with-speex
|
||||
|
||||
brew install libiconv
|
||||
brew install lzo bzip2
|
||||
brew install libogg
|
||||
brew install zstd lzip
|
||||
brew install libvorbis
|
||||
brew install hunspell
|
||||
git clone https://github.com/xiaoyifang/eb.git
|
||||
cd eb && ./configure && make -j 8 && sudo make install && cd ..
|
||||
brew install xz lzo
|
||||
brew install pkg-config
|
||||
brew install create-dmg
|
||||
brew install xapian
|
||||
brew install libzim
|
||||
# brew reinstall icu4c
|
||||
brew install dylibbundler
|
||||
find /opt -name libicudata.72.dylib
|
||||
find /usr/local -name libicudata.72.dylib
|
||||
- name: version-file
|
||||
shell: bash
|
||||
run: |
|
||||
current_tag=$(git tag --sort=-creatordate | grep "v.*" | sed -n 1p |cut -c 2-)
|
||||
echo "$current_tag">version.txt
|
||||
|
||||
- name: vcpkg install
|
||||
shell: bash
|
||||
run: |
|
||||
vcpkg install breakpad
|
||||
- name: copy vcpkg packages into winlibs
|
||||
shell: bash
|
||||
run: |
|
||||
ls -al /usr/local/share/vcpkg/packages/breakpad*
|
||||
cp -R /usr/local/share/vcpkg/packages/breakpad*/* thirdparty/breakpad
|
||||
ls -al thirdparty/breakpad/lib
|
||||
- uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ matrix.qt_ver }}
|
||||
arch: ${{ matrix.qt_arch }}
|
||||
|
||||
modules: qtwebengine qtwebchannel qtpositioning qt5compat qtmultimedia qtimageformats qtspeech
|
||||
setup-python: 'false'
|
||||
|
||||
- name: compile
|
||||
run: |
|
||||
qmake CONFIG+=release CONFIG+=no_macos_universal CONFIG+=zim_support CONFIG+=use_xapian
|
||||
make -j8
|
||||
|
||||
- name: package
|
||||
run: |
|
||||
|
||||
macdeployqt ${targetName}.app -qmldir=. -verbose=1
|
||||
otool -L GoldenDict.app/Contents/MacOS/GoldenDict
|
||||
ls -al GoldenDict.app/Contents/Frameworks
|
||||
otool -L GoldenDict.app/Contents/Frameworks/libicu*.dylib
|
||||
cp -r /usr/local/Cellar/icu4c/7*/lib/libicudata.*.dylib GoldenDict.app/Contents/Frameworks
|
||||
|
||||
codesign --force --deep -s - GoldenDict.app
|
||||
|
||||
ls -al GoldenDict.app/Contents/Frameworks
|
||||
mkdir tmp
|
||||
mv ${targetName}.app ./tmp
|
||||
# --background "installer_background.png"
|
||||
create-dmg --volname "${targetName} Installer" --volicon "icons/macicon.icns" --window-pos 200 120 --window-size 800 400 --icon-size 100 --icon "${targetName}.app" 200 190 --hide-extension "${targetName}.app" --app-drop-link 600 185 --skip-jenkins "${targetName}.dmg" tmp/
|
||||
- name: changelog
|
||||
id: changelog
|
||||
run: |
|
||||
previousTag=$(git tag --sort=-creatordate | grep "v.*" | sed -n 2p)
|
||||
echo "previousTag : $previousTag"
|
||||
|
||||
CHANGELOG="$(git log --oneline --no-decorate $previousTag..HEAD)"
|
||||
CHANGELOG="${CHANGELOG//'%'/'%25'}"
|
||||
CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
|
||||
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
|
||||
CHANGELOG="${CHANGELOG//'\"'/'%22'}"
|
||||
CHANGELOG="${CHANGELOG//"'"/ }"
|
||||
echo "::set-output name=changelog::$(echo "$CHANGELOG")"
|
||||
echo "::set-output name=prev_tag::$previousTag"
|
||||
echo "::set-output name=curr_tag::$(git tag --sort=-creatordate | grep "v.*" | sed -n 1p)"
|
||||
|
||||
- name: Set outputs
|
||||
id: vars
|
||||
run: |
|
||||
echo "::set-output name=sha_short::$(git rev-parse --short=8 HEAD)"
|
||||
echo "::set-output name=release_date::$(date +'%Y%m%d')"
|
||||
echo "::set-output name=release_time::$(date +'%H%M%S')"
|
||||
echo "::set-output name=release_time_clock::$(date +'%H:%M:%S')"
|
||||
echo "::set-output name=release_hm::$(date +'%y%m%d')"
|
||||
|
||||
# tag 上传Release
|
||||
- name: "Build Changelog"
|
||||
id: build_changelog
|
||||
uses: mikepenz/release-changelog-builder-action@v3
|
||||
with:
|
||||
commitMode: false
|
||||
fromTag: ${{ steps.changelog.outputs.prev_tag }}
|
||||
toTag: "${{ steps.changelog.outputs.curr_tag }}"
|
||||
configurationJson: |
|
||||
{
|
||||
"template": "#{{CHANGELOG}}\n\n<details>\n<summary>🔴 Uncategorized</summary>\n\n#{{UNCATEGORIZED}}\n</details>",
|
||||
"categories": [
|
||||
{
|
||||
"title": "## 🚀 Features",
|
||||
"labels": ["feature","feat","opt"]
|
||||
},
|
||||
{
|
||||
"title": "## 🐛 Fixes",
|
||||
"labels": ["fix","bug"]
|
||||
}
|
||||
,
|
||||
{
|
||||
"title": "## 🤖 Github action",
|
||||
"labels": ["action"]
|
||||
}
|
||||
,
|
||||
{
|
||||
"title": "## 🧼 Clean Code",
|
||||
"labels": ["clean"]
|
||||
}
|
||||
|
||||
],
|
||||
"label_extractor": [
|
||||
{
|
||||
"pattern": "([^:]*):.*",
|
||||
"target": "$1",
|
||||
"on_property": "title",
|
||||
"flags": "gu"
|
||||
}
|
||||
]
|
||||
}
|
||||
- name: uploadRelease
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ${{ env.targetName }}.dmg
|
||||
asset_name: ${{ matrix.qt_ver }}-${{ env.targetName }}_${{ matrix.os }}_homebrew_${{steps.vars.outputs.release_date}}.dmg
|
||||
|
||||
overwrite: true
|
||||
release_name: GoldenDict-ng-v${{env.version}}-${{env.version-suffix}}.${{ steps.vars.outputs.release_hm }}.${{ steps.vars.outputs.sha_short }}
|
||||
prerelease: ${{env.prerelease}}
|
||||
body: |
|
||||
release on date: ${{steps.vars.outputs.release_date}} time: ${{steps.vars.outputs.release_time_clock}}
|
||||
branch: ${{ github.ref_name }}
|
||||
commit: ${{ steps.vars.outputs.sha_short }}
|
||||
Qt version: Qt5.15.2, Qt6.X
|
||||
Windows built with: msvc64, Visual studio 2019
|
||||
## goldendict.exe can not be used alone
|
||||
if you have a previous version. replace this maybe ok. if not ,download the whole bundle.
|
||||
|
||||
AppImage built with: Ubuntu-20.04 ,latest gcc
|
||||
macos built with: macos-10.15,macos-11.0,clang_64 x86_64
|
||||
Qt6.X(homebrew build)
|
||||
Qt5.15.2(Intel Kind)
|
||||
auto built by github action. use on your on risk:-)
|
||||
**recommend version**:Qt6.X (with the latest bug fixes and performance enhancements)
|
||||
|
||||
Filename pattern: **[Qt version]-GoldenDict-[OS]-[release-date].[ext]**
|
||||
[xapian](https://xapian.org/) is enabled by default which offers 10X~20X performance
|
||||
------------------------------
|
||||
文件名的模式: **[Qt version]-GoldenDict-[OS]-[release-date].[ext]**
|
||||
[xapian](https://xapian.org/) 用于全文索引的创建,提供更快的全文索引创建、搜索支持
|
||||
比如:
|
||||
6.4.3-GoldenDict.exe_windows-2022_20230502.zip
|
||||
表示基于qt6.4.3,windows-2022, 于20230502日创建的版本。
|
||||
|
||||
|
||||
CHANGES:
|
||||
${{ steps.changelog.outputs.changelog }}
|
||||
|
||||
----------------
|
||||
|
||||
${{steps.build_changelog.outputs.changelog}}
|
70
.github/workflows/macos-homebrew-xapian.yml
vendored
70
.github/workflows/macos-homebrew-xapian.yml
vendored
|
@ -1,28 +1,28 @@
|
|||
name: macos-homebrew-xapian
|
||||
name: macos-homebrew-breakpad
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- master
|
||||
# - staged
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- ".github/**"
|
||||
- "howto/**"
|
||||
- "*.md"
|
||||
- ".clang-format"
|
||||
#push:
|
||||
# branches:
|
||||
# - dev
|
||||
# - master
|
||||
# # - staged
|
||||
# paths-ignore:
|
||||
# - 'docs/**'
|
||||
# - ".github/**"
|
||||
# - "howto/**"
|
||||
# - "*.md"
|
||||
# - ".clang-format"
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-11,macos-12]
|
||||
qt_ver: [ 6.5.1 ]
|
||||
os: [macos-13]
|
||||
qt_ver: [ 6.4.3,6.5.1 ]
|
||||
qt_arch: [clang_64]
|
||||
env:
|
||||
targetName: GoldenDict
|
||||
|
@ -37,18 +37,7 @@ jobs:
|
|||
softwareupdate --all --install --force
|
||||
sudo xcode-select --print-path
|
||||
sudo xcode-select --switch /Library/Developer/CommandLineTools
|
||||
- uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ matrix.qt_ver }}
|
||||
arch: ${{ matrix.qt_arch }}
|
||||
|
||||
modules: qtwebengine qtwebchannel qtpositioning qt5compat qtmultimedia qtimageformats qtspeech
|
||||
setup-python: 'false'
|
||||
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
@ -102,15 +91,38 @@ jobs:
|
|||
echo "$VAR_VERSION-$VAR_SUFFIX.$release_date.$current_tag">version.txt
|
||||
cat version.txt
|
||||
echo "$version"
|
||||
|
||||
- name: vcpkg install
|
||||
shell: bash
|
||||
run: |
|
||||
vcpkg install breakpad
|
||||
- name: copy vcpkg packages into winlibs
|
||||
shell: bash
|
||||
run: |
|
||||
ls -al /usr/local/share/vcpkg/packages/breakpad*
|
||||
cp -R /usr/local/share/vcpkg/packages/breakpad*/* thirdparty/breakpad
|
||||
ls -al thirdparty/breakpad/lib
|
||||
- uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: ${{ matrix.qt_ver }}
|
||||
arch: ${{ matrix.qt_arch }}
|
||||
|
||||
modules: qtwebengine qtwebchannel qtpositioning qt5compat qtmultimedia qtimageformats qtspeech
|
||||
setup-python: 'false'
|
||||
|
||||
- name: compile
|
||||
run: |
|
||||
qmake CONFIG+=release CONFIG+=no_macos_universal CONFIG+=zim_support CONFIG+=use_xapian
|
||||
qmake CONFIG+=release CONFIG+=no_macos_universal CONFIG+=zim_support CONFIG+=use_xapian CONFIG+=use_breakpad
|
||||
make -j8
|
||||
|
||||
- name: package
|
||||
run: |
|
||||
|
||||
macdeployqt ${targetName}.app -qmldir=. -verbose=1
|
||||
macdeployqt ${targetName}.app -no-strip -qmldir=. -verbose=1
|
||||
otool -L GoldenDict.app/Contents/MacOS/GoldenDict
|
||||
ls -al GoldenDict.app/Contents/Frameworks
|
||||
otool -L GoldenDict.app/Contents/Frameworks/libicu*.dylib
|
||||
|
@ -195,7 +207,7 @@ jobs:
|
|||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ${{ env.targetName }}.dmg
|
||||
asset_name: ${{ matrix.qt_ver }}-${{ env.targetName }}_${{ matrix.os }}_homebrew_${{steps.vars.outputs.release_date}}.dmg
|
||||
asset_name: ${{ matrix.qt_ver }}-${{ env.targetName }}_${{ matrix.os }}_homebrew_breakpad_${{steps.vars.outputs.release_date}}.dmg
|
||||
|
||||
tag: tag-${{env.version-suffix}}.${{ steps.vars.outputs.sha_short }}
|
||||
overwrite: true
|
||||
|
|
|
@ -83,8 +83,8 @@ win32{
|
|||
CONFIG( use_breakpad ) {
|
||||
DEFINES += USE_BREAKPAD
|
||||
|
||||
win32: LIBS += -L$$PWD/thirdparty/breakpad/lib/ -llibbreakpad -llibbreakpad_client
|
||||
else:unix: LIBS += -L$$PWD/thirdparty/breakpad/lib/ -llibbreakpa
|
||||
LIBS += -L$$PWD/thirdparty/breakpad/lib/ -llibbreakpad -llibbreakpad_client
|
||||
|
||||
|
||||
INCLUDEPATH += $$PWD/thirdparty/breakpad/include
|
||||
DEPENDPATH += $$PWD/thirdparty/breakpad/include
|
||||
|
|
|
@ -147,6 +147,7 @@ Class::Class( string const & id_, vector< string > const & dictionaryFiles_ ):
|
|||
|
||||
void Class::deferredInit()
|
||||
{
|
||||
//base method.
|
||||
}
|
||||
|
||||
sptr< WordSearchRequest > Class::stemmedMatch( wstring const & /*str*/,
|
||||
|
@ -510,18 +511,14 @@ string makeDictionaryId( vector< string > const & dictionaryFiles ) noexcept
|
|||
// For portable version, we use relative paths
|
||||
sortedList.reserve( dictionaryFiles.size() );
|
||||
|
||||
QDir dictionariesDir( Config::getPortableVersionDictionaryDir() );
|
||||
|
||||
for( unsigned x = 0; x < dictionaryFiles.size(); ++x )
|
||||
{
|
||||
string const & full( dictionaryFiles[ x ] );
|
||||
const QDir dictionariesDir( Config::getPortableVersionDictionaryDir() );
|
||||
|
||||
for ( const auto & full : dictionaryFiles ) {
|
||||
QFileInfo fileInfo( QString::fromStdString( full ) );
|
||||
|
||||
if ( fileInfo.isAbsolute() )
|
||||
sortedList.push_back( dictionariesDir.relativeFilePath( fileInfo.filePath() ).toStdString() );
|
||||
else
|
||||
{
|
||||
else {
|
||||
// Well, it's relative. We don't technically support those, but
|
||||
// what the heck
|
||||
sortedList.push_back( full );
|
||||
|
@ -535,9 +532,9 @@ string makeDictionaryId( vector< string > const & dictionaryFiles ) noexcept
|
|||
|
||||
QCryptographicHash hash( QCryptographicHash::Md5 );
|
||||
|
||||
for( std::vector< string >::const_iterator i = sortedList.begin();
|
||||
i != sortedList.end(); ++i )
|
||||
hash.addData( i->c_str(), i->size() + 1 );
|
||||
for ( const auto & i : sortedList ) {
|
||||
hash.addData( i.c_str(), i.size() + 1 );
|
||||
}
|
||||
|
||||
return hash.result().toHex().data();
|
||||
}
|
||||
|
@ -551,20 +548,17 @@ bool needToRebuildIndex( vector< string > const & dictionaryFiles,
|
|||
{
|
||||
unsigned long lastModified = 0;
|
||||
|
||||
for( std::vector< string >::const_iterator i = dictionaryFiles.begin();
|
||||
i != dictionaryFiles.end(); ++i )
|
||||
{
|
||||
QString name = QString::fromUtf8( i->c_str() );
|
||||
for ( const auto & dictionaryFile : dictionaryFiles ) {
|
||||
QString name = QString::fromUtf8( dictionaryFile.c_str() );
|
||||
QFileInfo fileInfo( name );
|
||||
unsigned long ts;
|
||||
|
||||
if( fileInfo.isDir() )
|
||||
if ( fileInfo.isDir() )
|
||||
continue;
|
||||
|
||||
if( name.toLower().endsWith( ".zip" ) )
|
||||
{
|
||||
if ( name.toLower().endsWith( ".zip" ) ) {
|
||||
ZipFile::SplitZipFile zf( name );
|
||||
if( !zf.exists() )
|
||||
if ( !zf.exists() )
|
||||
return true;
|
||||
ts = zf.lastModified().toSecsSinceEpoch();
|
||||
}
|
||||
|
@ -605,8 +599,9 @@ QMap< std::string, sptr< Dictionary::Class > >
|
|||
dictToMap( std::vector< sptr< Dictionary::Class > > const & dicts )
|
||||
{
|
||||
QMap< std::string, sptr< Dictionary::Class > > dictMap;
|
||||
for( auto dict : dicts )
|
||||
{
|
||||
for ( auto & dict : dicts ) {
|
||||
if ( !dict )
|
||||
continue;
|
||||
dictMap.insert( dict.get()->getId(), dict );
|
||||
}
|
||||
return dictMap;
|
||||
|
|
|
@ -145,7 +145,7 @@ Q_OBJECT
|
|||
Q_PROPERTY(int type READ getType WRITE setType USER true)
|
||||
|
||||
public:
|
||||
ProgramTypeEditor( QWidget * widget = 0 );
|
||||
explicit ProgramTypeEditor( QWidget * widget = nullptr );
|
||||
|
||||
// Returns localized name for the given program type
|
||||
static QString getNameForType( int );
|
||||
|
|
|
@ -130,7 +130,9 @@ public:
|
|||
}
|
||||
|
||||
void clearDictionaries()
|
||||
{ dictionaries.clear(); }
|
||||
{
|
||||
dictionaries.clear();
|
||||
}
|
||||
|
||||
/// Start dictionaries indexing for full-text search
|
||||
void doIndexing();
|
||||
|
@ -140,7 +142,7 @@ public:
|
|||
|
||||
QString nowIndexingName();
|
||||
|
||||
protected:
|
||||
private:
|
||||
QAtomicInt isCancelled;
|
||||
QSemaphore indexingExited;
|
||||
std::vector< sptr< Dictionary::Class > > dictionaries;
|
||||
|
|
55
src/main.cc
55
src/main.cc
|
@ -33,10 +33,17 @@
|
|||
#include <QMutex>
|
||||
|
||||
#if defined(USE_BREAKPAD)
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
#if defined( Q_OS_MAC )
|
||||
#include "client/mac/handler/exception_handler.h"
|
||||
#elif defined( Q_OS_LINUX )
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#elif defined( Q_OS_WIN32 )
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_BREAKPAD)
|
||||
#ifdef Q_OS_WIN32
|
||||
bool callback(const wchar_t* dump_path, const wchar_t* id,
|
||||
void* context, EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion,
|
||||
|
@ -48,6 +55,31 @@ bool callback(const wchar_t* dump_path, const wchar_t* id,
|
|||
}
|
||||
return succeeded;
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
bool callback( const google_breakpad::MinidumpDescriptor & descriptor, void * context, bool succeeded )
|
||||
{
|
||||
if ( succeeded ) {
|
||||
qDebug() << "Create dump file success";
|
||||
}
|
||||
else {
|
||||
qDebug() << "Create dump file failed";
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
bool callback( const char * dump_dir, const char * minidump_id, void * context, bool succeeded )
|
||||
{
|
||||
if ( succeeded ) {
|
||||
qDebug() << "Create dump file success";
|
||||
}
|
||||
else {
|
||||
qDebug() << "Create dump file failed";
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QMutex logMutex;
|
||||
|
@ -55,9 +87,7 @@ QMutex logMutex;
|
|||
void gdMessageHandler( QtMsgType type, const QMessageLogContext &context, const QString &mess )
|
||||
{
|
||||
QString strTime = QDateTime::currentDateTime().toString( "MM-dd hh:mm:ss" );
|
||||
QString message = QString( "%1 %2\r\n" )
|
||||
.arg( strTime )
|
||||
.arg( mess );
|
||||
QString message = QString( "%1 %2\r\n" ).arg( strTime, mess );
|
||||
|
||||
if ( ( logFilePtr != nullptr ) && logFilePtr->isOpen() ) {
|
||||
//without the lock ,on multithread,there would be assert error.
|
||||
|
@ -292,18 +322,32 @@ int main( int argc, char ** argv )
|
|||
QHotkeyApplication::setWindowIcon( QIcon( ":/icons/programicon.png" ) );
|
||||
|
||||
#if defined(USE_BREAKPAD)
|
||||
QString appDirPath = QCoreApplication::applicationDirPath() + "/crash";
|
||||
QString appDirPath = Config::getConfigDir() + "crash";
|
||||
|
||||
QDir dir;
|
||||
if ( !dir.exists( appDirPath ) ) {
|
||||
dir.mkpath( appDirPath );
|
||||
}
|
||||
#ifdef Q_OS_WIN32
|
||||
|
||||
google_breakpad::ExceptionHandler eh(
|
||||
appDirPath.toStdWString(), NULL, callback, NULL,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||
#elif defined( Q_OS_MAC )
|
||||
|
||||
|
||||
google_breakpad::ExceptionHandler eh( appDirPath.toStdString(), 0, callback, 0, true, NULL );
|
||||
|
||||
#else
|
||||
|
||||
google_breakpad::ExceptionHandler eh( google_breakpad::MinidumpDescriptor( appDirPath.toStdString() ),
|
||||
/*FilterCallback*/ 0,
|
||||
callback,
|
||||
/*context*/ 0,
|
||||
true,
|
||||
-1 );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
GDOptions gdcl{};
|
||||
|
@ -411,6 +455,7 @@ int main( int argc, char ** argv )
|
|||
|
||||
if ( gdcl.notts ) {
|
||||
cfg.notts = true;
|
||||
cfg.voiceEngines.clear();
|
||||
}
|
||||
|
||||
cfg.resetState = gdcl.resetState;
|
||||
|
|
|
@ -49,7 +49,7 @@ SpeechClient::Engines SpeechClient::availableEngines()
|
|||
|
||||
bool SpeechClient::tell( QString const & text, int volume, int rate ) const
|
||||
{
|
||||
if( internalData->sp->state() != QTextToSpeech::Ready )
|
||||
if ( !internalData || !internalData->sp || internalData->sp->state() != QTextToSpeech::Ready )
|
||||
return false;
|
||||
|
||||
internalData->sp->setVolume( volume / 100.0 );
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "config.hh"
|
||||
#include <QTextToSpeech>
|
||||
#include <memory>
|
||||
#include <QDebug>
|
||||
|
||||
class SpeechClient: public QObject
|
||||
{
|
||||
|
@ -40,10 +41,18 @@ public:
|
|||
sp( std::make_unique< QTextToSpeech >( e.engine_name ) ),
|
||||
engine( e )
|
||||
{
|
||||
qDebug() << QStringLiteral( "initialize tts" ) << e.engine_name;
|
||||
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
|
||||
if ( !sp || sp->state() == QTextToSpeech::Error )
|
||||
return;
|
||||
#else
|
||||
if ( !sp || sp->state() == QTextToSpeech::BackendError )
|
||||
return;
|
||||
#endif
|
||||
sp->setLocale( e.locale );
|
||||
auto voices = sp->availableVoices();
|
||||
for( const auto & voice : voices ) {
|
||||
if( voice.name() == e.voice_name ) {
|
||||
for ( const auto & voice : voices ) {
|
||||
if ( voice.name() == e.voice_name ) {
|
||||
sp->setVoice( voice );
|
||||
|
||||
break;
|
||||
|
@ -67,10 +76,6 @@ public:
|
|||
bool tell( QString const & text, int volume, int rate ) const;
|
||||
bool tell( QString const & text ) const;
|
||||
|
||||
signals:
|
||||
void started( bool ok );
|
||||
void finished();
|
||||
|
||||
private:
|
||||
std::unique_ptr< InternalData > internalData;
|
||||
};
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
#include "editdictionaries.hh"
|
||||
#include "dict/loaddictionaries.hh"
|
||||
#include "help.hh"
|
||||
#include <QTabWidget>
|
||||
#include <QMessageBox>
|
||||
|
||||
using std::vector;
|
||||
|
||||
EditDictionaries::EditDictionaries( QWidget * parent, Config::Class & cfg_,
|
||||
EditDictionaries::EditDictionaries( QWidget * parent,
|
||||
Config::Class & cfg_,
|
||||
vector< sptr< Dictionary::Class > > & dictionaries_,
|
||||
Instances::Groups & groupInstances_,
|
||||
QNetworkAccessManager & dictNetMgr_ ):
|
||||
|
@ -19,12 +21,10 @@ EditDictionaries::EditDictionaries( QWidget * parent, Config::Class & cfg_,
|
|||
dictNetMgr( dictNetMgr_ ),
|
||||
origCfg( cfg ),
|
||||
sources( this, cfg ),
|
||||
orderAndProps( new OrderAndProps( this, cfg.dictionaryOrder, cfg.inactiveDictionaries,
|
||||
dictionaries ) ),
|
||||
orderAndProps( new OrderAndProps( this, cfg.dictionaryOrder, cfg.inactiveDictionaries, dictionaries ) ),
|
||||
groups( new Groups( this, dictionaries, cfg.groups, orderAndProps->getCurrentDictionaryOrder() ) ),
|
||||
dictionariesChanged( false ),
|
||||
groupsChanged( false ),
|
||||
lastCurrentTab( 0 ),
|
||||
helpAction( this )
|
||||
{
|
||||
// Some groups may have contained links to non-existnent dictionaries. We
|
||||
|
@ -32,35 +32,32 @@ EditDictionaries::EditDictionaries( QWidget * parent, Config::Class & cfg_,
|
|||
// the initial group readings so that if no edits were really done, we won't
|
||||
// be changing groups.
|
||||
origCfg.groups = groups->getGroups();
|
||||
origCfg.dictionaryOrder = orderAndProps->getCurrentDictionaryOrder();
|
||||
origCfg.dictionaryOrder = orderAndProps->getCurrentDictionaryOrder();
|
||||
origCfg.inactiveDictionaries = orderAndProps->getCurrentInactiveDictionaries();
|
||||
|
||||
ui.setupUi( this );
|
||||
|
||||
setWindowIcon( QIcon(":/icons/dictionary.svg") );
|
||||
setWindowIcon( QIcon( ":/icons/dictionary.svg" ) );
|
||||
|
||||
ui.tabs->clear();
|
||||
|
||||
ui.tabs->addTab( &sources, QIcon(":/icons/sources.png"), tr( "&Sources" ) );
|
||||
ui.tabs->addTab( orderAndProps, QIcon(":/icons/book.svg"), tr( "&Dictionaries" ) );
|
||||
ui.tabs->addTab( groups.get(), QIcon(":/icons/bookcase.svg"), tr( "&Groups" ) );
|
||||
ui.tabs->addTab( &sources, QIcon( ":/icons/sources.png" ), tr( "&Sources" ) );
|
||||
ui.tabs->addTab( orderAndProps, QIcon( ":/icons/book.svg" ), tr( "&Dictionaries" ) );
|
||||
ui.tabs->addTab( groups, QIcon( ":/icons/bookcase.svg" ), tr( "&Groups" ) );
|
||||
|
||||
connect( ui.buttons, &QDialogButtonBox::clicked, this, &EditDictionaries::buttonBoxClicked );
|
||||
|
||||
connect( &sources, &Sources::rescan, this, &EditDictionaries::rescanSources );
|
||||
|
||||
connect( groups.get(), &Groups::showDictionaryInfo, this, &EditDictionaries::showDictionaryInfo );
|
||||
connect( groups, &Groups::showDictionaryInfo, this, &EditDictionaries::showDictionaryInfo );
|
||||
|
||||
connect( orderAndProps.data(),
|
||||
&OrderAndProps::showDictionaryHeadwords,
|
||||
this,
|
||||
&EditDictionaries::showDictionaryHeadwords );
|
||||
connect( orderAndProps, &OrderAndProps::showDictionaryHeadwords, this, &EditDictionaries::showDictionaryHeadwords );
|
||||
|
||||
helpAction.setShortcut( QKeySequence( "F1" ) );
|
||||
helpAction.setShortcutContext( Qt::WidgetWithChildrenShortcut );
|
||||
|
||||
connect( &helpAction, &QAction::triggered, [ this ]() {
|
||||
if ( ui.tabs->currentWidget() == this->groups.get() ) {
|
||||
if ( ui.tabs->currentWidget() == this->groups ) {
|
||||
Help::openHelpWebpage( Help::section::manage_groups );
|
||||
}
|
||||
else {
|
||||
|
@ -71,6 +68,7 @@ EditDictionaries::EditDictionaries( QWidget * parent, Config::Class & cfg_,
|
|||
|
||||
addAction( &helpAction );
|
||||
|
||||
connect( ui.tabs, &QTabWidget::currentChanged, this, &EditDictionaries::currentChanged );
|
||||
}
|
||||
|
||||
void EditDictionaries::editGroup( unsigned id )
|
||||
|
@ -90,19 +88,18 @@ void EditDictionaries::editGroup( unsigned id )
|
|||
|
||||
void EditDictionaries::save( bool rebuildGroups )
|
||||
{
|
||||
Config::Groups newGroups = groups->getGroups();
|
||||
Config::Group newOrder = orderAndProps->getCurrentDictionaryOrder();
|
||||
Config::Group newInactive = orderAndProps->getCurrentInactiveDictionaries();
|
||||
const Config::Groups newGroups = groups->getGroups();
|
||||
const Config::Group newOrder = orderAndProps->getCurrentDictionaryOrder();
|
||||
const Config::Group newInactive = orderAndProps->getCurrentInactiveDictionaries();
|
||||
|
||||
if( isSourcesChanged() )
|
||||
if ( isSourcesChanged() )
|
||||
acceptChangedSources( rebuildGroups );
|
||||
|
||||
if ( origCfg.groups != newGroups || origCfg.dictionaryOrder != newOrder ||
|
||||
origCfg.inactiveDictionaries != newInactive )
|
||||
{
|
||||
groupsChanged = true;
|
||||
cfg.groups = newGroups;
|
||||
cfg.dictionaryOrder = newOrder;
|
||||
if ( origCfg.groups != newGroups || origCfg.dictionaryOrder != newOrder
|
||||
|| origCfg.inactiveDictionaries != newInactive ) {
|
||||
groupsChanged = true;
|
||||
cfg.groups = newGroups;
|
||||
cfg.dictionaryOrder = newOrder;
|
||||
cfg.inactiveDictionaries = newInactive;
|
||||
}
|
||||
}
|
||||
|
@ -113,54 +110,49 @@ void EditDictionaries::accept()
|
|||
QDialog::accept();
|
||||
}
|
||||
|
||||
void EditDictionaries::on_tabs_currentChanged( int index )
|
||||
void EditDictionaries::currentChanged( int index )
|
||||
{
|
||||
if ( index == -1 || !isVisible() )
|
||||
return; // Sent upon the construction/destruction
|
||||
|
||||
if ( !lastCurrentTab && index )
|
||||
{
|
||||
qDebug() << ui.tabs->currentWidget()->objectName();
|
||||
if ( lastTabName.isEmpty() || lastTabName == "Sources" ) {
|
||||
// We're switching away from the Sources tab -- if its contents were
|
||||
// changed, we need to either apply or reject now.
|
||||
|
||||
if ( isSourcesChanged() )
|
||||
{
|
||||
ui.tabs->setCurrentIndex( 0 );
|
||||
|
||||
QMessageBox question( QMessageBox::Question, tr( "Sources changed" ),
|
||||
if ( isSourcesChanged() ) {
|
||||
QMessageBox question( QMessageBox::Question,
|
||||
tr( "Sources changed" ),
|
||||
tr( "Some sources were changed. Would you like to accept the changes?" ),
|
||||
QMessageBox::NoButton, this );
|
||||
QMessageBox::NoButton,
|
||||
this );
|
||||
|
||||
QPushButton * accept = question.addButton( tr( "Accept" ), QMessageBox::AcceptRole );
|
||||
const QPushButton * accept = question.addButton( tr( "Accept" ), QMessageBox::AcceptRole );
|
||||
|
||||
question.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
|
||||
|
||||
question.exec();
|
||||
|
||||
if ( question.clickedButton() == accept )
|
||||
{
|
||||
//When accept the changes ,the second and third tab will be recreated. which means the current Index tab will be changed.
|
||||
if ( question.clickedButton() == accept ) {
|
||||
disconnect( ui.tabs, &QTabWidget::currentChanged, this, &EditDictionaries::currentChanged );
|
||||
|
||||
acceptChangedSources( true );
|
||||
|
||||
lastCurrentTab = index;
|
||||
ui.tabs->setCurrentIndex( index );
|
||||
connect( ui.tabs, &QTabWidget::currentChanged, this, &EditDictionaries::currentChanged );
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// Prevent tab from switching
|
||||
lastCurrentTab = 0;
|
||||
return;
|
||||
// return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if ( lastCurrentTab == 1 && index != 1 )
|
||||
{
|
||||
else if ( lastTabName == "OrderAndProps" ) {
|
||||
// When switching from the dictionary order, we need to propagate any
|
||||
// changes to the groups.
|
||||
groups->updateDictionaryOrder( orderAndProps->getCurrentDictionaryOrder() );
|
||||
}
|
||||
|
||||
lastCurrentTab = index;
|
||||
lastTabName = ui.tabs->currentWidget()->objectName();
|
||||
}
|
||||
|
||||
void EditDictionaries::rescanSources()
|
||||
|
@ -194,64 +186,64 @@ void EditDictionaries::acceptChangedSources( bool rebuildGroups )
|
|||
{
|
||||
dictionariesChanged = true;
|
||||
|
||||
Config::Groups savedGroups = groups->getGroups();
|
||||
Config::Group savedOrder = orderAndProps->getCurrentDictionaryOrder();
|
||||
Config::Groups savedGroups = groups->getGroups();
|
||||
Config::Group savedOrder = orderAndProps->getCurrentDictionaryOrder();
|
||||
Config::Group savedInactive = orderAndProps->getCurrentInactiveDictionaries();
|
||||
|
||||
cfg.paths = sources.getPaths();
|
||||
cfg.soundDirs = sources.getSoundDirs();
|
||||
cfg.hunspell = sources.getHunspell();
|
||||
cfg.paths = sources.getPaths();
|
||||
cfg.soundDirs = sources.getSoundDirs();
|
||||
cfg.hunspell = sources.getHunspell();
|
||||
cfg.transliteration = sources.getTransliteration();
|
||||
cfg.lingua = sources.getLingua();
|
||||
cfg.forvo = sources.getForvo();
|
||||
cfg.mediawikis = sources.getMediaWikis();
|
||||
cfg.webSites = sources.getWebSites();
|
||||
cfg.dictServers = sources.getDictServers();
|
||||
cfg.programs = sources.getPrograms();
|
||||
cfg.voiceEngines = sources.getVoiceEngines();
|
||||
cfg.lingua = sources.getLingua();
|
||||
cfg.forvo = sources.getForvo();
|
||||
cfg.mediawikis = sources.getMediaWikis();
|
||||
cfg.webSites = sources.getWebSites();
|
||||
cfg.dictServers = sources.getDictServers();
|
||||
cfg.programs = sources.getPrograms();
|
||||
cfg.voiceEngines = sources.getVoiceEngines();
|
||||
|
||||
groupInstances.clear(); // Those hold pointers to dictionaries, we need to
|
||||
// free them.
|
||||
ui.tabs->setUpdatesEnabled( false );
|
||||
// Those hold pointers to dictionaries, we need to free them.
|
||||
groupInstances.clear();
|
||||
|
||||
groups.reset();
|
||||
groups.clear();
|
||||
orderAndProps.clear();
|
||||
|
||||
loadDictionaries( this, true, cfg, dictionaries, dictNetMgr );
|
||||
|
||||
// If no changes to groups were made, update the original data
|
||||
bool noGroupEdits = ( origCfg.groups == savedGroups );
|
||||
const bool noGroupEdits = ( origCfg.groups == savedGroups );
|
||||
|
||||
if ( noGroupEdits )
|
||||
savedGroups = cfg.groups;
|
||||
|
||||
Instances::updateNames( savedGroups, dictionaries );
|
||||
|
||||
bool noOrderEdits = ( origCfg.dictionaryOrder == savedOrder );
|
||||
const bool noOrderEdits = ( origCfg.dictionaryOrder == savedOrder );
|
||||
|
||||
if ( noOrderEdits )
|
||||
savedOrder = cfg.dictionaryOrder;
|
||||
|
||||
Instances::updateNames( savedOrder, dictionaries );
|
||||
|
||||
bool noInactiveEdits = ( origCfg.inactiveDictionaries == savedInactive );
|
||||
const bool noInactiveEdits = ( origCfg.inactiveDictionaries == savedInactive );
|
||||
|
||||
if ( noInactiveEdits )
|
||||
savedInactive = cfg.inactiveDictionaries;
|
||||
|
||||
Instances::updateNames( savedInactive, dictionaries );
|
||||
|
||||
if ( rebuildGroups )
|
||||
{
|
||||
if ( rebuildGroups ) {
|
||||
ui.tabs->removeTab( 1 );
|
||||
ui.tabs->removeTab( 1 );
|
||||
|
||||
orderAndProps = new OrderAndProps( this, savedOrder, savedInactive, dictionaries );
|
||||
groups = std::make_shared<Groups>( this, dictionaries, savedGroups, orderAndProps->getCurrentDictionaryOrder() );
|
||||
|
||||
ui.tabs->removeTab( 1 );
|
||||
ui.tabs->removeTab( 1 );
|
||||
ui.tabs->insertTab( 1, orderAndProps, QIcon(":/icons/book.svg"), tr( "&Dictionaries" ) );
|
||||
|
||||
ui.tabs->insertTab( 2, groups.get(), QIcon(":/icons/bookcase.svg"), tr( "&Groups" ) );
|
||||
groups = new Groups( this, dictionaries, savedGroups, orderAndProps->getCurrentDictionaryOrder() );
|
||||
|
||||
ui.tabs->insertTab( 1, orderAndProps, QIcon( ":/icons/book.svg" ), tr( "&Dictionaries" ) );
|
||||
ui.tabs->insertTab( 2, groups, QIcon( ":/icons/bookcase.svg" ), tr( "&Groups" ) );
|
||||
connect( groups, &Groups::showDictionaryInfo, this, &EditDictionaries::showDictionaryInfo );
|
||||
connect( orderAndProps, &OrderAndProps::showDictionaryHeadwords, this, &EditDictionaries::showDictionaryHeadwords );
|
||||
|
||||
if ( noGroupEdits )
|
||||
origCfg.groups = groups->getGroups();
|
||||
|
@ -263,5 +255,8 @@ void EditDictionaries::acceptChangedSources( bool rebuildGroups )
|
|||
origCfg.inactiveDictionaries = orderAndProps->getCurrentInactiveDictionaries();
|
||||
}
|
||||
ui.tabs->setUpdatesEnabled( true );
|
||||
|
||||
}
|
||||
EditDictionaries::~EditDictionaries()
|
||||
{
|
||||
disconnect( ui.tabs, &QTabWidget::currentChanged, this, &EditDictionaries::currentChanged );
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
Instances::Groups & groupInstances, // We only clear those on rescan
|
||||
QNetworkAccessManager & dictNetMgr );
|
||||
|
||||
~EditDictionaries() = default;
|
||||
~EditDictionaries();
|
||||
|
||||
/// Instructs the dialog to position itself on editing the given group.
|
||||
void editGroup( unsigned id );
|
||||
|
@ -45,7 +45,7 @@ protected:
|
|||
|
||||
private slots:
|
||||
|
||||
void on_tabs_currentChanged( int index );
|
||||
void currentChanged( int index );
|
||||
|
||||
void buttonBoxClicked( QAbstractButton * button );
|
||||
|
||||
|
@ -72,19 +72,19 @@ private:
|
|||
std::vector< sptr< Dictionary::Class > > & dictionaries;
|
||||
Instances::Groups & groupInstances;
|
||||
QNetworkAccessManager & dictNetMgr;
|
||||
|
||||
|
||||
// Backed up to decide later if something was changed or not
|
||||
Config::Class origCfg;
|
||||
|
||||
Ui::EditDictionaries ui;
|
||||
Sources sources;
|
||||
QPointer<OrderAndProps> orderAndProps;
|
||||
sptr< Groups > groups;
|
||||
QPointer< OrderAndProps > orderAndProps;
|
||||
QPointer< Groups > groups;
|
||||
|
||||
bool dictionariesChanged;
|
||||
bool groupsChanged;
|
||||
|
||||
int lastCurrentTab;
|
||||
|
||||
QString lastTabName;
|
||||
|
||||
QAction helpAction;
|
||||
};
|
||||
|
|
|
@ -84,7 +84,7 @@ void Groups::updateDictionaryOrder( Config::Group const & order )
|
|||
if( ui.dictionaries->getCurrentDictionaries() != newOrder.dictionaries )
|
||||
{
|
||||
// Repopulate
|
||||
ui.dictionaries->populate( Instances::Group( order, dicts, Config::Group() ).dictionaries, dicts );
|
||||
ui.dictionaries->populate( newOrder.dictionaries, dicts );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ DictGroupWidget::DictGroupWidget( QWidget * parent,
|
|||
|
||||
ui.groupIcon->addItem( tr( "None" ), "" );
|
||||
|
||||
bool usesIconData = !group.iconData.isEmpty();
|
||||
const bool usesIconData = !group.iconData.isEmpty();
|
||||
|
||||
if ( !usesIconData )
|
||||
ui.groupIcon->addItem( tr( "From file..." ), "" );
|
||||
|
@ -80,35 +80,32 @@ DictGroupWidget::DictGroupWidget( QWidget * parent,
|
|||
|
||||
void DictGroupWidget::groupIconActivated( int index )
|
||||
{
|
||||
if ( index == 1 )
|
||||
{
|
||||
if ( index == 1 ) {
|
||||
QList< QByteArray > supImageFormats = QImageReader::supportedImageFormats();
|
||||
|
||||
QString formatList( " (" );
|
||||
|
||||
for( int x = 0; x < supImageFormats.size(); ++x )
|
||||
formatList += "*." + QString::fromLatin1( supImageFormats[ x ] ) + " ";
|
||||
for ( const auto & supImageFormat : supImageFormats )
|
||||
formatList += "*." + QString::fromLatin1( supImageFormat ) + " ";
|
||||
|
||||
formatList.chop( 1 );
|
||||
formatList.append( ")" );
|
||||
|
||||
QString chosenFile =
|
||||
QFileDialog::getOpenFileName( this, tr( "Choose a file to use as group icon" ),
|
||||
QString(),
|
||||
tr( "Images" ) + formatList + ";;" +
|
||||
tr( "All files" ) + " (*.*)" );
|
||||
const QString chosenFile =
|
||||
QFileDialog::getOpenFileName( this,
|
||||
tr( "Choose a file to use as group icon" ),
|
||||
QString(),
|
||||
tr( "Images" ) + formatList + ";;" + tr( "All files" ) + " (*.*)" );
|
||||
|
||||
if ( !chosenFile.isEmpty() )
|
||||
{
|
||||
QIcon icon( chosenFile );
|
||||
if ( !chosenFile.isEmpty() ) {
|
||||
const QIcon icon( chosenFile );
|
||||
|
||||
if ( icon.isNull() )
|
||||
QMessageBox::critical( this, tr( "Error" ), tr( "Can't read the specified image file." ) );
|
||||
else
|
||||
{
|
||||
else {
|
||||
ui.groupIcon->setItemIcon( 1, icon );
|
||||
|
||||
QString baseName = QFileInfo( chosenFile ).completeBaseName();
|
||||
const QString baseName = QFileInfo( chosenFile ).completeBaseName();
|
||||
ui.groupIcon->setItemText( 1, baseName );
|
||||
ui.groupIcon->setItemData( 1, baseName );
|
||||
}
|
||||
|
@ -124,7 +121,7 @@ Config::Group DictGroupWidget::makeGroup() const
|
|||
|
||||
g.dictionaries = ui.dictionaries->getCurrentDictionaries();
|
||||
|
||||
int currentIndex = ui.groupIcon->currentIndex();
|
||||
const int currentIndex = ui.groupIcon->currentIndex();
|
||||
|
||||
if ( currentIndex == 1 ) // File
|
||||
g.iconData = ui.groupIcon->itemIcon( currentIndex );
|
||||
|
@ -140,7 +137,7 @@ Config::Group DictGroupWidget::makeGroup() const
|
|||
|
||||
void DictGroupWidget::showDictInfo( QPoint const & pos )
|
||||
{
|
||||
QVariant data = ui.dictionaries->getModel()->data( ui.dictionaries->indexAt( pos ), Qt::EditRole );
|
||||
const QVariant data = ui.dictionaries->getModel()->data( ui.dictionaries->indexAt( pos ), Qt::EditRole );
|
||||
QString id;
|
||||
if( data.canConvert< QString >() )
|
||||
id = data.toString();
|
||||
|
@ -197,7 +194,7 @@ std::vector< sptr< Dictionary::Class > > const &
|
|||
|
||||
Qt::ItemFlags DictListModel::flags( QModelIndex const & index ) const
|
||||
{
|
||||
Qt::ItemFlags defaultFlags = QAbstractListModel::flags( index );
|
||||
const Qt::ItemFlags defaultFlags = QAbstractListModel::flags( index );
|
||||
|
||||
if (index.isValid())
|
||||
return Qt::ItemIsDragEnabled | defaultFlags;
|
||||
|
@ -222,14 +219,12 @@ QVariant DictListModel::data( QModelIndex const & index, int role ) const
|
|||
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
case Qt::ToolTipRole: {
|
||||
QString tt = "<b>" + QString::fromUtf8( item->getName().c_str() ) + "</b>";
|
||||
|
||||
QString lfrom( Language::localizedNameForId( item->getLangFrom() ) );
|
||||
QString lto( Language::localizedNameForId( item->getLangTo() ) );
|
||||
if ( !lfrom.isEmpty() )
|
||||
{
|
||||
const QString lfrom( Language::localizedNameForId( item->getLangFrom() ) );
|
||||
const QString lto( Language::localizedNameForId( item->getLangTo() ) );
|
||||
if ( !lfrom.isEmpty() ) {
|
||||
if ( lfrom == lto )
|
||||
tt += "<br>" + lfrom;
|
||||
else
|
||||
|
@ -285,14 +280,13 @@ bool DictListModel::insertRows( int row, int count, const QModelIndex & parent )
|
|||
|
||||
void DictListModel::addRow(const QModelIndex & parent, sptr< Dictionary::Class > dict)
|
||||
{
|
||||
for (unsigned i = 0; i < dictionaries.size(); i++)
|
||||
{
|
||||
if (dictionaries[i]->getId() == dict->getId())
|
||||
for ( const auto & dictionary : dictionaries ) {
|
||||
if ( dictionary->getId() == dict->getId() )
|
||||
return;
|
||||
}
|
||||
|
||||
beginInsertRows( parent, dictionaries.size(), dictionaries.size()+1 );
|
||||
dictionaries.push_back(dict);
|
||||
beginInsertRows( parent, dictionaries.size(), dictionaries.size() + 1 );
|
||||
dictionaries.push_back( dict );
|
||||
endInsertRows();
|
||||
emit contentChanged();
|
||||
}
|
||||
|
@ -330,7 +324,7 @@ bool DictListModel::setData( QModelIndex const & index, const QVariant & value,
|
|||
|
||||
g.dictionaries.push_back( Config::DictionaryRef( value.toString(), QString() ) );
|
||||
|
||||
Instances::Group i( g, *allDicts, Config::Group() );
|
||||
const Instances::Group i( g, *allDicts, Config::Group() );
|
||||
|
||||
if ( i.dictionaries.size() == 1 )
|
||||
{
|
||||
|
@ -356,7 +350,7 @@ void DictListModel::removeSelectedRows( QItemSelectionModel * source )
|
|||
if ( !source )
|
||||
return;
|
||||
|
||||
QModelIndexList rows = source->selectedRows();
|
||||
const QModelIndexList rows = source->selectedRows();
|
||||
|
||||
if ( !rows.count() )
|
||||
return;
|
||||
|
@ -376,7 +370,7 @@ void DictListModel::addSelectedUniqueFromModel( QItemSelectionModel * source )
|
|||
if ( !source )
|
||||
return;
|
||||
|
||||
QModelIndexList rows = source->selectedRows();
|
||||
const QModelIndexList rows = source->selectedRows();
|
||||
|
||||
if ( !rows.count() )
|
||||
return;
|
||||
|
@ -389,9 +383,8 @@ void DictListModel::addSelectedUniqueFromModel( QItemSelectionModel * source )
|
|||
{
|
||||
baseModel = dynamic_cast< const DictListModel * > ( proxyModel->sourceModel() );
|
||||
}
|
||||
else
|
||||
{
|
||||
baseModel = dynamic_cast< const DictListModel * > ( source->model() );
|
||||
else {
|
||||
baseModel = dynamic_cast< const DictListModel * >( source->model() );
|
||||
}
|
||||
|
||||
if ( !baseModel )
|
||||
|
@ -399,13 +392,12 @@ void DictListModel::addSelectedUniqueFromModel( QItemSelectionModel * source )
|
|||
|
||||
QVector< std::string > list;
|
||||
QVector< std::string > dicts;
|
||||
for ( unsigned i = 0; i < dictionaries.size(); i++ )
|
||||
dicts.append( dictionaries.at( i )->getId() );
|
||||
for ( const auto & dictionarie : dictionaries )
|
||||
dicts.append( dictionarie->getId() );
|
||||
|
||||
for ( int i = 0; i < rows.count(); i++ )
|
||||
{
|
||||
QModelIndex idx = proxyModel ? proxyModel->mapToSource(rows.at( i )) : rows.at( i );
|
||||
std::string id = baseModel->dictionaries.at( idx.row() )->getId();
|
||||
for ( int i = 0; i < rows.count(); i++ ) {
|
||||
QModelIndex idx = proxyModel ? proxyModel->mapToSource( rows.at( i ) ) : rows.at( i );
|
||||
std::string id = baseModel->dictionaries.at( idx.row() )->getId();
|
||||
|
||||
if ( !dicts.contains( id ) )
|
||||
list.append( id );
|
||||
|
@ -414,13 +406,10 @@ void DictListModel::addSelectedUniqueFromModel( QItemSelectionModel * source )
|
|||
if ( list.empty() )
|
||||
return;
|
||||
|
||||
for ( int j = 0; j < list.size(); j++ )
|
||||
{
|
||||
for ( unsigned i = 0; i < allDicts->size(); i++ )
|
||||
{
|
||||
if ( allDicts->at( i )->getId() == list.at( j ) )
|
||||
{
|
||||
dictionaries.push_back( allDicts->at( i ) );
|
||||
for ( const auto & j : list ) {
|
||||
for ( const auto & allDict : *allDicts ) {
|
||||
if ( allDict->getId() == j ) {
|
||||
dictionaries.push_back( allDict );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -472,11 +461,6 @@ DictListWidget::DictListWidget( QWidget * parent ): QListView( parent ),
|
|||
setDropIndicatorShown( true );
|
||||
}
|
||||
|
||||
DictListWidget::~DictListWidget()
|
||||
{
|
||||
setModel( 0 );
|
||||
}
|
||||
|
||||
void DictListWidget::populate(
|
||||
std::vector< sptr< Dictionary::Class > > const & active,
|
||||
std::vector< sptr< Dictionary::Class > > const & available )
|
||||
|
@ -504,7 +488,7 @@ std::vector< sptr< Dictionary::Class > > const &
|
|||
|
||||
void DictListWidget::dropEvent( QDropEvent * event )
|
||||
{
|
||||
DictListWidget * sourceList = dynamic_cast< DictListWidget * > ( event->source() );
|
||||
const auto sourceList = dynamic_cast< DictListWidget * >( event->source() );
|
||||
|
||||
QListView::dropEvent( event );
|
||||
|
||||
|
@ -532,12 +516,10 @@ void DictListWidget::rowsAboutToBeRemoved( QModelIndex const & parent, int start
|
|||
{
|
||||
// When removing rows, if the current row is among the removed ones, select
|
||||
// an item just before the first row to be removed, if there's one.
|
||||
QModelIndex current = currentIndex();
|
||||
|
||||
if ( current.isValid() && current.row() &&
|
||||
current.row() >= start && current.row() <= end )
|
||||
selectionModel()->setCurrentIndex( model.index( current.row() - 1, 0, parent ),
|
||||
QItemSelectionModel::NoUpdate );
|
||||
if ( const QModelIndex current = currentIndex();
|
||||
current.isValid() && current.row() && current.row() >= start && current.row() <= end )
|
||||
selectionModel()->setCurrentIndex( model.index( current.row() - 1, 0, parent ), QItemSelectionModel::NoUpdate );
|
||||
|
||||
QListView::rowsAboutToBeRemoved( parent, start, end );
|
||||
}
|
||||
|
@ -546,7 +528,10 @@ void DictListWidget::rowsAboutToBeRemoved( QModelIndex const & parent, int start
|
|||
// DictGroupsWidget
|
||||
|
||||
DictGroupsWidget::DictGroupsWidget( QWidget * parent ):
|
||||
QTabWidget( parent ), nextId( 1 ), allDicts( 0 ), activeDicts( 0 )
|
||||
QTabWidget( parent ),
|
||||
nextId( 1 ),
|
||||
allDicts( nullptr ),
|
||||
activeDicts( nullptr )
|
||||
{
|
||||
setMovable( true );
|
||||
setContextMenuPolicy( Qt::CustomContextMenu );
|
||||
|
@ -585,14 +570,13 @@ void DictGroupsWidget::populate( Config::Groups const & groups,
|
|||
|
||||
for( int x = 0; x < groups.size(); ++x )
|
||||
{
|
||||
DictGroupWidget *gr = new DictGroupWidget( this, *allDicts, groups[ x ] );
|
||||
const auto gr = new DictGroupWidget( this, *allDicts, groups[ x ] );
|
||||
addTab( gr, escapeAmps( groups[ x ].name ) );
|
||||
connect( gr, &DictGroupWidget::showDictionaryInfo,this, &DictGroupsWidget::showDictionaryInfo );
|
||||
connect( gr->getModel(), &DictListModel::contentChanged, this, &DictGroupsWidget::tabDataChanged );
|
||||
|
||||
setCurrentIndex( x );
|
||||
QString toolTipStr = "\"" + tabText( x ) + "\"\n" + tr( "Dictionaries: " )
|
||||
+ QString::number( getCurrentModel()->getCurrentDictionaries().size() );
|
||||
QString toolTipStr =
|
||||
"\"" + tabText( x ) + "\"\n" + tr( "Dictionaries: " ) + QString::number( getDictionaryCountAt( x ) );
|
||||
setTabToolTip( x, toolTipStr );
|
||||
}
|
||||
|
||||
|
@ -619,53 +603,78 @@ Config::Groups DictGroupsWidget::makeGroups() const
|
|||
|
||||
DictListModel * DictGroupsWidget::getCurrentModel() const
|
||||
{
|
||||
int current = currentIndex();
|
||||
const int current = currentIndex();
|
||||
|
||||
if ( current >= 0 )
|
||||
{
|
||||
DictGroupWidget * w = ( DictGroupWidget * ) widget( current );
|
||||
const auto w = (DictGroupWidget *)widget( current );
|
||||
return w->getModel();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DictListModel * DictGroupsWidget::getModelAt( int current ) const
|
||||
{
|
||||
if ( current >= 0 && current < count() ) {
|
||||
const auto w = static_cast< DictGroupWidget * >( widget( current ) );
|
||||
if ( !w )
|
||||
return nullptr;
|
||||
return w->getModel();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int DictGroupsWidget::getDictionaryCountAt( int current ) const
|
||||
{
|
||||
const auto model = getModelAt( current );
|
||||
if ( !model )
|
||||
return 0;
|
||||
return model->getCurrentDictionaries().size();
|
||||
}
|
||||
|
||||
std::vector< sptr< Dictionary::Class > > DictGroupsWidget::getDictionaryAt( int current ) const
|
||||
{
|
||||
const auto model = getModelAt( current );
|
||||
if ( !model )
|
||||
return {};
|
||||
return model->getCurrentDictionaries();
|
||||
}
|
||||
|
||||
QItemSelectionModel * DictGroupsWidget::getCurrentSelectionModel() const
|
||||
{
|
||||
int current = currentIndex();
|
||||
const int current = currentIndex();
|
||||
|
||||
if ( current >= 0 )
|
||||
{
|
||||
DictGroupWidget * w = ( DictGroupWidget * ) widget( current );
|
||||
const auto w = (DictGroupWidget *)widget( current );
|
||||
return w->getSelectionModel();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void DictGroupsWidget::addNewGroup( QString const & name )
|
||||
int DictGroupsWidget::addNewGroup( QString const & name )
|
||||
{
|
||||
if ( !allDicts )
|
||||
return;
|
||||
|
||||
int idx = currentIndex() + 1;
|
||||
return 0;
|
||||
|
||||
Config::Group newGroup;
|
||||
|
||||
newGroup.id = nextId++;
|
||||
|
||||
DictGroupWidget *gr = new DictGroupWidget( this, *allDicts, newGroup );
|
||||
insertTab( idx, gr, escapeAmps( name ) );
|
||||
const auto gr = new DictGroupWidget( this, *allDicts, newGroup );
|
||||
const int idx = insertTab( currentIndex() + 1, gr, escapeAmps( name ) );
|
||||
connect( gr, &DictGroupWidget::showDictionaryInfo, this, &DictGroupsWidget::showDictionaryInfo );
|
||||
|
||||
setCurrentIndex( idx );
|
||||
|
||||
connect( gr->getModel(), &DictListModel::contentChanged, this, &DictGroupsWidget::tabDataChanged );
|
||||
|
||||
QString toolTipStr = "\"" + tabText( idx ) + "\"\n" + tr( "Dictionaries: " )
|
||||
+ QString::number( getCurrentModel()->getCurrentDictionaries().size() );
|
||||
const QString toolTipStr =
|
||||
"\"" + tabText( idx ) + "\"\n" + tr( "Dictionaries: " ) + QString::number( getDictionaryCountAt( idx ) );
|
||||
setTabToolTip( idx, toolTipStr );
|
||||
return idx;
|
||||
}
|
||||
|
||||
int DictGroupsWidget::addUniqueGroup( const QString & name )
|
||||
|
@ -673,12 +682,11 @@ int DictGroupsWidget::addUniqueGroup( const QString & name )
|
|||
for( int n = 0; n < count(); n++ )
|
||||
if( tabText( n ) == name )
|
||||
{
|
||||
setCurrentIndex( n );
|
||||
// setCurrentIndex( n );
|
||||
return n;
|
||||
}
|
||||
|
||||
addNewGroup( name );
|
||||
return currentIndex();
|
||||
return addNewGroup( name );
|
||||
}
|
||||
|
||||
void DictGroupsWidget::addAutoGroups()
|
||||
|
@ -697,17 +705,14 @@ void DictGroupsWidget::addAutoGroups()
|
|||
|
||||
// Put active dictionaries into lists
|
||||
|
||||
for ( unsigned i = 0; i < activeDicts->size(); i++ )
|
||||
{
|
||||
sptr<Dictionary::Class> dict = activeDicts->at( i );
|
||||
|
||||
for ( const auto & dict : *activeDicts ) {
|
||||
int idFrom = dict->getLangFrom();
|
||||
int idTo = dict->getLangTo();
|
||||
if( idFrom == 0)
|
||||
{
|
||||
// Attempt to find language pair in dictionary name
|
||||
|
||||
QPair<quint32,quint32> ids = LangCoder::findIdsForName( QString::fromUtf8( dict->getName().c_str() ) );
|
||||
const QPair< quint32, quint32 > ids = LangCoder::findIdsForName( QString::fromUtf8( dict->getName().c_str() ) );
|
||||
idFrom = ids.first;
|
||||
idTo = ids.second;
|
||||
}
|
||||
|
@ -737,34 +742,30 @@ void DictGroupsWidget::addAutoGroups()
|
|||
dictMap[ name ].push_back( dict );
|
||||
}
|
||||
|
||||
QStringList groupList = dictMap.keys();
|
||||
QStringList groupList = dictMap.keys();
|
||||
QStringList morphoList = morphoMap.keys();
|
||||
|
||||
// Insert morphology dictionaries into corresponding lists
|
||||
|
||||
for( QStringList::ConstIterator ln = morphoList.begin(); ln != morphoList.end(); ++ln )
|
||||
{
|
||||
for( QStringList::ConstIterator gr = groupList.begin(); gr != groupList.end(); ++gr )
|
||||
if( ln->compare( gr->left( 2 ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
QVector<sptr<Dictionary::Class> > vdg = dictMap[ *gr ];
|
||||
vdg += morphoMap[ *ln ];
|
||||
dictMap[ *gr ] = vdg;
|
||||
for ( const auto & ln : morphoList ) {
|
||||
for ( const auto & gr : groupList )
|
||||
if ( ln.compare( gr.left( 2 ), Qt::CaseInsensitive ) == 0 ) {
|
||||
QVector< sptr< Dictionary::Class > > vdg = dictMap[ gr ];
|
||||
vdg += morphoMap[ ln ];
|
||||
dictMap[ gr ] = vdg;
|
||||
}
|
||||
}
|
||||
|
||||
// Make groups
|
||||
|
||||
for( QStringList::ConstIterator gr = groupList.begin(); gr != groupList.end(); ++gr )
|
||||
{
|
||||
if( count() )
|
||||
setCurrentIndex( count() - 1 );
|
||||
|
||||
addUniqueGroup( *gr );
|
||||
for ( const auto & gr : groupList ) {
|
||||
const auto idx = addUniqueGroup( gr );
|
||||
|
||||
// add dictionaries into the current group
|
||||
QVector< sptr<Dictionary::Class> > vd = dictMap[ *gr ];
|
||||
DictListModel *model = getCurrentModel();
|
||||
QVector< sptr< Dictionary::Class > > vd = dictMap[ gr ];
|
||||
DictListModel * model = getModelAt( idx );
|
||||
if ( !model )
|
||||
continue;
|
||||
for( int i = 0; i < vd.count(); i++ )
|
||||
model->addRow(QModelIndex(), vd.at( i ) );
|
||||
}
|
||||
|
@ -866,13 +867,12 @@ void DictGroupsWidget::addAutoGroupsByFolders()
|
|||
void DictGroupsWidget::addGroupBasedOnMap( const QMultiMap<QString, sptr<Dictionary::Class>> & groupToDicts )
|
||||
{
|
||||
for ( const auto & group : groupToDicts.uniqueKeys() ) {
|
||||
if ( count() != 0 ) {
|
||||
setCurrentIndex( count() - 1 );
|
||||
const auto idx = addUniqueGroup( group );
|
||||
DictListModel * model = getModelAt( idx );
|
||||
|
||||
if ( !model ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addUniqueGroup( group );
|
||||
DictListModel * model = getCurrentModel();
|
||||
|
||||
for ( const auto & dict : groupToDicts.values( group ) ) {
|
||||
model->addRow( QModelIndex(), dict );
|
||||
}
|
||||
|
@ -902,7 +902,7 @@ void DictGroupsWidget::groupsByMetadata()
|
|||
|
||||
auto filePath = Utils::Path::combine( baseDir, "metadata.toml" );
|
||||
|
||||
auto dictMetaData = Metadata::load( filePath.toStdString() );
|
||||
const auto dictMetaData = Metadata::load( filePath.toStdString() );
|
||||
if ( dictMetaData && dictMetaData->categories ) {
|
||||
for ( const auto & category : dictMetaData->categories.value() ) {
|
||||
auto group = QString::fromStdString( category ).trimmed();
|
||||
|
@ -922,7 +922,7 @@ void DictGroupsWidget::groupsByMetadata()
|
|||
|
||||
QString DictGroupsWidget::getCurrentGroupName() const
|
||||
{
|
||||
int current = currentIndex();
|
||||
const int current = currentIndex();
|
||||
|
||||
if ( current >= 0 )
|
||||
return unescapeAmps( tabText( current ) );
|
||||
|
@ -932,7 +932,7 @@ QString DictGroupsWidget::getCurrentGroupName() const
|
|||
|
||||
void DictGroupsWidget::renameCurrentGroup( QString const & name )
|
||||
{
|
||||
int current = currentIndex();
|
||||
const int current = currentIndex();
|
||||
|
||||
if ( current >= 0 )
|
||||
setTabText( current, escapeAmps( name ) );
|
||||
|
@ -940,13 +940,10 @@ void DictGroupsWidget::renameCurrentGroup( QString const & name )
|
|||
|
||||
void DictGroupsWidget::removeCurrentGroup()
|
||||
{
|
||||
int current = currentIndex();
|
||||
const int current = currentIndex();
|
||||
|
||||
if ( current >= 0 )
|
||||
{
|
||||
QWidget * w = widget( current );
|
||||
if ( current >= 0 ) {
|
||||
removeTab( current );
|
||||
delete w;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -954,7 +951,7 @@ void DictGroupsWidget::removeAllGroups()
|
|||
{
|
||||
while ( count() )
|
||||
{
|
||||
QWidget * w = widget( 0 );
|
||||
const QWidget * w = widget( 0 );
|
||||
removeTab( 0 );
|
||||
delete w;
|
||||
}
|
||||
|
@ -965,37 +962,39 @@ void DictGroupsWidget::combineGroups( int source, int target )
|
|||
if( source < 0 || source >= count() || target < 0 || target >= count() )
|
||||
return;
|
||||
|
||||
setCurrentIndex( source );
|
||||
vector< sptr< Dictionary::Class > > const & dicts = getCurrentModel()->getCurrentDictionaries();
|
||||
vector< sptr< Dictionary::Class > > const & dicts = getDictionaryAt( source );
|
||||
|
||||
setCurrentIndex( target );
|
||||
DictListModel *model = getCurrentModel();
|
||||
const auto model = getModelAt( target );
|
||||
|
||||
if ( !model )
|
||||
return;
|
||||
|
||||
disconnect( model, &DictListModel::contentChanged, this, &DictGroupsWidget::tabDataChanged );
|
||||
|
||||
for( unsigned i = 0; i < dicts.size(); i++ )
|
||||
model->addRow( QModelIndex(), dicts[ i ] );
|
||||
for ( const auto & dict : dicts ) {
|
||||
model->addRow( QModelIndex(), dict );
|
||||
}
|
||||
|
||||
connect( model, &DictListModel::contentChanged, this, &DictGroupsWidget::tabDataChanged );
|
||||
|
||||
QString toolTipStr = "\"" + tabText( target ) + "\"\n" + tr( "Dictionaries: " )
|
||||
+ QString::number( model->getCurrentDictionaries().size() );
|
||||
const QString toolTipStr = "\"" + tabText( target ) + "\"\n" + tr( "Dictionaries: " )
|
||||
+ QString::number( model->getCurrentDictionaries().size() );
|
||||
setTabToolTip( target, toolTipStr );
|
||||
}
|
||||
|
||||
void DictGroupsWidget::contextMenu( QPoint const & pos )
|
||||
{
|
||||
int clickedGroup = tabBar()->tabAt( pos );
|
||||
const int clickedGroup = tabBar()->tabAt( pos );
|
||||
if( clickedGroup < 0 )
|
||||
return;
|
||||
QString name = tabText( clickedGroup );
|
||||
const QString name = tabText( clickedGroup );
|
||||
if( name.length() != 7 || name.mid( 2, 3 ) != " - " )
|
||||
return;
|
||||
|
||||
QMenu menu( this );
|
||||
|
||||
QAction *combineSourceAction = new QAction( QString( tr( "Combine groups by source language to \"%1->\"" ) )
|
||||
.arg( name.left( 2 ) ), &menu );
|
||||
const auto combineSourceAction =
|
||||
new QAction( QString( tr( "Combine groups by source language to \"%1->\"" ) ).arg( name.left( 2 ) ), &menu );
|
||||
combineSourceAction->setEnabled( false );
|
||||
|
||||
QString grLeft = name.left( 2 );
|
||||
|
@ -1011,8 +1010,8 @@ void DictGroupsWidget::contextMenu( QPoint const & pos )
|
|||
}
|
||||
menu.addAction( combineSourceAction );
|
||||
|
||||
QAction *combineTargetAction = new QAction( QString( tr( "Combine groups by target language to \"->%1\"" ) )
|
||||
.arg( name.right( 2 ) ), &menu );
|
||||
const auto combineTargetAction =
|
||||
new QAction( QString( tr( "Combine groups by target language to \"->%1\"" ) ).arg( name.right( 2 ) ), &menu );
|
||||
combineTargetAction->setEnabled( false );
|
||||
|
||||
for( int i = 0; i < count(); i++ )
|
||||
|
@ -1026,15 +1025,15 @@ void DictGroupsWidget::contextMenu( QPoint const & pos )
|
|||
}
|
||||
menu.addAction( combineTargetAction );
|
||||
|
||||
QAction *combineTwoSidedAction = NULL;
|
||||
QAction * combineTwoSidedAction = nullptr;
|
||||
if( grLeft != grRight )
|
||||
{
|
||||
combineTwoSidedAction = new QAction( QString( tr( "Make two-side translate group \"%1-%2-%1\"" ) )
|
||||
.arg( grLeft ).arg( grRight ), &menu );
|
||||
combineTwoSidedAction =
|
||||
new QAction( QString( tr( "Make two-side translate group \"%1-%2-%1\"" ) ).arg( grLeft, grRight ), &menu );
|
||||
|
||||
combineTwoSidedAction->setEnabled( false );
|
||||
|
||||
QString str = grRight + " - " + grLeft;
|
||||
const QString str = grRight + " - " + grLeft;
|
||||
for( int i = 0; i < count(); i++ )
|
||||
{
|
||||
if( str == tabText( i ) )
|
||||
|
@ -1047,8 +1046,7 @@ void DictGroupsWidget::contextMenu( QPoint const & pos )
|
|||
menu.addAction( combineTwoSidedAction );
|
||||
}
|
||||
|
||||
QAction *combineFirstAction = new QAction( QString( tr( "Combine groups with \"%1\"" ) )
|
||||
.arg( grLeft ), &menu );
|
||||
const auto combineFirstAction = new QAction( QString( tr( "Combine groups with \"%1\"" ) ).arg( grLeft ), &menu );
|
||||
combineFirstAction->setEnabled( false );
|
||||
for( int i = 0; i < count(); i++ )
|
||||
{
|
||||
|
@ -1062,7 +1060,7 @@ void DictGroupsWidget::contextMenu( QPoint const & pos )
|
|||
}
|
||||
menu.addAction( combineFirstAction );
|
||||
|
||||
QAction *combineSecondAction = NULL;
|
||||
QAction * combineSecondAction = nullptr;
|
||||
|
||||
if( grLeft != grRight )
|
||||
{
|
||||
|
@ -1083,58 +1081,45 @@ void DictGroupsWidget::contextMenu( QPoint const & pos )
|
|||
menu.addAction( combineSecondAction );
|
||||
}
|
||||
|
||||
QAction *result = menu.exec( mapToGlobal( pos ) );
|
||||
const QAction * result = menu.exec( mapToGlobal( pos ) );
|
||||
|
||||
setUpdatesEnabled( false );
|
||||
int targetGroup;
|
||||
|
||||
if( result && result == combineSourceAction )
|
||||
{
|
||||
setCurrentIndex( clickedGroup );
|
||||
if ( result && result == combineSourceAction ) {
|
||||
targetGroup = addUniqueGroup( grLeft + "->" );
|
||||
|
||||
for( int i = 0; i < count(); i++ )
|
||||
{
|
||||
for ( int i = 0; i < count(); i++ ) {
|
||||
QString str = tabText( i );
|
||||
if( str.length() == 7 && str.mid( 2, 3 ) == " - " && str.startsWith( grLeft ) )
|
||||
if ( str.length() == 7 && str.mid( 2, 3 ) == " - " && str.startsWith( grLeft ) )
|
||||
combineGroups( i, targetGroup );
|
||||
}
|
||||
|
||||
setCurrentIndex( targetGroup );
|
||||
}
|
||||
else
|
||||
if( result && result == combineTargetAction )
|
||||
{
|
||||
setCurrentIndex( clickedGroup );
|
||||
else if ( result && result == combineTargetAction ) {
|
||||
targetGroup = addUniqueGroup( "->" + grRight );
|
||||
|
||||
for( int i = 0; i < count(); i++ )
|
||||
{
|
||||
for ( int i = 0; i < count(); i++ ) {
|
||||
QString str = tabText( i );
|
||||
if( str.length() == 7 && str.mid( 2, 3 ) == " - " && str.endsWith( grRight ) )
|
||||
if ( str.length() == 7 && str.mid( 2, 3 ) == " - " && str.endsWith( grRight ) )
|
||||
combineGroups( i, targetGroup );
|
||||
}
|
||||
|
||||
setCurrentIndex( targetGroup );
|
||||
}
|
||||
else
|
||||
if( result && result == combineTwoSidedAction )
|
||||
{
|
||||
setCurrentIndex( clickedGroup );
|
||||
targetGroup = addUniqueGroup( name + " - " + grLeft );
|
||||
QString str = grRight + " - " + grLeft;
|
||||
else if ( result && result == combineTwoSidedAction ) {
|
||||
targetGroup = addUniqueGroup( name + " - " + grLeft );
|
||||
const QString str = grRight + " - " + grLeft;
|
||||
|
||||
for( int i = 0; i < count(); i++ )
|
||||
if( tabText( i ) == name || tabText( i ) == str )
|
||||
for ( int i = 0; i < count(); i++ )
|
||||
if ( tabText( i ) == name || tabText( i ) == str )
|
||||
combineGroups( i, targetGroup );
|
||||
|
||||
setCurrentIndex( targetGroup );
|
||||
}
|
||||
else
|
||||
if( result && ( result == combineFirstAction || result == combineSecondAction ) )
|
||||
{
|
||||
else if ( result && ( result == combineFirstAction || result == combineSecondAction ) ) {
|
||||
QString const & grBase = result == combineFirstAction ? grLeft : grRight;
|
||||
setCurrentIndex( clickedGroup );
|
||||
targetGroup = addUniqueGroup( grBase );
|
||||
|
||||
for( int i = 0; i < count(); i++ )
|
||||
|
@ -1153,8 +1138,8 @@ void DictGroupsWidget::contextMenu( QPoint const & pos )
|
|||
|
||||
void DictGroupsWidget::tabDataChanged()
|
||||
{
|
||||
QString toolTipStr = "\"" + tabText( currentIndex() ) + "\"\n" + tr( "Dictionaries: " )
|
||||
+ QString::number( getCurrentModel()->getCurrentDictionaries().size() );
|
||||
const QString toolTipStr = "\"" + tabText( currentIndex() ) + "\"\n" + tr( "Dictionaries: " )
|
||||
+ QString::number( getCurrentModel()->getCurrentDictionaries().size() );
|
||||
setTabToolTip( currentIndex(), toolTipStr );
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,10 @@ public:
|
|||
|
||||
/// Marks that this model is used as an immutable dictionary source
|
||||
void setAsSource();
|
||||
bool sourceModel() const { return isSource; }
|
||||
bool sourceModel() const
|
||||
{
|
||||
return isSource;
|
||||
}
|
||||
|
||||
/// Returns the dictionaries the model currently has listed
|
||||
std::vector< sptr< Dictionary::Class > > const & getCurrentDictionaries() const;
|
||||
|
@ -43,16 +46,16 @@ public:
|
|||
void removeSelectedRows( QItemSelectionModel * source );
|
||||
void addSelectedUniqueFromModel( QItemSelectionModel * source );
|
||||
|
||||
Qt::ItemFlags flags( QModelIndex const &index ) const;
|
||||
int rowCount( QModelIndex const & parent ) const;
|
||||
QVariant data( QModelIndex const & index, int role ) const;
|
||||
bool insertRows( int row, int count, const QModelIndex & parent );
|
||||
bool removeRows( int row, int count, const QModelIndex & parent );
|
||||
bool setData( QModelIndex const & index, const QVariant & value, int role );
|
||||
Qt::ItemFlags flags( QModelIndex const & index ) const override;
|
||||
int rowCount( QModelIndex const & parent ) const override;
|
||||
QVariant data( QModelIndex const & index, int role ) const override;
|
||||
bool insertRows( int row, int count, const QModelIndex & parent ) override;
|
||||
bool removeRows( int row, int count, const QModelIndex & parent ) override;
|
||||
bool setData( QModelIndex const & index, const QVariant & value, int role ) override;
|
||||
|
||||
void addRow(const QModelIndex & parent, sptr< Dictionary::Class > dict);
|
||||
void addRow( const QModelIndex & parent, sptr< Dictionary::Class > dict );
|
||||
|
||||
Qt::DropActions supportedDropActions() const;
|
||||
Qt::DropActions supportedDropActions() const override;
|
||||
|
||||
void filterDuplicates();
|
||||
|
||||
|
@ -73,7 +76,7 @@ class DictListWidget: public QListView
|
|||
Q_OBJECT
|
||||
public:
|
||||
DictListWidget( QWidget * parent );
|
||||
~DictListWidget();
|
||||
~DictListWidget() override = default;
|
||||
|
||||
/// Populates the current list with the given dictionaries.
|
||||
void populate( std::vector< sptr< Dictionary::Class > > const & active,
|
||||
|
@ -87,18 +90,20 @@ public:
|
|||
std::vector< sptr< Dictionary::Class > > const & getCurrentDictionaries() const;
|
||||
|
||||
DictListModel * getModel()
|
||||
{ return & model; }
|
||||
{
|
||||
return &model;
|
||||
}
|
||||
|
||||
signals:
|
||||
void gotFocus();
|
||||
|
||||
protected:
|
||||
virtual void dropEvent( QDropEvent * event );
|
||||
virtual void focusInEvent(QFocusEvent *);
|
||||
void dropEvent( QDropEvent * event ) override;
|
||||
void focusInEvent( QFocusEvent * ) override;
|
||||
|
||||
// We need these to to handle drag-and-drop focus issues
|
||||
virtual void rowsInserted( QModelIndex const & parent, int start, int end );
|
||||
virtual void rowsAboutToBeRemoved( QModelIndex const & parent, int start, int end );
|
||||
void rowsInserted( QModelIndex const & parent, int start, int end ) override;
|
||||
void rowsAboutToBeRemoved( QModelIndex const & parent, int start, int end ) override;
|
||||
|
||||
private:
|
||||
DictListModel model;
|
||||
|
@ -156,7 +161,7 @@ public:
|
|||
std::vector< sptr< Dictionary::Class > > const & activeDicts );
|
||||
|
||||
/// Creates new empty group with the given name
|
||||
void addNewGroup( QString const & );
|
||||
int addNewGroup( QString const & );
|
||||
|
||||
/// Creates new empty group with the given name if no such group
|
||||
/// and return it index
|
||||
|
@ -187,6 +192,10 @@ public:
|
|||
|
||||
DictListModel * getCurrentModel() const;
|
||||
|
||||
DictListModel * getModelAt( int current ) const;
|
||||
int getDictionaryCountAt( int current ) const;
|
||||
std::vector< sptr< Dictionary::Class > > getDictionaryAt( int current ) const;
|
||||
|
||||
QItemSelectionModel * getCurrentSelectionModel() const;
|
||||
|
||||
private:
|
||||
|
@ -213,7 +222,7 @@ class QuickFilterLine: public QLineEdit
|
|||
public:
|
||||
|
||||
QuickFilterLine( QWidget * parent );
|
||||
~QuickFilterLine();
|
||||
~QuickFilterLine() override;
|
||||
|
||||
/// Sets the source view to filter
|
||||
void applyTo( QAbstractItemView * source );
|
||||
|
@ -223,7 +232,7 @@ public:
|
|||
QModelIndex mapToSource( QModelIndex const & idx );
|
||||
|
||||
protected:
|
||||
virtual void keyPressEvent( QKeyEvent * event );
|
||||
void keyPressEvent( QKeyEvent * event ) override;
|
||||
|
||||
private:
|
||||
QSortFilterProxyModel m_proxyModel;
|
||||
|
|
Loading…
Reference in a new issue