Compare commits

...

99 Commits

Author SHA1 Message Date
tastytea 733aad9903
Remove xdgcfg dependency by copying it into this repo.
continuous-integration/drone/push Build is failing Details
2021-12-24 16:10:15 +01:00
tastytea 3a8b8c715a
Fix translation loading.
continuous-integration/drone/push Build is passing Details
https://www.kdab.com/fixing-a-common-antipattern-when-loading-translations-in-qt/
2020-07-09 13:22:17 +02:00
tastytea b19e8b233a
Fixed this and that in the readme. 2019-06-12 01:35:52 +02:00
tastytea bc6444747d
CI: Don't let rm fail if lockfile isn't there.
continuous-integration/drone/push Build is passing Details
2019-06-12 00:26:48 +02:00
tastytea ea9755bf9a
Updated readme.
continuous-integration/drone/push Build is failing Details
2019-06-12 00:22:38 +02:00
tastytea 774c1685af
Modified drone config to work with versions > 1.
continuous-integration/drone/push Build is failing Details
2019-06-12 00:14:33 +02:00
tastytea 9067b9dc91
Small cosmetic change to manpage.
the build was successful Details
2019-04-12 19:54:53 +02:00
tastytea 11b88aaf3d
Added files section to manpage.
the build was successful Details
2019-01-21 01:07:04 +01:00
tastytea 231f8ee1bb
fixed readme.
the build was successful Details
2019-01-21 00:30:58 +01:00
tastytea 788d56f98e
Rearranged stuff 2019-01-21 00:29:29 +01:00
tastytea bd33509e7a
Set default variables in build recipe correctly.
the build failed Details
2019-01-21 00:27:38 +01:00
tastytea 3711f30f3b
Fixed manpage version and email 2019-01-21 00:09:24 +01:00
tastytea 69177d5dda
Fixed translation compilation recipe.
the build was successful Details
2019-01-21 00:03:14 +01:00
tastytea dc33ae0a54
Fixed manpage script
the build failed Details
2019-01-21 00:01:29 +01:00
tastytea 032dc9f644
Enhanced manpage 2019-01-21 00:00:38 +01:00
tastytea 1bb26d9c33
Fixed version
the build failed Details
2019-01-20 23:48:47 +01:00
tastytea 3ab52e1b9e
CI: Added asciidoc as dependency
the build failed Details
2019-01-20 23:48:20 +01:00
tastytea 58a79b0681
Renamed whyblocked-gui -> whyblocked 2019-01-20 23:46:41 +01:00
tastytea fac5bd700a
Added manpage. 2019-01-20 23:31:58 +01:00
tastytea 3ed5d3ce0d
Set to blocked by default if account is added via drag & drop.
the build was successful Details
2019-01-16 15:49:36 +01:00
tastytea 449651e94f
Remove mentions of text interface from readme.
the build was successful Details
2019-01-15 01:46:11 +01:00
tastytea 59466c5f9e
Delete all selected rows, not just half.
the build was successful Details
2019-01-15 01:37:55 +01:00
tastytea 229c3f6645
Re-added translations. They were wiped somehow. 2019-01-15 01:08:15 +01:00
tastytea 2acd37bcce
Made "reason"-header is always 125px wide.
the build was successful Details
Because it stretches all the way to ther right anyway.
2019-01-14 20:50:14 +01:00
tastytea ccf31d072e
Changed search method from eventFilter to textChanged-signal.
The search is also updated if one of the checkbuttons is clicked.
2019-01-14 20:45:22 +01:00
tastytea daefd245f0
Refactored the QT interface. (#12)
the build was successful Details
2019-01-14 15:45:05 +01:00
tastytea 8a5aa60d66
Fixed german translation.
the build was successful Details
2019-01-12 22:16:40 +01:00
tastytea 1a99bf1ded
Bugfix: Do not perform a search if mouse enters text field. 2019-01-12 22:14:04 +01:00
tastytea fd951ed502
Deleted text interface. 2019-01-12 21:28:29 +01:00
tastytea d9065280ea
Let the Database-class handle the data. 2019-01-12 21:24:09 +01:00
tastytea 0fdaad70ee
Only reload database on start and when the reload button is clicked. 2019-01-12 20:37:43 +01:00
tastytea 0f13bc8d9b
Rewrote QT interface to use new database interface.
the build was successful Details
2019-01-12 19:35:24 +01:00
tastytea 75dc40406c
Deactivated text interface. 2019-01-12 18:22:05 +01:00
tastytea 54919796d7
Rewrote database interface.
It is a class now and has a saner return type, a struct.
2019-01-12 18:18:49 +01:00
tastytea 165e9039a7
Added more warnings for debug builds, removed superfluous consts 2019-01-12 17:39:20 +01:00
tastytea f29e180092
Update search results if focus enters text field.
the build was successful Details
With this change, the search results are updated if text is dragged
into the text field.
2019-01-11 23:09:11 +01:00
tastytea 64ab212a1f
Fixed german translation.
the build was successful Details
2019-01-11 21:52:14 +01:00
tastytea eab650d6dd
Added settings for checkboxes in find-widget.
the build was successful Details
2019-01-11 21:13:45 +01:00
tastytea dd83e11338
Added find function 2019-01-11 20:50:22 +01:00
tastytea 89eef7247a
Added find action (without function). 2019-01-11 18:58:20 +01:00
tastytea 540877fb75
Removed error report via statusbar, added error reporting via message box.
the build was successful Details
2018-12-06 15:32:28 +01:00
tastytea f0e01cd268
Added link to wiki on binary packages
the build failed Details
2018-11-12 02:05:59 +01:00
tastytea 7407a9a037
updated dependencies
the build was successful Details
2018-11-05 23:29:13 +01:00
tastytea 614eb26f32
CI: Build packages on ubuntu 16.04
the build was successful Details
2018-11-05 21:50:01 +01:00
tastytea 7d1d5e52d8
CI: re-added gnupg
the build was successful Details
2018-11-05 18:07:01 +01:00
tastytea b50f38decf
CI: Building packages on Debian jessie
the build failed Details
2018-11-05 17:52:04 +01:00
tastytea a65c1c549e
Added xdgcfg instructions to readme
the build was successful Details
2018-11-03 13:44:10 +01:00
tastytea e680b8e323
CI: fixed dependency in recipe
the build was successful Details
2018-11-03 13:19:26 +01:00
tastytea 2a8cd9c5b0
Added libconfig dependency
the build failed Details
2018-11-03 13:09:19 +01:00
tastytea 740d0929d2
Added submodule indo to readme
the build failed Details
2018-11-03 13:06:21 +01:00
tastytea 5163b4adbb
Implemented saving and loading settings
the build failed Details
Visibility of toolbar, toolbar location, size of window, width of
table headers. Fixes #6
2018-11-03 12:59:49 +01:00
tastytea 096c74c4cc
Clarified optional dependencies
the build was successful Details
2018-11-02 15:45:06 +01:00
tastytea ce9d156ef2
updated readme, removed AppImage mention.
the build was successful Details
2018-11-02 12:31:56 +01:00
tastytea 0458ef2d8d
Added shortcut to add dialog: Del deletes selected receipt
the build was successful Details
2018-11-02 12:04:29 +01:00
tastytea 9cc5af5142
Added drop-support to add dialog (closes #8)
If text is dropped in the add dialog, a receipt is added with that
text.
2018-11-02 12:00:51 +01:00
tastytea f6ff77571d
Added drop-support to main window (issue #8)
If text is dropped on the main window, the add dialog pops up with the
user/instance field pre-filled.
2018-11-02 11:54:40 +01:00
tastytea 27ccc954a1
Enhanced appdata
the build was successful Details
2018-11-01 20:11:59 +01:00
tastytea 48beb922fa
Removed AppImage support
I was unable to produce an AppImage that works on Ubuntu 18.04, after
several days. I will not spend any further time trying.
2018-11-01 20:11:42 +01:00
tastytea 85ea86953a
typo 2018-10-31 07:14:56 +01:00
tastytea 08de099a0a
Made heading of receipts-label translatable, added german translation
the build was successful Details
2018-10-25 07:36:58 +02:00
tastytea 96cfb050c5
Added automatic package signing
the build was successful Details
2018-10-25 05:02:13 +02:00
tastytea 39b424facc
Made sure translations are not deleted by make clean
the build was successful Details
2018-10-25 03:15:16 +02:00
tastytea ca6e46eb8d
AppImage: Added workaround for translation-placing (bug #7)
the build was successful Details
2018-10-25 02:40:07 +02:00
tastytea a6fe38af2f
Qt interface: Changed the icon names to lookup according to the Icon Naming Specification (bug #7)
the build was successful Details
2018-10-25 00:46:48 +02:00
tastytea ed4fa40a3c
CI: AppImage: Fixed update information
the build was successful Details
2018-10-24 15:25:12 +02:00
tastytea e24ecebc6c
Version bump 0.10.9
the build was successful Details
2018-10-24 14:40:59 +02:00
tastytea 629ee93b2d
translation file update 2018-10-24 14:40:22 +02:00
tastytea 376f77a3c9
CI: AppImage: Added Qt plugin
the build failed Details
2018-10-24 14:36:50 +02:00
tastytea b25da776ae
CI: Added dpkg-dev for shlibs
the build was successful Details
2018-10-24 13:24:28 +02:00
tastytea d44ef20aa1
Fixed dependency versions in readme
the build was successful Details
2018-10-23 10:33:00 +02:00
tastytea 82e1ff1861
CI: Switched back to jessie
the build failed Details
2018-10-23 10:30:34 +02:00
tastytea 576b879cb1
version bump 0.10.7
the build was successful Details
2018-10-23 09:36:03 +02:00
tastytea 3cb5fe3e13
Changed introduction in readme 2018-10-23 09:35:49 +02:00
tastytea 869102e0e9
CI: Install d-shlibs for automatic dependency adding for dpkgs
the build failed Details
2018-10-23 09:08:59 +02:00
tastytea 060b060010
CI: Fixed prepare_release
the build failed Details
2018-10-23 08:30:41 +02:00
tastytea e9be4a1e90
Refactored, cosmetic 2018-10-23 08:29:07 +02:00
tastytea 6692ab8e0c
CI: Build packages on Debian jessie
the build failed Details
2018-10-23 08:02:30 +02:00
tastytea d5316891ef
cmake: Reverted requiredness of sqlite3 2018-10-23 06:28:04 +02:00
tastytea d387c6d8c4
cmake: Stopped linking sqlite3, since we only need vsqlite++
the build failed Details
2018-10-23 01:14:26 +02:00
tastytea bb2a68d326
cmake: Added sqlite3-check 2018-10-22 19:17:41 +02:00
tastytea 97a5cbd1e6
Expanded appdata to comply with the AppStream specification.
the build failed Details
2018-10-22 03:47:57 +02:00
tastytea ea9048fb49
CI: added CXXFLAGS
the build failed Details
2018-10-22 02:15:07 +02:00
tastytea 9ad1eaba37
fixed appdata
the build failed Details
2018-10-22 01:39:01 +02:00
tastytea 3183feb541
Version bump 0.10.6
the build failed Details
2018-10-22 00:11:14 +02:00
tastytea a857d1c7c3
Added appdata.xml
the build failed Details
2018-10-22 00:07:43 +02:00
tastytea f6ed2c8d89
Added AppImage generation
the build failed Details
2018-10-21 23:51:30 +02:00
tastytea 4f6d7477a7
Only try to install translations if WITHOUT_TRANSLATIONS is unset
the build was successful Details
2018-10-20 22:15:14 +02:00
tastytea 3874ec8e98
Added cmake options to readme
the build was successful Details
2018-10-20 07:28:10 +02:00
tastytea a5dec132a1
Split up cmake file 2018-10-20 07:19:14 +02:00
tastytea 691292598a
renamed menus 2018-10-20 06:35:41 +02:00
tastytea b7c8c51486
Removed direct boost dependency
the build was successful Details
2018-10-20 06:06:41 +02:00
tastytea 7fd0412eb1
Added linguist dependencies to readme 2018-10-20 05:42:42 +02:00
tastytea bac1445238
Added icon to packages 2018-10-20 02:15:49 +02:00
tastytea 240e1feeee
Fixed icon
the build failed Details
It was cut off on Ubuntu.
2018-10-20 01:53:08 +02:00
tastytea 1a17fa0c6e
CI: Do not test all compilers on tags 2018-10-20 01:27:57 +02:00
tastytea 6492271faf
Qt interface: Re-Added window title for toolbar
the build was successful Details
If you right-click on the toolbar or menu, you can enable/disable it.
The window title is used there.
2018-10-20 01:11:08 +02:00
tastytea b5cb58e612
Qt interface: Made keyboard shortcuts not translatable.
the build failed Details
Turns out, they no longer work after translation.
2018-10-20 00:40:45 +02:00
tastytea 7fcfd3618f
Added icon
the build was successful Details
2018-10-20 00:34:00 +02:00
tastytea c856555df8
text interface: Switched back to default keys.
the build was successful Details
Translatable command keys were a mistake.
2018-10-18 22:45:58 +02:00
26 changed files with 1847 additions and 1628 deletions

View File

@ -1,202 +1,245 @@
pipeline: kind: pipeline
gcc7: name: build x86_64
image: debian:stretch-slim
pull: true
environment:
- LANG=C.utf8
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- apt-get update -q
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- apt-get install -qy gnupg
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- apt-get update -q
- apt-get install -qy build-essential cmake pkg-config
- apt-get install -qy -t xenial g++-7
- update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 100
- update-alternatives --set g++ /usr/bin/g++-7
- apt-get install -qy libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev qt5-default qttools5-dev-tools
- apt-get install -qy rpm file
- rm -rf build && mkdir -p build && cd build
- cmake ..
- make VERBOSE=1
- make install DESTDIR=install
- make package
- cmake -DWITH_DEB=ON ..
- make package
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON ..
- make package
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
gcc8: volumes:
image: debian:stretch-slim - name: debian-package-cache
pull: true host:
environment: path: /var/cache/debian-package-cache
- LANG=C.utf8
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- apt-get update -q
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- apt-get install -qy gnupg
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- apt-get update -q
- apt-get install -qy build-essential cmake pkg-config
- apt-get install -qy -t xenial g++-8
- update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 100
- update-alternatives --set g++ /usr/bin/g++-8
- apt-get install -qy libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev qt5-default qttools5-dev-tools
- apt-get install -qy rpm file
- rm -rf build && mkdir -p build && cd build
- cmake ..
- make VERBOSE=1
- make install DESTDIR=install
- make package
- cmake -DWITH_DEB=ON ..
- make package
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON ..
- make package
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
clang3: trigger:
image: debian:stretch-slim event:
pull: true exclude:
environment: - tag
- LANG=C.utf8
- CXX=clang++
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- apt-get update -q
- apt-get install -qy build-essential clang cmake pkg-config
- apt-get install -qy libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev qt5-default qttools5-dev-tools
- apt-get install -qy rpm file
- rm -rf build && mkdir -p build && cd build
- cmake ..
- make VERBOSE=1
- make install DESTDIR=install
- make package
- cmake -DWITH_DEB=ON ..
- make package
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON ..
- make package
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
clang5: steps:
image: debian:stretch-slim - name: submodules
pull: true image: docker:git
environment: commands:
- LANG=C.utf8 - git submodule init
- CXX=clang++-5.0 - git submodule update --recursive
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/sid.list
- apt-get update -q
- apt-get install -qy build-essential cmake pkg-config
- apt-get install -qy libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev qt5-default qttools5-dev-tools
- apt-get install -qy rpm file
- apt-get install -qy -t stretch-backports clang-5.0
- rm -rf build && mkdir -p build && cd build
- cmake ..
- make VERBOSE=1
- make install DESTDIR=install
- make package
- cmake -DWITH_DEB=ON ..
- make package
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON ..
- make package
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
clang6: - name: gcc6
image: debian:stretch-slim image: ubuntu:xenial
pull: true pull: always
environment: environment:
- LANG=C.utf8 CXX: g++-6
- CXX=clang++-6.0 CXXFLAGS: -pipe -O2
commands: commands:
- rm /etc/apt/apt.conf.d/docker-clean - rm /etc/apt/apt.conf.d/docker-clean
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release - echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/sid.list - gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- apt-get update -q - gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- apt-get install -qy build-essential cmake pkg-config - rm -f /var/cache/apt/archives/lock
- apt-get install -qy libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev qt5-default qttools5-dev-tools - apt-get update -q
- apt-get install -qy rpm file - rm -f /var/cache/apt/archives/lock
- apt-get install -qy -t stretch-backports clang-6.0 - apt-get install -qy g++-6 cmake pkg-config
- rm -rf build && mkdir -p build && cd build - rm -f /var/cache/apt/archives/lock
- cmake .. - apt-get install -qy libvsqlitepp-dev libboost-dev libxdg-basedir-dev qt5-default qttools5-dev-tools qttools5-dev libconfig++-dev asciidoc
- make VERBOSE=1 - rm -rf build && mkdir -p build && cd build
- make install DESTDIR=install - cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make package - make VERBOSE=1
- cmake -DWITH_DEB=ON .. - make install DESTDIR=install
- make package volumes:
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON .. - name: debian-package-cache
- make package path: /var/cache/apt/archives
volumes:
- /var/cache/debian-package-cache:/var/cache/apt/archives
gcc6: - name: gcc9
image: debian:stretch-slim image: debian:stretch-slim
pull: true pull: always
environment: environment:
- LANG=C.utf8 CXX: g++-9
commands: CXXFLAGS: -pipe -O2
- rm /etc/apt/apt.conf.d/docker-clean commands:
- apt-get update -q - rm /etc/apt/apt.conf.d/docker-clean
- apt-get install -qy build-essential cmake pkg-config - rm -f /var/cache/apt/archives/lock
- apt-get install -qy libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev qt5-default qttools5-dev-tools - apt-get update -q
- apt-get install -qy rpm file - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- rm -rf build && mkdir -p build && cd build - echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/backports.list
- cmake .. - echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- make VERBOSE=1 - rm -f /var/cache/apt/archives/lock
- make install DESTDIR=install - apt-get install -qy gnupg
- make package - gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- cmake -DWITH_DEB=ON .. - gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- make package - rm -f /var/cache/apt/archives/lock
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON .. - apt-get update -q
- make package - rm -f /var/cache/apt/archives/lock
volumes: - apt-get install -qy -t xenial g++-9
- /var/cache/debian-package-cache:/var/cache/apt/archives - rm -f /var/cache/apt/archives/lock
- apt-get install -qy cmake pkg-config
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy libvsqlitepp-dev libboost-dev libxdg-basedir-dev qt5-default qttools5-dev-tools qttools5-dev libconfig++-dev asciidoc
- rm -rf build && mkdir -p build && cd build
- cmake ..
- make VERBOSE=1
- make install DESTDIR=install
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: clang3
image: debian:stretch-slim
pull: always
environment:
CXX: clang++
CXXFLAGS: -pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/backports.list
- rm -f /var/cache/apt/archives/lock
- apt-get update -q
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy clang cmake pkg-config
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy libvsqlitepp-dev libboost-dev libxdg-basedir-dev qt5-default qttools5-dev-tools qttools5-dev libconfig++-dev asciidoc
- rm -rf build && mkdir -p build && cd build
- cmake ..
- make VERBOSE=1
- make install DESTDIR=install
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
prepare_release: - name: clang6
image: debian:stretch-slim image: debian:stretch-slim
pull: true pull: always
when: environment:
event: tag CXX: clang++-6.0
commands: CXXFLAGS: -pipe -O2
- cp -v build/whyblocked-${DRONE_TAG}_x86_64.tar.gz . commands:
- cp -v build/whyblocked_${DRONE_TAG}-0_amd64.deb . - rm /etc/apt/apt.conf.d/docker-clean
- cp -v build/whyblocked-${DRONE_TAG}-0.x86_64.rpm . - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release
- echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/stretch.list
- rm -f /var/cache/apt/archives/lock
- apt-get update -q
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy -t stretch-backports clang-6.0
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy cmake pkg-config
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy libvsqlitepp-dev libboost-dev libxdg-basedir-dev qt5-default qttools5-dev-tools qttools5-dev libconfig++-dev asciidoc
- rm -rf build && mkdir -p build && cd build
- cmake ..
- make VERBOSE=1
- make install DESTDIR=install
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
gitea_release: - name: notify
image: plugins/gitea-release image: drillster/drone-email
pull: true pull: always
when: settings:
event: tag host: cryptoparty-celle.de
username:
from_secret: email_username
password:
from_secret: email_password
from: drone@tzend.de
when:
status: [ changed, failure ]
---
kind: pipeline
name: packages x86_64
volumes:
- name: debian-package-cache
host:
path: /var/cache/debian-package-cache
- name: gpg-key
host:
path: /var/autosign_gpg.key
trigger:
event:
- tag
steps:
- name: submodules
image: docker:git
commands:
- git submodule init
- git submodule update --recursive
- name: gcc6
image: ubuntu:xenial
pull: always
environment:
CXX: g++-6
CXXFLAGS: -pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f
- gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add -
- rm -f /var/cache/apt/archives/lock
- apt-get update -q
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy g++-6 cmake pkg-config
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy libvsqlitepp-dev libboost-dev libxdg-basedir-dev qt5-default qttools5-dev-tools qttools5-dev libconfig++-dev asciidoc
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy dpkg-dev rpm file wget
- gpg --import /var/autosign_gpg.key
- rm -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
- make install DESTDIR=install
- make package
- cmake -DWITH_DEB=ON ..
- make package
- cmake -DWITH_DEB=OFF -DWITH_RPM=ON ..
- make package
- gpg --verbose --detach-sign *.tar.gz
- gpg --verbose --detach-sign *.deb
- gpg --verbose --detach-sign *.rpm
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: gpg-key
path: /var/autosign_gpg.key
- name: prepare_release
image: ubuntu:xenial
pull: always
commands:
- cp -v build/whyblocked-${DRONE_TAG}_x86_64.tar.gz .
- cp -v build/whyblocked-${DRONE_TAG}_x86_64.tar.gz.sig .
- cp -v build/whyblocked_${DRONE_TAG}-0_amd64.deb .
- cp -v build/whyblocked_${DRONE_TAG}-0_amd64.deb.sig .
- cp -v build/whyblocked-${DRONE_TAG}-0.x86_64.rpm .
- cp -v build/whyblocked-${DRONE_TAG}-0.x86_64.rpm.sig .
- name: release
image: plugins/gitea-release
pull: always
settings:
base_url: https://schlomp.space base_url: https://schlomp.space
secrets: [ gitea_token ] api_key:
from_secret: gitea_token
title: ${DRONE_TAG} title: ${DRONE_TAG}
prerelease: true prerelease: true
files: files:
- whyblocked-${DRONE_TAG}_x86_64.tar.gz - whyblocked-${DRONE_TAG}_x86_64.tar.gz
- whyblocked-${DRONE_TAG}_x86_64.tar.gz.sig
- whyblocked_${DRONE_TAG}-0_amd64.deb - whyblocked_${DRONE_TAG}-0_amd64.deb
- whyblocked_${DRONE_TAG}-0_amd64.deb.sig
- whyblocked-${DRONE_TAG}-0.x86_64.rpm - whyblocked-${DRONE_TAG}-0.x86_64.rpm
- whyblocked-${DRONE_TAG}-0.x86_64.rpm.sig
checksum: checksum:
- sha256 - sha256
- sha512 - sha512
notify: - name: notify
image: drillster/drone-email image: drillster/drone-email
pull: true pull: always
settings:
host: cryptoparty-celle.de host: cryptoparty-celle.de
secrets: [ email_username, email_password ] username:
from_secret: email_username
password:
from_secret: email_password
from: drone@tzend.de from: drone@tzend.de
when: when:
status: [ changed, failure ] status: [ changed, failure ]

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "xdgcfg"]
path = xdgcfg
url = https://schlomp.space/tastytea/xdgcfg.git

View File

@ -1,33 +1,39 @@
cmake_minimum_required (VERSION 3.6) cmake_minimum_required (VERSION 3.2)
project (whyblocked project (whyblocked
VERSION 0.10.0 VERSION 0.15.0
LANGUAGES CXX LANGUAGES CXX
) )
include(GNUInstallDirs) include(GNUInstallDirs)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir) pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir)
# sqlite3 is not a direct dependency, but vsqlite++ has no cmake- or pkg-config
# module. Since it installs in the same directories as sqlite3, I am adding the
# module here to add the include- and link directories below. It is not REQUIRED
# because the sqlite3 in Debian jessie doesn't come with a pkg-config module.
pkg_check_modules(SQLITE3 sqlite3)
find_package(Qt5Core CONFIG REQUIRED) find_package(Qt5Core CONFIG REQUIRED)
if(NOT WITHOUT_GUI) find_package(Qt5Widgets CONFIG REQUIRED)
find_package(Qt5Widgets CONFIG REQUIRED) pkg_check_modules(LIBCONFIG REQUIRED libconfig++)
endif()
find_package(Qt5LinguistTools)
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -g -Og") set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -Wpedantic -Wall -Wextra -g -Og -fno-omit-frame-pointer")
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR}) include_directories(${PROJECT_BINARY_DIR})
include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS}) include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS})
include_directories(${SQLITE3_INCLUDE_DIRS})
include_directories(${LIBCONFIG_INCLUDE_DIRS})
link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS}) link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS})
link_directories(${SQLITE3_LIBRARY_DIRS})
link_directories(${LIBCONFIG_LIBRARY_DIRS})
# Write version in header # Write version in header
configure_file ( configure_file (
@ -35,87 +41,47 @@ configure_file (
"${PROJECT_BINARY_DIR}/version.hpp" "${PROJECT_BINARY_DIR}/version.hpp"
) )
if(Qt5_LRELEASE_EXECUTABLE) add_executable(${CMAKE_PROJECT_NAME}
file(GLOB TS_FILES "translations/*.ts") src/qt/main.cpp src/qt/mainwindow.cpp src/qt/dialog_add.cpp
file(GLOB TS_SRC_FILES "src/*") src/whyblocked.cpp src/xdgcfg.cpp)
qt5_create_translation(QM_FILES ${TS_SRC_FILES} ${TS_FILES} target_link_libraries(${CMAKE_PROJECT_NAME}
OPTIONS -no-obsolete) ${LIBXDG_BASEDIR_LIBRARIES} vsqlitepp Qt5::Widgets
qt5_add_translation(QM_FILES ${TS_FILES}) ${LIBCONFIG_LIBRARIES} stdc++fs)
set(WITH_MAN "YES" CACHE STRING "WITH_MAN defaults to \"YES\"")
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_PROJECT_NAME} whyblocked-gui)
if(WITH_MAN)
add_custom_command(
OUTPUT "${PROJECT_BINARY_DIR}/whyblocked.1"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
DEPENDS "${CMAKE_SOURCE_DIR}/whyblocked.1.adoc"
COMMAND ${CMAKE_SOURCE_DIR}/build_manpage.sh
ARGS ${PROJECT_VERSION})
add_custom_target(run ALL
DEPENDS "${PROJECT_BINARY_DIR}/whyblocked.1"
)
endif() endif()
add_executable(whyblocked src/interface_text.cpp src/whyblocked.cpp) install(TARGETS ${CMAKE_PROJECT_NAME}
target_link_libraries(whyblocked DESTINATION ${CMAKE_INSTALL_BINDIR})
${LIBXDG_BASEDIR_LIBRARIES} vsqlitepp stdc++fs Qt5::Core) install(FILES "${PROJECT_BINARY_DIR}/whyblocked-gui"
install(TARGETS whyblocked DESTINATION ${CMAKE_INSTALL_BINDIR}) DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(FILES de.tastytea.Whyblocked.desktop
if(NOT WITHOUT_GUI) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
add_executable(whyblocked-gui src/interface_qt.cpp src/whyblocked.cpp install(FILES de.tastytea.Whyblocked.appdata.xml
${QM_FILES}) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)
target_link_libraries(whyblocked-gui install(FILES de.tastytea.Whyblocked.svg
${LIBXDG_BASEDIR_LIBRARIES} vsqlitepp stdc++fs DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps)
Qt5::Widgets) if(WITH_MAN)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/whyblocked.1
install(TARGETS whyblocked-gui DESTINATION ${CMAKE_INSTALL_BINDIR}) DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
install(FILES de.tastytea.Whyblocked.desktop DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES ${QM_FILES} DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}/qt5/translations)
endif() endif()
set(WITH_TRANSLATIONS "YES" CACHE STRING "WITH_TRANSLATIONS defaults to \"YES\"")
# Packages if(WITH_TRANSLATIONS)
set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) add_subdirectory(translations)
set(CPACK_PACKAGE_VERSION_MAJOR ${mastodon-cpp_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${mastodon-cpp_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${mastodon-cpp_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION ${whyblocked_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "whyblocked reminds you why you blocked someone.")
set(CPACK_PACKAGE_CONTACT "tastytea <tastytea@tastytea.de>")
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git"
"/.gitignore"
"/build/"
"\\\\.sublime-"
"/.drone.yml")
execute_process(COMMAND uname -m
OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}")
set(CPACK_GENERATOR "TGZ")
set(CPACK_SOURCE_GENERATOR "TGZ")
if (WITH_DEB)
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
set(CPACK_GENERATOR "DEB")
set(CPACK_SOURCE_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://schlomp.space/tastytea/whyblocked")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
execute_process(COMMAND dpkg --print-architecture
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_src")
endif() endif()
if (WITH_RPM) include(packages.CMakeLists.txt)
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
set(CPACK_GENERATOR "RPM")
set(CPACK_SOURCE_GENERATOR "RPM")
set(CPACK_RPM_PACKAGE_LICENSE "GPL-3")
set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/whyblocked")
if(NOT WITHOUT_QT)
set(CPACK_RPM_PACKAGE_REQUIRES "vsqlite++ >= 0.3.13, libxdg-basedir >= 1.2.0, qt >= 5.0")
else()
set(CPACK_RPM_PACKAGE_REQUIRES "vsqlite++ >= 0.3.13, libxdg-basedir >= 1.2.0")
endif()
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.src")
endif()
include(CPack)

View File

@ -1,14 +1,13 @@
**Whyblocked** reminds you why you blocked someone. It is developed with **Whyblocked** allows you to store the reason why you blocked someone, along
Mastodon in mind, but can be used for other contexts, of course. with “receipts”, URLs to the posts that led you to block them.
It has a text- and a Qt-interface and uses a SQLite-database. It has a Qt-interface and uses an SQLite-database.
![Screenshot Qt interface](https://doc.schlomp.space/whyblocked/whyblocked_screenshot.png) ![Screenshot](https://doc.schlomp.space/whyblocked/whyblocked_screenshot.png)
## Usage ## Usage
For the text interface start `whyblocked`, for the Qt interface Run `whyblocked`. You can also start it from the menu of your desktop
`whyblocked-gui`. You can also start it from the menu of your desktop
environment. environment.
## Install ## Install
@ -17,8 +16,13 @@ environment.
Every [release](https://schlomp.space/tastytea/whyblocked/releases) includes Every [release](https://schlomp.space/tastytea/whyblocked/releases) includes
a .deb-package, an .rpm-package and a .tar.gz-package with precompiled binaries a .deb-package, an .rpm-package and a .tar.gz-package with precompiled binaries
for x86_64(amd64). These are automatically built and not tested. You can install for x86_64(amd64)
them with `dpkg -i` or `rpm -i`, respectively. ([more info](https://schlomp.space/tastytea/whyblocked/wiki/Binary-Packages)).
These are automatically built and not tested. You can install them with
`apt install ./whyblocked*.deb` or `yum install ./whyblocked*.rpm`,
respectively. The packages are signed with the PGP key
[242E5AC4DA587BF9](https://tastytea.de/tastytea_autosign.asc)
(Fingerprint: `F730 1ADF C9ED 2624 48C4 2B64 242E 5AC4 DA58 7BF9`).
Gentoo ebuilds are available via my Gentoo ebuilds are available via my
[repository](https://schlomp.space/tastytea/overlay). [repository](https://schlomp.space/tastytea/overlay).
@ -27,13 +31,17 @@ Gentoo ebuilds are available via my
#### Dependencies #### Dependencies
* C++ compiler (tested: [gcc](https://gcc.gnu.org/) 6/7/8, * C++ compiler (tested: [gcc](https://gcc.gnu.org/) 6/8/9,
[clang](https://llvm.org/) 3/5/6) [clang](https://llvm.org/) 3/6)
* [cmake](https://cmake.org/) (at least 3.6) * [cmake](https://cmake.org/) (at least 3.2)
* [vsqlite++](http://vsqlite.virtuosic-bytes.com/) (tested: 0.3.13) * [vsqlite++](http://vsqlite.virtuosic-bytes.com/) (tested: 0.3)
* [libxdg-basedir](http://repo.or.cz/w/libxdg-basedir.git) (tested: 1.2) * [libxdg-basedir](http://repo.or.cz/w/libxdg-basedir.git) (tested: 1.2)
* [qtcore](https://www.qt.io/) (tested: 5.11/5.7) * [qtcore](https://www.qt.io/) (tested: 5.12/5.5)
* [qtwidgets](https://www.qt.io/) (tested: 5.11/5.7) * [qtwidgets](https://www.qt.io/) (tested: 5.12/5.5)
* [libconfig++](https://github.com/hyperrealm/libconfig) (tested: 1.5)
* Optional
* Translations: [lupdate & lrelease](http://doc.qt.io/qt-5/linguist-manager.html) (tested: 5.12/5.5)
* Manpage: [asciidoc](http://asciidoc.org/) (tested: 8.6)
#### Get sourcecode #### Get sourcecode
@ -42,7 +50,7 @@ Download the current
#### Compile #### Compile
```SH ``` zsh
mkdir build mkdir build
cd build cd build
cmake .. cmake ..
@ -50,6 +58,14 @@ make
make install make install
``` ```
cmake options:
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build
* `-DWITH_TRANSLATIONS=NO` to not compile translations
* `-DWITH_MAN=NO` to not compile the manpage
* One of:
* `-DWITH_DEB=YES` if you want to be able to generate a deb-package
* `-DWITH_RPM=YES` if you want to be able to generate an rpm-package
## Contributing ## Contributing
Contributions are always welcome. You can submit them as pull requests or via Contributions are always welcome. You can submit them as pull requests or via
@ -71,11 +87,19 @@ Please report them on the
[issue tracker](https://schlomp.space/tastytea/whyblocked/issues) or to [issue tracker](https://schlomp.space/tastytea/whyblocked/issues) or to
`tastytea`@`tastytea.de`. `tastytea`@`tastytea.de`.
## Copyright ## Licence & Copyright
```PLAIN ``` plain
Copyright © 2018 tastytea <tastytea@tastytea.de>. Copyright © 2018 tastytea <tastytea@tastytea.de>.
License GPLv3: GNU GPL version 3 <https://www.gnu.org/licenses/gpl-3.0.html>. License GPLv3: GNU GPL version 3 <https://www.gnu.org/licenses/gpl-3.0.html>.
This program comes with ABSOLUTELY NO WARRANTY. This is free software, This program comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions. and you are welcome to redistribute it under certain conditions.
``` ```
The icon is derived from the icons *“messagebox critical”* and *“help”* of the
[Gartoon icon theme](https://commons.wikimedia.org/wiki/Gartoon_icons). The
original authors were Zeus, Patrick Yavitz and La Mula Francis, who released
them under the terms of the
[GPL2+](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) and
[DSL](http://www.fsf.org/licensing/licenses/dsl.html). The new icon is released
under the same terms.

10
build_manpage.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
if [ -n "${1}" ]; then
dir="$(dirname ${0})"
cp -vf ${dir}/whyblocked.1.adoc .
sed -Ei "s/(Revision: +)[0-9]+\.[0-9]\.[0-9]/\1${1}/" whyblocked.1.adoc
a2x --doctype manpage --format manpage --no-xmllint whyblocked.1.adoc
else
echo "usage: ${0} VERSION" >&2
fi

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>de.tastytea.Whyblocked</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0</project_license>
<name>Whyblocked</name>
<summary>Reminds you why you blocked someone</summary>
<summary xml:lang="de">Erinnert dich, warum du jemanden blockiertest</summary>
<description>
<p>
Whyblocked allows you to store the reason why you blocked someone, along
with "receipts", URLs to the posts that led you to block them.
</p>
</description>
<categories>
<category>Utility</category>
</categories>
<launchable type="desktop-id">de.tastytea.Whyblocked.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>https://doc.schlomp.space/whyblocked/whyblocked_screenshot.png</image>
</screenshot>
</screenshots>
<url type="homepage">https://schlomp.space/tastytea/whyblocked</url>
<url type="bugtracker">https://schlomp.space/tastytea/whyblocked/issues</url>
</component>

View File

@ -4,8 +4,8 @@ Version=1.1
Name=Whyblocked Name=Whyblocked
Comment=Reminds you why you blocked someone Comment=Reminds you why you blocked someone
Comment[de]=Erinnert dich, warum du jemanden blockiertest Comment[de]=Erinnert dich, warum du jemanden blockiertest
#Icon=org.tastytea.Whyblocked Icon=de.tastytea.Whyblocked
Exec=whyblocked-gui Exec=whyblocked
Terminal=false Terminal=false
Categories=Utility; Categories=Utility;
Keywords=blocklist;social-network; Keywords=blocklist;social-network;

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
height="96"
width="96"
id="svg582">
<metadata
id="metadata3770">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs584" />
<circle
r="36.697987"
cy="54.63929"
cx="41.000965"
id="path585"
style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.81696439pt;stroke-opacity:1" />
<circle
r="32.105907"
cy="54.998936"
cx="41.226917"
id="path586"
style="font-size:12px;fill:#ff1500;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.71473642pt;stroke-opacity:1" />
<path
id="path590"
d="m 17.175004,48.615656 -0.05518,11.96019 47.840764,0.220747 0.05518,-11.96019 z"
style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.76233709pt" />
<path
id="path582"
d="m 73.332827,54.998938 c 0,2.215308 -0.224743,4.378443 -0.652654,6.467835 -0.427911,2.089393 -1.058994,4.105041 -1.871674,6.025377 -0.812681,1.920334 -1.806961,3.745354 -2.961268,5.453489 -1.154309,1.708134 -2.468644,3.299384 -3.921437,4.752176 -1.452791,1.452792 -3.044041,2.767129 -4.752175,3.921436 -1.708134,1.154308 -3.533155,2.148588 -5.45349,2.961268 -1.920335,0.81268 -3.935983,1.443763 -6.025375,1.871675 -2.089393,0.427911 -4.252528,0.652653 -6.467836,0.652653 -2.215307,0 -4.378443,-0.224742 -6.467835,-0.652653 -2.089393,-0.427912 -4.105042,-1.058995 -6.025376,-1.871675 -1.920335,-0.81268 -7.487408,-3.297913 -5.45349,-2.961268 61.196537,10.098434 43.412705,-46.275148 44.567014,-44.567014 1.154307,1.708135 2.148587,3.533155 2.961268,5.45349 0.81268,1.920335 1.443763,3.935984 1.871674,6.025376 0.427911,2.089392 0.652654,4.252528 0.652654,6.467835 z"
style="font-size:12px;fill:#cb0000;fill-opacity:1;fill-rule:evenodd;stroke-width:0.71473642pt" />
<path
id="path583"
d="m 8.5654503,56.089226 c -0.1365183,-2.211097 -0.045507,-4.38397 0.2528332,-6.495761 0.2983392,-2.111791 0.8040078,-4.1625 1.4968035,-6.129268 0.692795,-1.966764 1.572718,-3.849588 2.619569,-5.625611 1.046851,-1.776022 2.260628,-3.445243 3.621131,-4.984802 1.360502,-1.53956 2.867731,-2.949458 4.501485,-4.206835 1.633755,-1.257378 3.394033,-2.362234 5.260636,-3.29171 1.866604,-0.929477 3.839532,-1.683575 5.898583,-2.239431 2.059051,-0.555856 4.204227,-0.913474 6.415323,-1.049991 2.211097,-0.136518 4.383971,-0.04551 6.495763,0.252832 2.111791,0.29834 4.162498,0.804008 6.129265,1.496803 1.966767,0.692796 7.7928,3.737778 5.810084,3.172984 C 7.5394825,12.932635 10.171299,64.5636 9.6154425,62.504549 9.059586,60.445497 8.7019687,58.300324 8.5654503,56.089226 Z"
style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.83482128pt" />
<path
id="path577"
d="m 48.266792,61.564074 12.112009,6.755343 C 63.406881,67.68611 71.842055,64.519574 75.302674,62.197381 74.004955,60.508495 73.572416,57.34206 72.707236,55.019867 76.167854,54.175526 95.84996,41.720318 90.442866,23.776583 75.519098,-9.9998284 38.31758,13.010413 38.101258,14.910335 c -0.216216,1.8999 5.19098,10.977406 6.70502,13.299499 l 9.516571,4.222014 6.272377,-3.588707 c -5.190876,9.499606 -12.760972,12.24387 -14.491332,14.354927 -0.865078,0.422171 2.379219,18.999313 2.162898,18.366006 z"
style="fill:#000000;fill-opacity:0.3;fill-rule:evenodd;stroke:none;stroke-width:1.02010846pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<ellipse
id="path575"
style="fill:#000000;fill-opacity:0.3;fill-rule:evenodd;stroke:none;stroke-width:1.16593337pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
cx="66.994057"
cy="72.316933"
rx="13.777713"
ry="12.954969" />
<ellipse
ry="12.118935"
rx="12.384315"
cy="71.202225"
cx="65.18264"
id="path558"
style="fill:#002c00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.06914175pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path556"
d="m 47.083689,56.718653 11.035075,6.305838 C 60.877603,62.433324 68.562765,59.477492 71.715684,57.309819 70.533351,55.733313 70.139272,52.777575 69.351019,50.609902 72.503938,49.821743 90.436016,38.195314 85.509692,21.445569 71.912866,-10.083336 38.019106,11.395788 37.82202,13.169288 c -0.196993,1.773479 4.729425,10.246961 6.108844,12.41454 l 8.670409,3.941078 5.714671,-3.349912 c -4.729331,8.867495 -11.626334,11.429154 -13.202841,13.39974 -0.788159,0.394079 2.167673,17.735085 1.970586,17.143919 z"
style="fill:#002c00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.94074851pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path553"
d="m 50.827774,54.353987 8.670409,-3.349911 7.685163,4.729237 -8.867496,3.152919 z"
style="fill:#007900;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.94074851pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path554"
d="m 59.498183,51.003981 c 0,0 6.896909,5.123506 7.093997,5.123506 0.197086,0 -1.576413,-7.291084 -1.576413,-7.291084 33.105307,-21.676163 7.88225,-35.864165 5.714671,-37.834722 9.458756,17.537978 -7.291083,31.134899 -12.414588,35.075977 -0.394079,3.152918 1.37942,5.517584 1.37942,5.517584 z"
style="fill:#007900;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.94074851pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path557"
d="m 45.31019,21.445569 c 2.758839,1.97068 8.276329,3.941171 8.276329,3.941171 l 9.852836,-4.335251 C 61.074689,17.504491 53.19244,18.095657 45.31019,21.445569 Z"
style="fill:#007900;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.94074851pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
id="path562"
d="m 74.382363,71.821463 c 0,4.687628 -3.764785,8.492069 -8.403507,8.492069 -4.638911,0 -8.403696,-3.804441 -8.403696,-8.492069 0,-4.687627 10.487722,-1.827345 8.403696,-8.492065 4.638722,0 8.403507,3.804438 8.403507,8.492065 z"
style="font-size:12px;fill:#007900;fill-opacity:1;fill-rule:evenodd;stroke-width:0.98431286pt" />
<path
id="path561"
d="m 71.197847,70.583051 c 0,4.394635 -3.447748,7.961337 -7.695892,7.961337 -4.248236,0 -7.695985,-3.566702 -7.695985,-7.961337 0,-4.394636 3.447749,-7.961336 7.695985,-7.961336 4.248144,0 7.695892,3.5667 7.695892,7.961336 z"
style="font-size:12px;fill:#00ff00;fill-rule:evenodd;stroke-width:0.9847548pt" />
<path
id="path552"
d="m 48.463109,41.348327 2.167579,13.399739 8.867495,-3.152918 -0.985246,-5.51749 c 0,0 22.66141,-13.793914 16.552659,-29.7555 C 68.956939,6.4693868 57.921771,4.8929462 42.748437,15.336912 c 1.970587,3.152919 3.546999,7.48817 4.335252,7.48817 6.699823,-3.744085 16.552658,-6.108751 17.143919,0.39408 0.591167,2.955832 -11.823422,17.734991 -15.764499,18.129165 z"
style="fill:#00ff00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.94074851pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

57
packages.CMakeLists.txt Normal file
View File

@ -0,0 +1,57 @@
# Packages
set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME})
set(CPACK_PACKAGE_VERSION_MAJOR ${${CMAKE_PROJECT_NAME}_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${${CMAKE_PROJECT_NAME}_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${${CMAKE_PROJECT_NAME}_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION ${whyblocked_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Whyblocked reminds you why you blocked someone.")
set(CPACK_PACKAGE_CONTACT "tastytea <tastytea@tastytea.de>")
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md")
set(CPACK_PACKAGE_ICON "de.tastytea.Whyblocked.svg")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git"
"/.gitignore"
"/build/"
"\\\\.sublime-"
"/.drone.yml")
execute_process(COMMAND uname -m
OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}")
set(CPACK_GENERATOR "TGZ")
set(CPACK_SOURCE_GENERATOR "TGZ")
if (WITH_DEB)
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
set(CPACK_GENERATOR "DEB")
set(CPACK_SOURCE_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://schlomp.space/tastytea/whyblocked")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
execute_process(COMMAND dpkg --print-architecture
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_src")
endif()
if (WITH_RPM)
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
set(CPACK_GENERATOR "RPM")
set(CPACK_SOURCE_GENERATOR "RPM")
set(CPACK_RPM_PACKAGE_LICENSE "GPL-3")
set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/whyblocked")
if(NOT WITHOUT_QT)
set(CPACK_RPM_PACKAGE_REQUIRES "vsqlite++ >= 0.3.13, libxdg-basedir >= 1.2.0, qt >= 5.0")
else()
set(CPACK_RPM_PACKAGE_REQUIRES "vsqlite++ >= 0.3.13, libxdg-basedir >= 1.2.0")
endif()
set(CPACK_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.src")
endif()
include(CPack)

View File

@ -1,277 +0,0 @@
/* This file is part of whyblocked.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <regex>
#include <QMessageBox>
#include <QDebug>
#include <QTranslator>
#include <QLibraryInfo>
#include "version.hpp"
#include "whyblocked.hpp"
#include "interface_qt.hpp"
MainWindow::MainWindow(QMainWindow *parent) : QMainWindow(parent)
{
setupUi(this);
_model = new QStandardItemModel;
tableview->setModel(_model);
populate_tableview();
}
void MainWindow::populate_tableview()
{
_model->clear();
_model->setHorizontalHeaderLabels(
{
tr("User/Instance"),
tr("Blocked/Silenced"),
tr("Reason")
});
tableview->horizontalHeader()->resizeSection(0, 250);
result_view result;
if (database::view(result))
{
for (const std::tuple<string, int, string> &line : result)
{
add_row(QString::fromStdString(std::get<0>(line)),
std::get<1>(line),
QString::fromStdString(std::get<2>(line)));
}
}
statusBar()->showMessage(tr("Database loaded."));
}
void MainWindow::add_row(const QString &user, const int &blocked, const QString &reason)
{
QList<QStandardItem*> items;
items.append(new QStandardItem(user));
if (blocked == 1)
{
items.append(new QStandardItem(QString(tr("blocked"))));
}
else
{
items.append(new QStandardItem(QString(tr("silenced"))));
}
items.append(new QStandardItem(reason));
_model->appendRow(items);
}
void MainWindow::add()
{
DialogAdd *dialog = new DialogAdd(this);
dialog->show();
}
void MainWindow::edit()
{
if (tableview->selectionModel()->selectedRows().count() != 1)
{
QMessageBox::warning(this, tr("Invalid selection"),
tr("Please select only 1 entry to edit."));
return;
}
DialogAdd *dialog = new DialogAdd(this);
dialog->setWindowTitle(tr("Edit entry"));
Dialogdata data;
QModelIndex index = tableview->selectionModel()->selectedRows().first();
data.user = index.sibling(index.row(), 0).data().toString().toStdString();
result_details details;
database::details(data.user, details);
if (std::get<0>(details) == true)
{
data.blocked = 1;
}
else
{
data.blocked = 0;
}
data.reason = std::get<1>(details);
data.receipts = std::get<2>(details);
dialog->set_data(data);
dialog->setProperty("edit", true);
dialog->show();
}
void MainWindow::remove()
{
QItemSelectionModel *selection = tableview->selectionModel();
if (selection->hasSelection())
{
for (auto &row : selection->selectedRows())
{
const string user = row.data().toString().toStdString();
database::remove(user);
statusBar()->showMessage(tr("Removed %1 from database.")
.arg(QString::fromStdString(user)));
_model->removeRow(row.row());
}
label_receipts->clear();
}
else
{
statusBar()->showMessage(tr("Select data to remove."));
}
}
void MainWindow::about()
{
QMessageBox::about(this, tr("About Whyblocked"),
tr("<p><b>Whyblocked</b> %1</p>"
"<p>Reminds you why you blocked someone.</p>"
"<p>Sourcecode: <a href=\"https://schlomp.space/tastytea/whyblocked\">"
"https://schlomp.space/tastytea/whyblocked</a></p>"
"<p><small>Copyright © 2018 <a href=\"mailto:tastytea@tastytea.de\">tastytea</a>.<br>"
"Licence GPLv3: <a href=\"https://www.gnu.org/licenses/gpl-3.0.html\">"
"GNU GPL version 3</a>.<br>"
"This program comes with ABSOLUTELY NO WARRANTY. This is free software, "
"and you are welcome to redistribute it under certain conditions.</small></p>")
.arg(global::version));
}
void MainWindow::show_details(QModelIndex index)
{
const string user = index.sibling(index.row(), 0).data().toString().toStdString();
result_details result;
string text = "";
if (database::details(user, result))
{
if (!std::get<2>(result).empty())
{
text += "<b>Receipts:</b>";
for (const string &url : std::get<2>(result))
{
text += "<br>" + url;
}
text = urls_to_hyperlinks(text);
}
label_receipts->setText(QString::fromStdString((text)));
}
}
const string MainWindow::urls_to_hyperlinks(const string &text)
{
std::regex re_url("((https?|gopher|ftps?)\\://[^ <]*)");
return std::regex_replace(text, re_url, "<a href=\"$1\">$1</a>");
}
DialogAdd::DialogAdd(QMainWindow *parent)
: QDialog(parent)
, _parent(static_cast<MainWindow*>(parent))
{
setupUi(this);
}
const Dialogdata DialogAdd::get_data() const
{
std::vector<string> receipts;
for (int row = 0; row <= list_receipts->count() - 1; ++row)
{
receipts.push_back(list_receipts->item(row)->text().toStdString());
}
Dialogdata data;
data.user = text_user->text().toStdString();
data.blocked = radio_blocked->isChecked();
data.reason = text_reason->text().toStdString();
data.receipts = receipts;
return data;
}
const void DialogAdd::set_data(const Dialogdata &data)
{
text_user->setText(QString::fromStdString(data.user));
radio_blocked->setChecked(data.blocked);
radio_silcenced->setChecked(!data.blocked);
text_reason->setText(QString::fromStdString(data.reason));
for (const string &receipt : data.receipts)
{
QListWidgetItem *item = new QListWidgetItem(QString::fromStdString(receipt));
item->setFlags(item->flags() | Qt::ItemIsEditable);
list_receipts->insertItem(list_receipts->count(), item);
}
}
void DialogAdd::add_receipt()
{
QListWidgetItem *item = new QListWidgetItem(tr("Insert receipt here."));
item->setFlags(item->flags() | Qt::ItemIsEditable);
list_receipts->insertItem(list_receipts->count(), item);
list_receipts->editItem(item);
}
void DialogAdd::remove_receipt()
{
for (auto item :list_receipts->selectedItems())
{
delete item;
}
}
void DialogAdd::accept()
{
if (property("edit").toBool())
{
_parent->remove();
}
Dialogdata data = get_data();
if (data.user.empty())
{
return;
}
database::add_block(data.user, data.blocked, data.reason);
_parent->add_row(QString::fromStdString(data.user),
data.blocked,
QString::fromStdString(data.reason));
for (const string &receipt : data.receipts)
{
database::add_receipt(data.user, receipt);
}
_parent->statusBar()->showMessage(tr("Added %1 to database.")
.arg(QString::fromStdString(data.user)));
delete this;
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QCoreApplication::setApplicationName("Whyblocked");
QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&qtTranslator);
QTranslator appTranslator;
appTranslator.load("whyblocked_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&appTranslator);
MainWindow win;
win.show();
return app.exec();
}

View File

@ -1,304 +0,0 @@
/* This file is part of whyblocked.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <QCoreApplication>
#include <QTranslator>
#include <QLocale>
#include <QLibraryInfo>
#include "version.hpp"
#include "whyblocked.hpp"
#include "interface_text.hpp"
using std::cout;
using std::cerr;
using std::cin;
// Allow cout to output QStrings
std::ostream &operator <<(std::ostream &stream, const QString &str)
{
stream << str.toStdString();
return stream;
}
const string Text::get_answer(const QString &question)
{
string answer;
cout << question << ": ";
std::getline(cin, answer, '\n');
return answer;
}
const bool Text::askblocked()
{
while (true)
{
const string blocked = get_answer(tr("Blocked(b) or silenced(s)"));
if (blocked[0] == tr("b")[0] || blocked[0] == tr("B")[0])
{
return true;
}
else if (blocked[0] == tr("s")[0] || blocked[0] == tr("S")[0])
{
return false;
}
}
}
const void Text::askrecipes(const string &user)
{
while (true)
{
const string receipt_yn = get_answer(tr("Add receipt? [y/n]"));
if (receipt_yn[0] == tr("y")[0] || receipt_yn[0] == tr("Y")[0])
{
const string receipt = get_answer(tr("Receipt"));
if (database::add_receipt(user, receipt))
{
cout << tr("Receipt added.") << '\n';
}
}
else if (receipt_yn[0] == tr("n")[0] || receipt_yn[0] == tr("N")[0])
{
break;
}
else
{
continue;
}
}
}
const void Text::add()
{
const string user = get_answer(tr("User or instance"));
int blocked;
if (askblocked())
{
blocked = 1;
}
else
{
blocked = 0;
}
const string reason = get_answer(tr("Reason"));
if (database::add_block(user, blocked, reason))
{
cout << user << " " << tr("added.") << '\n';
}
askrecipes(user);
}
const void Text::edit()
{
result_details olddata;
const string olduser = get_answer(tr("User or instance"));
if (database::details(olduser, olddata))
{
cout << tr("A blank line keeps the former value.") << '\n';
string newuser = get_answer(tr("Change user or instance to"));
if (newuser.empty())
{
newuser = olduser;
}
int blocked;
if (askblocked())
{
blocked = 1;
}
else
{
blocked = 0;
}
cout << tr("Old reason was:") << " " << std::get<1>(olddata) << '\n';
string newreason = get_answer(tr("Change reason to"));
if (newreason.empty())
{
newreason = std::get<1>(olddata);
}
std::vector<string> newreceipts;
for (const string &oldreceipt : std::get<2>(olddata))
{
cout << tr("Old receipt was:") << " " << oldreceipt << '\n';
string newreceipt = get_answer(tr("Change receipt to"));
if (newreceipt.empty())
{
newreceipt = oldreceipt;
}
newreceipts.push_back(newreceipt);
}
if (database::remove(olduser))
{
database::add_block(newuser, blocked, newreason);
if (!newreceipts.empty())
{
for (const string &newreceipt : newreceipts)
{
database::add_receipt(newuser, newreceipt);
}
}
askrecipes(newuser);
}
else
{
cerr << tr("Could not remove") << " " << olduser << ".\n";
}
}
}
const void Text::remove()
{
const string user = get_answer(tr("User or instance"));
if (database::remove(user))
{
cout << user << " " << tr("removed.") << '\n';
}
}
const void Text::view()
{
result_view result;
if (database::view(result))
{
for (const std::tuple<string, int, string> &line : result)
{
if (std::get<1>(line) == 1)
{
cout << tr(" Blocked:") << " ";
}
else
{
cout << tr("Silenced:") << " ";
}
cout << std::get<0>(line) << " " << tr("because:") << " ";
cout << std::get<2>(line) << '\n';
}
}
}
const void Text::details()
{
const string user = get_answer(tr("User or instance"));
{
result_details result;
if (database::details(user, result))
{
cout << user << " " << tr("is") << " ";
if (std::get<0>(result) == 1)
{
cout << tr("blocked, because:") << " ";
}
else if (std::get<0>(result) == 0)
{
cout << tr("silenced, because:") << " ";
}
cout << std::get<1>(result) << '\n';
if (!std::get<2>(result).empty())
{
cout << tr("Receipts:") << '\n';
for (const string &url : std::get<2>(result))
{
cout << " " << url << '\n';
}
}
}
}
}
const void Text::help()
{
cout << tr(
"Type add, edit, remove, view or details. Or just the first letter.")
<< '\n';
cout << tr(
"Type help or h to show this help. Type quit or q to quit the program.")
<< '\n';
}
Text::Text(QObject *parent) : QObject(parent)
{
bool keeprunning = true;
cout << tr("This is Whyblocked") << " " << global::version << ".\n";
help();
while (keeprunning)
{
string answer = get_answer("");
if (answer[0] == tr("a")[0] || answer[0] == tr("A")[0])
{
add();
}
else if (answer[0] == tr("e")[0] || answer[0] == tr("E")[0])
{
edit();
}
else if (answer[0] == tr("r")[0] || answer[0] == tr("R")[0])
{
remove();
}
else if (answer[0] == tr("v")[0] || answer[0] == tr("V")[0])
{
view();
}
else if (answer[0] == tr("d")[0] || answer[0] == tr("D")[0])
{
details();
}
else if (answer[0] == tr("h")[0] || answer[0] == tr("H")[0])
{
help();
}
else if (answer[0] == tr("q")[0] || answer[0] == tr("Q")[0])
{
keeprunning = false;
}
else
{
cout << tr("Response not understood.") << '\n';
}
}
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName("Whyblocked");
QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&qtTranslator);
QTranslator appTranslator;
appTranslator.load("whyblocked_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&appTranslator);
Text t(&app);
return 0;
}

112
src/qt/dialog_add.cpp Normal file
View File

@ -0,0 +1,112 @@
/* This file is part of whyblocked.
* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <QtCore/qmimedata.h>
#include "dialog_add.hpp"
DialogAdd::DialogAdd(Database &database, QMainWindow *parent)
: QDialog(parent)
, _parent(static_cast<MainWindow*>(parent))
, _database(database)
{
setupUi(this);
}
void DialogAdd::set_data(const Database::data &data)
{
text_user->setText(QString::fromStdString(data.user));
radio_blocked->setChecked(data.blocked);
radio_silcenced->setChecked(!data.blocked);
text_reason->setText(QString::fromStdString(data.reason));
for (const string &receipt : data.receipts)
{
QListWidgetItem *item =
new QListWidgetItem(QString::fromStdString(receipt));
item->setFlags(item->flags() | Qt::ItemIsEditable);
list_receipts->insertItem(list_receipts->count(), item);
}
}
const Database::data DialogAdd::get_data() const
{
std::vector<string> receipts;
for (int row = 0; row <= list_receipts->count() - 1; ++row)
{
receipts.push_back(list_receipts->item(row)->text().toStdString());
}
Database::data data;
data.user = text_user->text().toStdString();
data.blocked = radio_blocked->isChecked();
data.reason = text_reason->text().toStdString();
data.receipts = receipts;
return data;
}
void DialogAdd::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("text/plain"))
{
event->acceptProposedAction();
}
}
void DialogAdd::dropEvent(QDropEvent *event)
{
const QString text = event->mimeData()->text();
QListWidgetItem *item = new QListWidgetItem(text);
item->setFlags(item->flags() | Qt::ItemIsEditable);
list_receipts->insertItem(list_receipts->count(), item);
}
void DialogAdd::add_receipt()
{
QListWidgetItem *item = new QListWidgetItem(tr("Insert receipt here."));
item->setFlags(item->flags() | Qt::ItemIsEditable);
list_receipts->insertItem(list_receipts->count(), item);
list_receipts->editItem(item);
}
void DialogAdd::remove_receipt()
{
for (auto item :list_receipts->selectedItems())
{
delete item;
}
}
void DialogAdd::accept()
{
if (property("edit").toBool())
{
_parent->remove();
}
Database::data data = get_data();
if (!data)
{
return;
}
_database.add_user(data);
_parent->add_row(QString::fromStdString(data.user),
data.blocked,
QString::fromStdString(data.reason));
delete this;
}

View File

@ -1,5 +1,5 @@
/* This file is part of whyblocked. /* This file is part of whyblocked.
* Copyright © 2018 tastytea <tastytea@tastytea.de> * Copyright © 2019 tastytea <tastytea@tastytea.de>
* *
* 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 * it under the terms of the GNU General Public License as published by
@ -14,31 +14,33 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef INTERFACE_TEXT_HPP #ifndef DIALOG_ADD_HPP
#define INTERFACE_TEXT_HPP #define DIALOG_ADD_HPP
#include <string> #include "mainwindow.hpp"
#include <QtCore> #include "ui_whyblocked_add.h"
using std::string; class DialogAdd : public QDialog, private Ui::DialogAdd
class Text : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Text(QObject *parent = nullptr); explicit DialogAdd(Database &database, QMainWindow *parent = nullptr);
void set_data(const Database::data &data);
private: private:
const string get_answer(const QString &question); const Database::data get_data() const;
const bool askblocked(); void dragEnterEvent(QDragEnterEvent *event);
const void askrecipes(const string &user); void dropEvent(QDropEvent *event);
const void add();
const void edit(); MainWindow *_parent;
const void remove(); Database &_database;
const void view();
const void details(); private slots:
const void help(); void add_receipt();
void remove_receipt();
void accept();
}; };
#endif // INTERFACE_TEXT_HPP #endif // DIALOG_ADD_HPP

42
src/qt/main.cpp Normal file
View File

@ -0,0 +1,42 @@
/* This file is part of whyblocked.
* Copyright © 2019, 2020 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "mainwindow.hpp"
#include <QLibraryInfo>
#include <QLocale>
#include <QTranslator>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QCoreApplication::setApplicationName("Whyblocked");
QTranslator qtTranslator;
qtTranslator.load(QLocale(), "qt", "_",
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&qtTranslator);
QTranslator appTranslator;
appTranslator.load(QLocale(), "whyblocked", "_",
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&appTranslator);
MainWindow win;
win.show();
return app.exec();
}

399
src/qt/mainwindow.cpp Normal file
View File

@ -0,0 +1,399 @@
/* This file is part of whyblocked.
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <regex>
#include <array>
#include <locale>
#include <codecvt>
#include <algorithm>
#include <QMessageBox>
#include <QtCore/qmimedata.h>
#include <libconfig.h++>
#include "version.hpp"
#include "mainwindow.hpp"
#include "dialog_add.hpp"
using std::wstring;
MainWindow::MainWindow(QMainWindow *parent)
: QMainWindow(parent)
, _config("whyblocked.cfg")
, _headersize({ 250, 125, 125 })
, _database()
, _dbdata(_database.get_data())
{
std::locale::global(std::locale(""));
setupUi(this);
_model = new QStandardItemModel;
tableview->setModel(_model);
if (_config.read() == 0)
{
libconfig::Setting &root = _config.get_cfg().getRoot();
string key;
key = "size";
if (root.exists(key) && root[key.c_str()].isArray())
{
this->resize(root[key.c_str()][0], root[key.c_str()][1]);
}
key = "toolbar_position";
if (root.exists(key))
{
const string value = root[key.c_str()].c_str();
if (value == "top")
{
this->removeToolBar(toolbar);
this->addToolBar(Qt::TopToolBarArea, toolbar);
}
else if (value == "right")
{
this->removeToolBar(toolbar);
this->addToolBar(Qt::RightToolBarArea, toolbar);
}
else if (value == "bottom")
{
this->removeToolBar(toolbar);
this->addToolBar(Qt::BottomToolBarArea, toolbar);
}
else if (value == "left")
{
this->removeToolBar(toolbar);
this->addToolBar(Qt::LeftToolBarArea, toolbar);
}
}
key = "toolbar_visible";
if (root.exists(key))
{
toolbar->setVisible(root[key.c_str()]);
}
key = "table_headers";
if (root.exists(key) && root[key.c_str()].isArray())
{
const libconfig::Setting &value = root[key.c_str()];
_headersize = { value[0], value[1], value[2] };
}
key = "find_in";
if (root.exists(key) && root[key.c_str()].isGroup())
{
const libconfig::Setting &value = root[key.c_str()];
check_user->setChecked(value["user"]);
check_reason->setChecked(value["reason"]);
}
}
widget_find->hide();
reload();
statusBar()->showMessage(tr("Try dragging an account from your webbrowser "
"into this window."));
}
MainWindow::~MainWindow()
{
libconfig::Setting &root = _config.get_cfg().getRoot();
// We can't add an element that already exists, so we delete it beforehand.
for (const string &key :
{ "size", "toolbar_position", "toolbar_visible", "table_headers",
"find_in" })
{
if (root.exists(key))
{
root.remove(key);
}
}
libconfig::Setting &size = root.add("size", libconfig::Setting::TypeArray);
size.add(libconfig::Setting::TypeInt) = this->width();
size.add(libconfig::Setting::TypeInt) = this->height();
libconfig::Setting &pos = root.add("toolbar_position",
libconfig::Setting::TypeString);
if (toolbar->orientation() == Qt::Orientation::Horizontal)
{
if (toolbar-> geometry().top() < 100)
{
pos = "top";
}
else
{
pos = "bottom";
}
}
else
{
if (toolbar->geometry().left() == 0)
{
pos = "left";
}
else
{
pos = "right";
}
}
root.add("toolbar_visible", libconfig::Setting::TypeBoolean)
= !toolbar->isHidden();
libconfig::Setting &headers = root.add("table_headers",
libconfig::Setting::TypeArray);
headers.add(libconfig::Setting::TypeInt) =
tableview->horizontalHeader()->sectionSize(0);
headers.add(libconfig::Setting::TypeInt) =
tableview->horizontalHeader()->sectionSize(1);
headers.add(libconfig::Setting::TypeInt) = 125;
libconfig::Setting &find_in = root.add("find_in",
libconfig::Setting::TypeGroup);
find_in.add("user", libconfig::Setting::TypeBoolean) =
check_user->isChecked();
find_in.add("reason", libconfig::Setting::TypeBoolean) =
check_reason->isChecked();
_config.write();
}
void MainWindow::add_row(const QString &user, const int &blocked,
const QString &reason)
{
QList<QStandardItem*> items;
items.append(new QStandardItem(user));
if (blocked == 1)
{
items.append(new QStandardItem(QString(tr("blocked"))));
}
else
{
items.append(new QStandardItem(QString(tr("silenced"))));
}
items.append(new QStandardItem(reason));
_model->appendRow(items);
}
void MainWindow::remove()
{
QItemSelectionModel *selection = tableview->selectionModel();
if (selection->hasSelection())
{
// I use this construct here because the number of selected rows
// decrease by 1 each iteration.
for (; selection->selectedRows().count() > 0;)
{
const QModelIndex row = selection->selectedRows().front();
const string user = row.data().toString().toStdString();
_database.remove(user);
_model->removeRow(row.row());
}
label_receipts->clear();
}
else
{
QMessageBox::warning(this, tr("Nothing selected"),
tr("Please select entries to remove."));
}
}
const string MainWindow::urls_to_hyperlinks(const string &text)
{
std::regex re_url("((https?|gopher|ftps?)\\://[^ <]*)");
return std::regex_replace(text, re_url, "<a href=\"$1\">$1</a>");
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("text/plain"))
{
event->acceptProposedAction();
}
}
void MainWindow::dropEvent(QDropEvent *event)
{
string text = event->mimeData()->text().toStdString();
const std::array<const std::regex, 4> fediverse =
{
std::regex("https://([^/]+)/@([^/]+)"), // Mastodon
std::regex("https://([^/]+)/profile/([^/]+)"), // Friendica
std::regex("https://([^/]+)/users/([^/]+)"), // Pleroma
std::regex("https://([^/]+)/([^/]+)") // Gnusocial
};
std::smatch match;
for (const std::regex &re : fediverse)
{
std::regex_match(text, match, re);
const string instance = match[1];
const string user = match[2];
if (!instance.empty() && !user.empty())
{
text = '@' + user + '@' + instance;
break;
}
}
DialogAdd *dialog = new DialogAdd(_database, this);
Database::data data;
data.user = text;
data.blocked = true;
dialog->set_data(data);
dialog->show();
}
void MainWindow::add()
{
DialogAdd *dialog = new DialogAdd(_database, this);
dialog->show();
}
void MainWindow::edit()
{
if (tableview->selectionModel()->selectedRows().count() != 1)
{
QMessageBox::warning(this, tr("Invalid selection"),
tr("Please select only 1 entry to edit."));
return;
}
DialogAdd *dialog = new DialogAdd(_database, this);
dialog->setWindowTitle(tr("Edit entry"));
QModelIndex index = tableview->selectionModel()->selectedRows().first();
const string user = index.sibling(index.row(), 0).data()
.toString().toStdString();
dialog->set_data(_database.get_user(user));
dialog->setProperty("edit", true);
dialog->show();
}
void MainWindow::about()
{
QMessageBox::about(this, tr("About Whyblocked"),
tr("<p><b>Whyblocked</b> %1</p>"
"<p>Reminds you why you blocked someone.</p>"
"<p>Sourcecode: <a href=\"https://schlomp.space/tastytea/whyblocked\">"
"https://schlomp.space/tastytea/whyblocked</a></p>"
"<p><small>Copyright © 2018 <a href=\"mailto:tastytea@tastytea.de\">tastytea</a>.<br>"
"Licence GPLv3: <a href=\"https://www.gnu.org/licenses/gpl-3.0.html\">"
"GNU GPL version 3</a>.<br>"
"This program comes with ABSOLUTELY NO WARRANTY. This is free software, "
"and you are welcome to redistribute it under certain conditions.</small></p>")
.arg(global::version));
}
void MainWindow::show_details(QModelIndex index)
{
const string user = index.sibling(index.row(), 0).data()
.toString().toStdString();
Database::data data = _database.get_user(user);
string text = "";
if (!data.receipts.empty())
{
text += string("<b>") + tr("Receipts:").toStdString() + "</b>";
for (const string &url : data.receipts)
{
text += "<br>" + url;
}
text = urls_to_hyperlinks(text);
}
label_receipts->setText(QString::fromStdString((text)));
}
void MainWindow::populate_tableview(const vector<Database::data> &entries)
{
_model->clear();
_model->setHorizontalHeaderLabels(
{
tr("User/Instance"),
tr("Blocked/Silenced"),
tr("Reason")
});
tableview->horizontalHeader()->resizeSection(0, _headersize[0]);
tableview->horizontalHeader()->resizeSection(1, _headersize[1]);
tableview->horizontalHeader()->resizeSection(2, _headersize[2]);
for (const Database::data &entry : entries)
{
add_row(QString::fromStdString(entry.user),
entry.blocked,
QString::fromStdString(entry.reason));
}
}
void MainWindow::reload()
{
_database.reload();
populate_tableview(_dbdata);
}
void MainWindow::find()
{
if (widget_find->isVisible())
{
widget_find->hide();
}
else
{
widget_find->show();
text_find->setFocus();
}
}
void MainWindow::update_search(const QString &text)
{
const wstring searchfor = text.toLower().toStdWString();
vector<Database::data> filtered_entries;
if (!_dbdata.empty())
{
for (const Database::data &entry : _dbdata)
{
wstring searchstring;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
if (check_user->isChecked())
{
searchstring += convert.from_bytes(entry.user);
}
if (check_reason->isChecked())
{
searchstring += convert.from_bytes(entry.reason);
}
std::transform(searchstring.begin(), searchstring.end(),
searchstring.begin(), ::towlower);
if (searchstring.find(searchfor) != std::string::npos)
{
filtered_entries.push_back(entry);
}
}
}
populate_tableview(filtered_entries);
}
void MainWindow::update_search()
{
update_search(text_find->text());
}

View File

@ -1,5 +1,5 @@
/* This file is part of whyblocked. /* This file is part of whyblocked.
* Copyright © 2018 tastytea <tastytea@tastytea.de> * Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
* *
* 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 * it under the terms of the GNU General Public License as published by
@ -14,25 +14,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef INTERFACE_QT_HPP #ifndef MAINWINDOW_HPP
#define INTERFACE_QT_HPP #define MAINWINDOW_HPP
#include <string> #include <string>
#include <memory>
#include <array>
#include <vector>
#include <QMainWindow> #include <QMainWindow>
#include <QStandardItemModel> #include <QStandardItemModel>
#include <QDialog> #include <QDialog>
#include <QtGui/qevent.h>
#include "../xdgcfg.hpp"
#include "../whyblocked.hpp"
#include "ui_whyblocked.h" #include "ui_whyblocked.h"
#include "ui_whyblocked_add.h"
using std::string; using std::string;
using std::vector;
struct Dialogdata
{
string user;
bool blocked;
string reason;
std::vector<string> receipts;
};
class MainWindow : public QMainWindow, private Ui::MainWindow class MainWindow : public QMainWindow, private Ui::MainWindow
{ {
@ -40,43 +38,35 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
public: public:
explicit MainWindow(QMainWindow *parent = nullptr); explicit MainWindow(QMainWindow *parent = nullptr);
void add_row(const QString &user, const int &blocked, const QString &reason); ~MainWindow();
void add_row(const QString &user, const int &blocked,
const QString &reason);
public slots: public slots:
void remove(); void remove();
private: private:
const string urls_to_hyperlinks(const string &text); const string urls_to_hyperlinks(const string &text);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
QStandardItemModel *_model; QStandardItemModel *_model;
xdgcfg _config;
std::array<int, 3> _headersize;
Database _database;
std::vector<Database::data> &_dbdata;
private slots: private slots:
void add(); void add();
void edit(); void edit();
void about(); void about();
void show_details(QModelIndex index); void show_details(QModelIndex index);
void populate_tableview(); void populate_tableview(const vector<Database::data> &entries);
void reload();
void find();
void update_search(const QString &text);
void update_search();
}; };
class DialogAdd : public QDialog, private Ui::DialogAdd #endif // MAINWINDOW_HPP
{
Q_OBJECT
public:
explicit DialogAdd(QMainWindow *parent = nullptr);
const void set_data(const Dialogdata &data);
private:
const Dialogdata get_data() const;
MainWindow *_parent;
private slots:
void add_receipt();
void remove_receipt();
void accept();
};
#endif // INTERFACE_QT_HPP

View File

@ -10,16 +10,80 @@
<height>600</height> <height>600</height>
</rect> </rect>
</property> </property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Whyblocked</string> <string>Whyblocked</string>
</property> </property>
<property name="windowIcon">
<iconset theme="de.tastytea.Whyblocked">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="locale"> <property name="locale">
<locale language="English" country="UnitedKingdom"/> <locale language="English" country="UnitedKingdom"/>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget_find" native="true">
<layout class="QHBoxLayout" name="hbox_find">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="text_find">
<property name="enabled">
<bool>true</bool>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="check_user">
<property name="toolTip">
<string>Search for Users/Instances</string>
</property>
<property name="text">
<string>User/Instance</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="check_reason">
<property name="toolTip">
<string>Search for Reasons</string>
</property>
<property name="text">
<string>Reason</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QTableView" name="tableview"> <widget class="QTableView" name="tableview">
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="toolTip"> <property name="toolTip">
<string>Click or press enter to view receipts</string> <string>Click or press enter to view receipts</string>
</property> </property>
@ -88,7 +152,10 @@
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolbar"> <widget class="QToolBar" name="toolbar">
<property name="windowTitle"> <property name="windowTitle">
<string/> <string>Toolbar</string>
</property>
<property name="floatable">
<bool>false</bool>
</property> </property>
<attribute name="toolBarArea"> <attribute name="toolBarArea">
<enum>TopToolBarArea</enum> <enum>TopToolBarArea</enum>
@ -100,10 +167,12 @@
<addaction name="action_edit"/> <addaction name="action_edit"/>
<addaction name="action_remove"/> <addaction name="action_remove"/>
<addaction name="action_reload"/> <addaction name="action_reload"/>
<addaction name="action_find"/>
<addaction name="separator"/>
<addaction name="action_about"/> <addaction name="action_about"/>
<addaction name="action_quit"/> <addaction name="action_quit"/>
</widget> </widget>
<widget class="QMenuBar" name="menuBar"> <widget class="QMenuBar" name="menubar">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
@ -112,7 +181,7 @@
<height>21</height> <height>21</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuDatabase"> <widget class="QMenu" name="menu_database">
<property name="title"> <property name="title">
<string>&amp;Database</string> <string>&amp;Database</string>
</property> </property>
@ -120,20 +189,21 @@
<addaction name="action_edit"/> <addaction name="action_edit"/>
<addaction name="action_remove"/> <addaction name="action_remove"/>
<addaction name="action_reload"/> <addaction name="action_reload"/>
<addaction name="action_find"/>
<addaction name="action_quit"/> <addaction name="action_quit"/>
</widget> </widget>
<widget class="QMenu" name="menuHelp"> <widget class="QMenu" name="menu_help">
<property name="title"> <property name="title">
<string>&amp;Help</string> <string>&amp;Help</string>
</property> </property>
<addaction name="action_about"/> <addaction name="action_about"/>
</widget> </widget>
<addaction name="menuDatabase"/> <addaction name="menu_database"/>
<addaction name="menuHelp"/> <addaction name="menu_help"/>
</widget> </widget>
<action name="action_add"> <action name="action_add">
<property name="icon"> <property name="icon">
<iconset theme="add"> <iconset theme="list-add">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
@ -148,7 +218,7 @@
</action> </action>
<action name="action_remove"> <action name="action_remove">
<property name="icon"> <property name="icon">
<iconset theme="remove"> <iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
@ -163,7 +233,7 @@
</action> </action>
<action name="action_about"> <action name="action_about">
<property name="icon"> <property name="icon">
<iconset theme="info"> <iconset theme="help-about">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
@ -175,7 +245,7 @@
</action> </action>
<action name="action_reload"> <action name="action_reload">
<property name="icon"> <property name="icon">
<iconset theme="reload"> <iconset theme="view-refresh">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
@ -190,7 +260,7 @@
</action> </action>
<action name="action_quit"> <action name="action_quit">
<property name="icon"> <property name="icon">
<iconset theme="exit"> <iconset theme="application-exit">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
@ -215,7 +285,25 @@
<string>Edit entry</string> <string>Edit entry</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string>Ctrl+E</string> <string notr="true">Ctrl+E</string>
</property>
</action>
<action name="action_find">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="edit-find">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Find</string>
</property>
<property name="toolTip">
<string>Find entries</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property> </property>
</action> </action>
</widget> </widget>
@ -273,7 +361,7 @@
<sender>action_reload</sender> <sender>action_reload</sender>
<signal>triggered()</signal> <signal>triggered()</signal>
<receiver>MainWindow</receiver> <receiver>MainWindow</receiver>
<slot>populate_tableview()</slot> <slot>reload()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>-1</x> <x>-1</x>
@ -349,6 +437,70 @@
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>action_find</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>find()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>299</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>text_find</sender>
<signal>textChanged(QString)</signal>
<receiver>MainWindow</receiver>
<slot>update_search(QString)</slot>
<hints>
<hint type="sourcelabel">
<x>201</x>
<y>83</y>
</hint>
<hint type="destinationlabel">
<x>299</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>check_user</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>update_search()</slot>
<hints>
<hint type="sourcelabel">
<x>455</x>
<y>82</y>
</hint>
<hint type="destinationlabel">
<x>299</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>check_reason</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>update_search()</slot>
<hints>
<hint type="sourcelabel">
<x>553</x>
<y>82</y>
</hint>
<hint type="destinationlabel">
<x>299</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections> </connections>
<slots> <slots>
<slot>add()</slot> <slot>add()</slot>
@ -357,5 +509,11 @@
<slot>about()</slot> <slot>about()</slot>
<slot>show_details(QModelIndex)</slot> <slot>show_details(QModelIndex)</slot>
<slot>edit()</slot> <slot>edit()</slot>
<slot>find()</slot>
<slot>reload()</slot>
<slot>check_user_changed(int)</slot>
<slot>check_reason_changed(int)</slot>
<slot>update_search(QString)</slot>
<slot>update_search()</slot>
</slots> </slots>
</ui> </ui>

View File

@ -10,6 +10,9 @@
<height>300</height> <height>300</height>
</rect> </rect>
</property> </property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Add entry</string> <string>Add entry</string>
</property> </property>
@ -56,7 +59,7 @@
<string>&amp;Add</string> <string>&amp;Add</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="add"> <iconset theme="list-add">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
</widget> </widget>
@ -154,13 +157,19 @@
<string>Re&amp;move</string> <string>Re&amp;move</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="remove"> <iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="shortcut">
<string>Del</string>
</property>
</widget> </widget>
</item> </item>
<item row="4" column="1" rowspan="3"> <item row="4" column="1" rowspan="3">
<widget class="QListWidget" name="list_receipts"> <widget class="QListWidget" name="list_receipts">
<property name="toolTip">
<string>You can drag URLs in here</string>
</property>
<property name="editTriggers"> <property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set> <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property> </property>

View File

@ -1,5 +1,5 @@
/* This file is part of whyblocked. /* This file is part of whyblocked.
* Copyright © 2018 tastytea <tastytea@tastytea.de> * Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
* *
* 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 * it under the terms of the GNU General Public License as published by
@ -17,32 +17,36 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <tuple> #include <iterator>
#include <experimental/filesystem> #include <experimental/filesystem>
#include <basedir.h> #include <basedir.h>
#include <sqlite/connection.hpp> #include <sqlite/connection.hpp>
#include <sqlite/execute.hpp> #include <sqlite/execute.hpp>
#include <sqlite/query.hpp> #include <sqlite/query.hpp>
#include <boost/shared_ptr.hpp>
#include "whyblocked.hpp" #include "whyblocked.hpp"
using std::cerr; using std::cerr;
namespace fs = std::experimental::filesystem; namespace fs = std::experimental::filesystem;
const string get_filepath() Database::data::operator bool() const
{ {
string filepath; return !user.empty();
}
const string Database::get_filepath() const
{
fs::path filepath;
xdgHandle xdg; xdgHandle xdg;
xdgInitHandle(&xdg); xdgInitHandle(&xdg);
filepath = xdgDataHome(&xdg); filepath = xdgDataHome(&xdg);
xdgWipeHandle(&xdg); xdgWipeHandle(&xdg);
filepath += "/whyblocked"; filepath /= "whyblocked";
if (!fs::exists(filepath)) if (!fs::exists(filepath))
{ {
fs::create_directories(filepath); fs::create_directories(filepath);
} }
filepath += "/database.sqlite"; filepath /= "database.sqlite";
if (!fs::exists(filepath)) if (!fs::exists(filepath))
{ {
sqlite::connection con(filepath); sqlite::connection con(filepath);
@ -54,15 +58,30 @@ const string get_filepath()
return filepath; return filepath;
} }
const bool database::add_block(const string &user, const int blocked, bool Database::add_user(const Database::data &userdata)
const string &reason)
{ {
try try
{ {
int blocked_int = 0;
if (userdata.blocked)
{
blocked_int = 1;
}
sqlite::connection con(get_filepath()); sqlite::connection con(get_filepath());
sqlite::execute ins(con, "INSERT INTO blocks VALUES(?, ?, ?);"); {
ins % user % blocked % reason; sqlite::execute ins(con, "INSERT INTO blocks VALUES(?, ?, ?);");
ins(); ins % userdata.user % blocked_int % userdata.reason;
ins();
}
{
for (const string &receipt : userdata.receipts)
{
sqlite::execute ins(con, "INSERT INTO urls VALUES(?, ?);");
ins % userdata.user % receipt;
ins();
}
}
_data.push_back(userdata);
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -73,25 +92,7 @@ const bool database::add_block(const string &user, const int blocked,
return true; return true;
} }
const bool database::add_receipt(const string &user, const string &receipt) bool Database::remove(const string &user)
{
try
{
sqlite::connection con(get_filepath());
sqlite::execute ins(con, "INSERT INTO urls VALUES(?, ?);");
ins % user % receipt;
ins();
}
catch (const std::exception &e)
{
cerr << "An error occurred: " << e.what() << std::endl;
return false;
}
return true;
}
const bool database::remove(const string &user)
{ {
try try
{ {
@ -102,6 +103,7 @@ const bool database::remove(const string &user)
rm_urls % user; rm_urls % user;
rm_blocks(); rm_blocks();
rm_urls(); rm_urls();
reload();
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -112,67 +114,80 @@ const bool database::remove(const string &user)
return true; return true;
} }
const bool database::view(result_view &result) const vector<Database::data> Database::query(const string &sql_query) const
{ {
try try
{ {
sqlite::connection con(get_filepath()); sqlite::connection con(get_filepath());
sqlite::query q(con, "SELECT * FROM blocks;"); sqlite::query q_blocks(con, sql_query);
boost::shared_ptr<sqlite::result> res = q.get_result(); sqlite::result_type res_blocks = q_blocks.get_result();
while(res->next_row()) std::vector<data> result;
while(res_blocks->next_row())
{ {
const string user = res_blocks->get_string(0);
const int blocked = res_blocks->get_int(1);
const string reason = res_blocks->get_string(2);
bool blocked_bool = false;
if (blocked == 1)
{
blocked_bool = true;
}
sqlite::query q_urls(con,
"SELECT * FROM urls WHERE user = \'" + user + "\';");
sqlite::result_type res_urls = q_urls.get_result();
vector<string> receipts;
while(res_urls->next_row())
{
receipts.push_back(res_urls->get_string(1));
}
result.push_back( result.push_back(
{ {
res->get_string(0), user,
res->get_int(1), blocked_bool,
res->get_string(2) reason,
receipts
}); });
} }
return result;
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
cerr << "An error occurred: " << e.what() << std::endl; cerr << "An error occurred: " << e.what() << std::endl;
return false; return {};
} }
return true;
} }
const bool database::details(const string &user, result_details &result) bool Database::reload()
{ {
try auto buffer = query();
if (buffer.empty())
{ {
sqlite::connection con(get_filepath());
sqlite::query q_blocks(con, "SELECT * FROM blocks WHERE user = \'" + user + "\';");
boost::shared_ptr<sqlite::result> res_blocks = q_blocks.get_result();
sqlite::query q_urls(con, "SELECT * FROM urls WHERE user = \'" + user + "\';");
boost::shared_ptr<sqlite::result> res_urls = q_urls.get_result();
if (!res_blocks->next_row())
{
cerr << user << " is not in the database.\n";
return false;
}
std::vector<string> urls;
while (res_urls->next_row())
{
urls.push_back(res_urls->get_string(1));
}
result =
{
res_blocks->get_int(1),
res_blocks->get_string(2),
urls
};
}
catch (const std::exception &e)
{
cerr << "An error occurred: " << e.what() << std::endl;
return false; return false;
} }
else
return true; {
_data = std::move(buffer);
return true;
}
}
std::vector<Database::data> &Database::get_data()
{
return _data;
}
const Database::data Database::get_user(const string &user) const
{
for (const Database::data &entry : _data)
{
if (entry.user == user)
{
return entry;
}
}
return {};
} }

View File

@ -1,5 +1,5 @@
/* This file is part of whyblocked. /* This file is part of whyblocked.
* Copyright © 2018 tastytea <tastytea@tastytea.de> * Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
* *
* 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 * it under the terms of the GNU General Public License as published by
@ -18,22 +18,37 @@
#define WHYBLOCKED_HPP #define WHYBLOCKED_HPP
#include <vector> #include <vector>
#include <tuple>
#include <string> #include <string>
using std::string; using std::string;
using result_view = std::vector<std::tuple<string, int, string>>; using std::vector;
using result_details = std::tuple<int, string, std::vector<string>>;
const string get_filepath(); class Database
namespace database
{ {
const bool add_block(const string &user, const int blocked, public:
const string &reason); struct data
const bool add_receipt(const string &user, const string &receipt); {
const bool remove(const string &user); string user;
const bool view(result_view &result); bool blocked;
const bool details(const string &user, result_details &result); string reason;
} vector<string> receipts;
explicit operator bool() const;
};
bool add_user(const data &userdata);
bool remove(const string &user);
const vector<data> query(const string &sql_query =
"SELECT * FROM blocks;") const;
bool reload();
std::vector<data> &get_data();
const data get_user(const string &user) const;
private:
std::vector<data> _data;
private:
const string get_filepath() const;
};
#endif // WHYBLOCKED_HPP #endif // WHYBLOCKED_HPP

95
src/xdgcfg.cpp Normal file
View File

@ -0,0 +1,95 @@
/* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the BSD-3-Clause license.
*/
#include <basedir.h>
#include "xdgcfg.hpp"
xdgcfg::xdgcfg(const string &filename, const string &subdir)
: _cfg()
, _verbose(false)
{
xdgHandle xdg;
xdgInitHandle(&xdg);
_filepath = xdgConfigHome(&xdg);
xdgWipeHandle(&xdg);
if (!subdir.empty())
{
_filepath /= subdir;
}
if (!fs::exists(_filepath))
{
fs::create_directories(_filepath);
}
_filepath /= filename;
}
uint8_t xdgcfg::read()
{
try
{
_cfg.readFile(_filepath.c_str());
}
catch (const libconfig::FileIOException &e)
{
if (_verbose)
{
cerr << "I/O error while reading " << _filepath
<< " - " << e.what() << endl;
}
return 1;
}
catch (const libconfig::ParseException &e)
{
if (_verbose)
{
cerr << "Parse error at " << e.getFile() << ":" << e.getLine()
<< " - " << e.getError() << endl;
}
return 2;
}
return 0;
}
bool xdgcfg::write()
{
try
{
_cfg.writeFile(_filepath.c_str());
}
catch (const libconfig::FileIOException &e)
{
if (_verbose)
{
cerr << "I/O error while writing " << _filepath
<< " - " << e.what() << endl;
}
return false;
}
return true;
}
libconfig::Config &xdgcfg::get_cfg()
{
return _cfg;
}
const fs::path xdgcfg::get_filepath() const
{
return _filepath;
}
void xdgcfg::set_verbose(bool verbose)
{
_verbose = verbose;
}
bool xdgcfg::get_verbose() const
{
return _verbose;
}

106
src/xdgcfg.hpp Normal file
View File

@ -0,0 +1,106 @@
/* Copyright © 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the BSD-3-Clause license.
*/
#ifndef XDGCFG_HPP
#define XDGCFG_HPP
#if __cplusplus >= 201703L
#include <filesystem>
#else
#include <experimental/filesystem>
#endif
#include <string>
#include <iostream>
#include <cstdint>
#include <libconfig.h++>
#if __cplusplus >= 201703L
namespace fs = std::filesystem;
#else
namespace fs = std::experimental::filesystem;
#endif
using std::string;
using std::uint8_t;
using std::cerr;
using std::endl;
class xdgcfg
{
public:
/*!
* @brief Checks if subdir is present, creates it if necessary
*
* Example:
* @code
* xdgcfg config("test.cfg", "subdirectory");
* @endcode
*
* @param filename The name of the file, including extension
* @param subdir The subdir (optional)
*/
explicit xdgcfg(const string &filename, const string &subdir = "");
/*!
* @brief Read the file
*
* @return 0 on success, 1 on I/O error, 2 on parse error.
*/
uint8_t read();
/*!
* @brief Write the file
*
* @return `true` on success
*/
bool write();
/*!
* @brief Returns a reference to the config as libconfig::Config
*
* Example:
* @code
* libconfig::Config &cfg = config.get_cfg();
* @endcode
*/
libconfig::Config &get_cfg();
/*!
* @brief Returns the complete filepath
*/
const fs::path get_filepath() const;
/*!
* @brief Sets verbosity
*/
void set_verbose(bool verbose);
/*!
* @brief Returns verbosity
*/
bool get_verbose() const;
private:
/*!
* Holds the contents of the CFG file
*/
libconfig::Config _cfg;
/*!
* Complete filepath
*/
fs::path _filepath;
/*!
* Print out error messages if true
*/
bool _verbose;
};
/*!
* @example example.cpp
*/
#endif // XDGCFG_HPP

View File

@ -0,0 +1,12 @@
set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM 1)
find_package(Qt5LinguistTools REQUIRED)
file(GLOB TS_FILES "${PROJECT_SOURCE_DIR}/translations/*.ts")
file(GLOB TS_SRC_FILES "${PROJECT_SOURCE_DIR}/src/*")
qt5_create_translation(QM_FILES ${TS_SRC_FILES} ${TS_FILES}
OPTIONS -no-obsolete)
# qt5_add_translation(QM_FILES ${TS_FILES})
add_custom_target(translations ALL DEPENDS ${QM_FILES})
add_dependencies(${CMAKE_PROJECT_NAME} translations)
install(FILES ${QM_FILES} DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}/qt5/translations)

View File

@ -4,494 +4,285 @@
<context> <context>
<name>DialogAdd</name> <name>DialogAdd</name>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="14"/> <location filename="../src/qt/whyblocked_add.ui" line="17"/>
<source>Add entry</source> <source>Add entry</source>
<translation>Eintrag hinzufügen</translation> <translation>Eintrag hinzufügen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="37"/> <location filename="../src/qt/whyblocked_add.ui" line="40"/>
<source>Memory aids, proof</source> <source>Memory aids, proof</source>
<translation>Gedächtnisstützen, Beweise</translation> <translation>Gedächtnisstützen, Beweise</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="40"/> <location filename="../src/qt/whyblocked_add.ui" line="43"/>
<source>Rece&amp;ipts</source> <source>Rece&amp;ipts</source>
<translation>Be&amp;lege</translation> <translation>Be&amp;lege</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="53"/> <location filename="../src/qt/whyblocked_add.ui" line="56"/>
<source>Add receipt</source> <source>Add receipt</source>
<translation>Beleg hinzufügen</translation> <translation>Beleg hinzufügen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="56"/> <location filename="../src/qt/whyblocked_add.ui" line="59"/>
<source>&amp;Add</source> <source>&amp;Add</source>
<translation>&amp;Hinzufügen</translation> <translation>&amp;Hinzufügen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="76"/> <location filename="../src/qt/whyblocked_add.ui" line="79"/>
<source>&amp;Blocked</source> <source>&amp;Blocked</source>
<translation>&amp;Blockiert</translation> <translation>&amp;Blockiert</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="95"/> <location filename="../src/qt/whyblocked_add.ui" line="98"/>
<source>&amp;Silenced</source> <source>&amp;Silenced</source>
<translation>&amp;Gedämpft</translation> <translation>&amp;Gedämpft</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="102"/> <location filename="../src/qt/whyblocked_add.ui" line="105"/>
<source>R&amp;eason</source> <source>R&amp;eason</source>
<translation>B&amp;egründung</translation> <translation>B&amp;egründung</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="131"/> <location filename="../src/qt/whyblocked_add.ui" line="134"/>
<source>Blocked/Silenced</source> <source>Blocked/Silenced</source>
<translation>Blockiert/Gedämpft</translation> <translation>Blockiert/Gedämpft</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="141"/> <location filename="../src/qt/whyblocked_add.ui" line="144"/>
<source>&amp;User/Instance</source> <source>&amp;User/Instance</source>
<translation>Ben&amp;utzer/Instanz</translation> <translation>Ben&amp;utzer/Instanz</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="151"/> <location filename="../src/qt/whyblocked_add.ui" line="154"/>
<source>Remove receipt</source> <source>Remove receipt</source>
<translation>Beleg entfernen</translation> <translation>Beleg entfernen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="154"/> <location filename="../src/qt/whyblocked_add.ui" line="157"/>
<source>Re&amp;move</source> <source>Re&amp;move</source>
<translation>Ent&amp;fernen</translation> <translation>Ent&amp;fernen</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="218"/> <location filename="../src/qt/whyblocked_add.ui" line="164"/>
<source>Insert receipt here.</source> <source>Del</source>
<translation>Beleg hier einfügen.</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="253"/> <location filename="../src/qt/whyblocked_add.ui" line="171"/>
<source>Added %1 to database.</source> <source>You can drag URLs in here</source>
<translation>%1 zur Datenbank hinzugefügt.</translation> <translation>Du kannst URLs hier hineinziehen</translation>
</message>
<message>
<location filename="../src/qt/dialog_add.cpp" line="79"/>
<source>Insert receipt here.</source>
<translation>Beleg hier einfügen.</translation>
</message> </message>
</context> </context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../src/whyblocked.ui" line="14"/> <location filename="../src/qt/whyblocked.ui" line="17"/>
<source>Whyblocked</source> <source>Whyblocked</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="24"/> <location filename="../src/qt/whyblocked.ui" line="56"/>
<source>Search for Users/Instances</source>
<translation>Suche nach Benutzern/Instanzen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="69"/>
<source>Search for Reasons</source>
<translation>Suche nach Begründungen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="88"/>
<source>Click or press enter to view receipts</source> <source>Click or press enter to view receipts</source>
<translation>Klicken oder Eingabe drücken, um Belege zu anzuzeigen</translation> <translation>Klicken oder Eingabe drücken, um Belege zu anzuzeigen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="67"/> <location filename="../src/qt/whyblocked.ui" line="131"/>
<source>Memory aids, proof</source> <source>Memory aids, proof</source>
<translation>Gedächtnisstützen, Beweise</translation> <translation>Gedächtnisstützen, Beweise</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="117"/> <location filename="../src/qt/whyblocked.ui" line="155"/>
<source>Toolbar</source>
<translation>Werkzeugleiste</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="186"/>
<source>&amp;Database</source> <source>&amp;Database</source>
<translation>&amp;Datenbank</translation> <translation>&amp;Datenbank</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="127"/> <location filename="../src/qt/whyblocked.ui" line="197"/>
<source>&amp;Help</source> <source>&amp;Help</source>
<translation>&amp;Hilfe</translation> <translation>&amp;Hilfe</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="140"/> <location filename="../src/qt/whyblocked.ui" line="210"/>
<source>&amp;Add</source> <source>&amp;Add</source>
<translation>&amp;Hinzufügen</translation> <translation>&amp;Hinzufügen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="143"/> <location filename="../src/qt/whyblocked.ui" line="213"/>
<source>Add user or instance</source> <source>Add user or instance</source>
<translation>Benutzer oder Instanz hinzufügen</translation> <translation>Benutzer oder Instanz hinzufügen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="146"/> <location filename="../src/qt/whyblocked.ui" line="216"/>
<source>Ctrl+N</source> <source>Ctrl+N</source>
<translation>Strg+N</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="155"/> <location filename="../src/qt/whyblocked.ui" line="225"/>
<source>Re&amp;move</source> <source>Re&amp;move</source>
<translation>Ent&amp;fernen</translation> <translation>Ent&amp;fernen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="158"/> <location filename="../src/qt/whyblocked.ui" line="228"/>
<source>Remove user or instance</source> <source>Remove user or instance</source>
<translation>Benutzer oder Instanz entfernen</translation> <translation>Benutzer oder Instanz entfernen</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="161"/> <location filename="../src/qt/whyblocked.ui" line="231"/>
<source>Del</source> <source>Del</source>
<translation>Entf</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="170"/> <location filename="../src/qt/whyblocked.ui" line="240"/>
<source>&amp;About</source> <source>&amp;About</source>
<translation>&amp;Über</translation> <translation>&amp;Über</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="173"/> <location filename="../src/qt/whyblocked.ui" line="243"/>
<source>About this application</source> <source>About this application</source>
<translation>Über dieses Programm</translation> <translation>Über dieses Programm</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="182"/> <location filename="../src/qt/whyblocked.ui" line="252"/>
<source>&amp;Reload</source> <source>&amp;Reload</source>
<translation>Neu &amp;laden</translation> <translation>Neu &amp;laden</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="185"/> <location filename="../src/qt/whyblocked.ui" line="255"/>
<source>Reload database</source> <source>Reload database</source>
<translation>Datenbank neu laden</translation> <translation>Datenbank neu laden</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="188"/> <location filename="../src/qt/whyblocked.ui" line="258"/>
<source>Ctrl+R</source> <source>Ctrl+R</source>
<translation>Strg+R</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="197"/> <location filename="../src/qt/whyblocked.ui" line="267"/>
<source>&amp;Quit</source> <source>&amp;Quit</source>
<translation>&amp;Beenden</translation> <translation>&amp;Beenden</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="200"/> <location filename="../src/qt/whyblocked.ui" line="270"/>
<source>Quit application</source> <source>Quit application</source>
<translation>Programm beenden</translation> <translation>Programm beenden</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="203"/> <location filename="../src/qt/whyblocked.ui" line="273"/>
<source>Ctrl+Q</source> <source>Ctrl+Q</source>
<translation>Strg+Q</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="212"/> <location filename="../src/qt/whyblocked.ui" line="282"/>
<source>&amp;Edit</source> <source>&amp;Edit</source>
<translation>B&amp;earbeiten</translation> <translation>B&amp;earbeiten</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="215"/> <location filename="../src/qt/whyblocked.ui" line="285"/>
<location filename="../src/interface_qt.cpp" line="92"/> <location filename="../src/qt/mainwindow.cpp" line="279"/>
<source>Edit entry</source> <source>Edit entry</source>
<translation>Eintrag bearbeiten</translation> <translation>Eintrag bearbeiten</translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="218"/> <location filename="../src/qt/whyblocked.ui" line="300"/>
<source>Ctrl+E</source> <source>&amp;Find</source>
<translation>Strg+E</translation> <translation>&amp;Finden</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="40"/> <location filename="../src/qt/whyblocked.ui" line="303"/>
<source>Find entries</source>
<translation>Finde Einträge</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="306"/>
<source>Ctrl+F</source>
<translation></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="59"/>
<location filename="../src/qt/mainwindow.cpp" line="329"/>
<source>User/Instance</source> <source>User/Instance</source>
<translation>Benutzer/Instanz</translation> <translation>Benutzer/Instanz</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="41"/> <location filename="../src/qt/mainwindow.cpp" line="330"/>
<source>Blocked/Silenced</source> <source>Blocked/Silenced</source>
<translation>Blockiert/Gedämpft</translation> <translation>Blockiert/Gedämpft</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="42"/> <location filename="../src/qt/whyblocked.ui" line="72"/>
<location filename="../src/qt/mainwindow.cpp" line="331"/>
<source>Reason</source> <source>Reason</source>
<translation>Begründung</translation> <translation>Begründung</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="57"/> <location filename="../src/qt/mainwindow.cpp" line="109"/>
<source>Database loaded.</source> <source>Try dragging an account from your webbrowser into this window.</source>
<translation>Datenbank geladen.</translation> <translation>Versuche, einen Account von deinem Webbrowser in dieses Fenster zu ziehen.</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="66"/> <location filename="../src/qt/mainwindow.cpp" line="184"/>
<source>blocked</source> <source>blocked</source>
<translation>blockiert</translation> <translation>blockiert</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="70"/> <location filename="../src/qt/mainwindow.cpp" line="188"/>
<source>silenced</source> <source>silenced</source>
<translation>gedämpft</translation> <translation>gedämpft</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="86"/> <location filename="../src/qt/mainwindow.cpp" line="273"/>
<source>Invalid selection</source> <source>Invalid selection</source>
<translation>Ungültige Auswahl</translation> <translation>Ungültige Auswahl</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="87"/> <location filename="../src/qt/mainwindow.cpp" line="274"/>
<source>Please select only 1 entry to edit.</source> <source>Please select only 1 entry to edit.</source>
<translation>Bitte nur 1 Eintrag zum bearbeiten auswählen.</translation> <translation>Bitte nur 1 Eintrag zum bearbeiten auswählen.</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="124"/> <location filename="../src/qt/mainwindow.cpp" line="212"/>
<source>Removed %1 from database.</source> <source>Nothing selected</source>
<translation>%1 aus der Datenbank gelöscht.</translation> <translation>Nichts ausgewählt</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="132"/> <location filename="../src/qt/mainwindow.cpp" line="213"/>
<source>Select data to remove.</source> <source>Please select entries to remove.</source>
<translation>Wähle Daten zum löschen aus.</translation> <translation>Bitte wähle Einträge aus, die gelöscht werden sollen.</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="138"/> <location filename="../src/qt/mainwindow.cpp" line="292"/>
<source>About Whyblocked</source> <source>About Whyblocked</source>
<translation>Über Whyblocked</translation> <translation>Über Whyblocked</translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="139"/> <location filename="../src/qt/mainwindow.cpp" line="293"/>
<source>&lt;p&gt;&lt;b&gt;Whyblocked&lt;/b&gt; %1&lt;/p&gt;&lt;p&gt;Reminds you why you blocked someone.&lt;/p&gt;&lt;p&gt;Sourcecode: &lt;a href=&quot;https://schlomp.space/tastytea/whyblocked&quot;&gt;https://schlomp.space/tastytea/whyblocked&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;small&gt;Copyright © 2018 &lt;a href=&quot;mailto:tastytea@tastytea.de&quot;&gt;tastytea&lt;/a&gt;.&lt;br&gt;Licence GPLv3: &lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;GNU GPL version 3&lt;/a&gt;.&lt;br&gt;This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions.&lt;/small&gt;&lt;/p&gt;</source> <source>&lt;p&gt;&lt;b&gt;Whyblocked&lt;/b&gt; %1&lt;/p&gt;&lt;p&gt;Reminds you why you blocked someone.&lt;/p&gt;&lt;p&gt;Sourcecode: &lt;a href=&quot;https://schlomp.space/tastytea/whyblocked&quot;&gt;https://schlomp.space/tastytea/whyblocked&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;small&gt;Copyright © 2018 &lt;a href=&quot;mailto:tastytea@tastytea.de&quot;&gt;tastytea&lt;/a&gt;.&lt;br&gt;Licence GPLv3: &lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;GNU GPL version 3&lt;/a&gt;.&lt;br&gt;This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions.&lt;/small&gt;&lt;/p&gt;</source>
<translation>&lt;p&gt;&lt;b&gt;Whyblocked&lt;/b&gt; %1&lt;/p&gt;&lt;p&gt;Erinnert dich, warum du jemanden blockiertest.&lt;/p&gt;&lt;p&gt;Quelltext: &lt;a href=&quot;https://schlomp.space/tastytea/whyblocked&quot;&gt;https://schlomp.space/tastytea/whyblocked&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;small&gt;Copyright © 2018 &lt;a href=&quot;mailto:tastytea@tastytea.de&quot;&gt;tastytea&lt;/a&gt;.&lt;br&gt;Lizenz GPLv3: &lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;GNU GPL version 3&lt;/a&gt;.&lt;br&gt;Für dieses Programm besteht KEINERLEI GARANTIE. Dies ist freie Software, die Sie unter bestimmten Bedingungen weitergeben dürfen.&lt;/small&gt;&lt;/p&gt;</translation> <translation>&lt;p&gt;&lt;b&gt;Whyblocked&lt;/b&gt; %1&lt;/p&gt;&lt;p&gt;Erinnert dich, warum du jemanden blockiertest.&lt;/p&gt;&lt;p&gt;Quelltext: &lt;a href=&quot;https://schlomp.space/tastytea/whyblocked&quot;&gt;https://schlomp.space/tastytea/whyblocked&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;small&gt;Copyright © 2018 &lt;a href=&quot;mailto:tastytea@tastytea.de&quot;&gt;tastytea&lt;/a&gt;.&lt;br&gt;Lizenz GPLv3: &lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;GNU GPL version 3&lt;/a&gt;.&lt;br&gt;Für dieses Programm besteht KEINERLEI GARANTIE. Dies ist freie Software, die Sie unter bestimmten Bedingungen weitergeben dürfen.&lt;/small&gt;&lt;/p&gt;</translation>
</message> </message>
</context>
<context>
<name>Text</name>
<message> <message>
<location filename="../src/interface_text.cpp" line="51"/> <location filename="../src/qt/mainwindow.cpp" line="314"/>
<source>Blocked(b) or silenced(s)</source>
<translation>Blockiert(b) oder Gedämpft(g)</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="52"/>
<source>b</source>
<translation>b</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="52"/>
<source>B</source>
<translation>B</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="56"/>
<source>s</source>
<translation>g</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="56"/>
<source>S</source>
<translation>G</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="67"/>
<source>Add receipt? [y/n]</source>
<translation>Beleg hinzufügen? [j/n]</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="68"/>
<source>y</source>
<translation>j</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="68"/>
<source>Y</source>
<translation>J</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="70"/>
<source>Receipt</source>
<translation>Beleg</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="74"/>
<source>Receipt added.</source>
<translation>Beleg hinzugefügt.</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="77"/>
<source>n</source>
<translation>n</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="77"/>
<source>N</source>
<translation>N</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="90"/>
<location filename="../src/interface_text.cpp" line="114"/>
<location filename="../src/interface_text.cpp" line="174"/>
<location filename="../src/interface_text.cpp" line="205"/>
<source>User or instance</source>
<translation>Benutzer oder Instanz</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="101"/>
<source>Reason</source>
<translation>Begründung</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="105"/>
<source>added.</source>
<translation>hinzugefügt.</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="117"/>
<source>A blank line keeps the former value.</source>
<translation>Leere Zeile um den alten Wert zu erhalten.</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="118"/>
<source>Change user or instance to</source>
<translation>Ändere Benutzer oder Instanz zu</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="134"/>
<source>Old reason was:</source>
<translation>Alte Begründung war:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="135"/>
<source>Change reason to</source>
<translation>Ändere Begründung zu</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="144"/>
<source>Old receipt was:</source>
<translation>Alter Beleg war:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="145"/>
<source>Change receipt to</source>
<translation>Ändere beleg zu</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="167"/>
<source>Could not remove</source>
<translation>Konnte nicht entfernen:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="178"/>
<source>removed.</source>
<translation>entfernt.</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="191"/>
<source> Blocked:</source>
<translation>Blockiert:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="195"/>
<source>Silenced:</source>
<translation> Gedämpft:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="197"/>
<source>because:</source>
<translation>weil:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="210"/>
<source>is</source>
<translation>ist</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="213"/>
<source>blocked, because:</source>
<translation>blockiert, weil:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="217"/>
<source>silenced, because:</source>
<translation>gedämpft, weil:</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="223"/>
<source>Receipts:</source> <source>Receipts:</source>
<translation>Belege:</translation> <translation>Belege:</translation>
</message> </message>
<message>
<location filename="../src/interface_text.cpp" line="235"/>
<source>Type add, edit, remove, view or details. Or just the first letter.</source>
<translation>Schreibe zufügen, ändern, entfernen, anschauen oder details. Oder nur den Anfangsbuchstaben.</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="238"/>
<source>Type help or h to show this help. Type quit or q to quit the program.</source>
<translation>Schreibe hilfe oder h, um die Hilfe anzuzeigen. Schreibe beenden oder b um das Programm zu beenden.</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="247"/>
<source>This is Whyblocked</source>
<translation>Dies ist Whyblocked</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="252"/>
<source>a</source>
<translation>z</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="252"/>
<source>A</source>
<translation>Z</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="256"/>
<source>e</source>
<translation>ä</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="256"/>
<source>E</source>
<translation>Ä</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="260"/>
<source>r</source>
<translation>e</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="260"/>
<source>R</source>
<translation>E</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="264"/>
<source>v</source>
<translation>a</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="264"/>
<source>V</source>
<translation>A</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="268"/>
<source>d</source>
<translation>d</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="268"/>
<source>D</source>
<translation>D</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="272"/>
<source>h</source>
<translation>h</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="272"/>
<source>H</source>
<translation>H</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="276"/>
<source>q</source>
<translation>b</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="276"/>
<source>Q</source>
<translation>B</translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="282"/>
<source>Response not understood.</source>
<translation>Antwort nicht verstanden.</translation>
</message>
</context> </context>
</TS> </TS>

View File

@ -4,494 +4,285 @@
<context> <context>
<name>DialogAdd</name> <name>DialogAdd</name>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="14"/> <location filename="../src/qt/whyblocked_add.ui" line="17"/>
<source>Add entry</source> <source>Add entry</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="37"/> <location filename="../src/qt/whyblocked_add.ui" line="40"/>
<source>Memory aids, proof</source> <source>Memory aids, proof</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="40"/> <location filename="../src/qt/whyblocked_add.ui" line="43"/>
<source>Rece&amp;ipts</source> <source>Rece&amp;ipts</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="53"/> <location filename="../src/qt/whyblocked_add.ui" line="56"/>
<source>Add receipt</source> <source>Add receipt</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="56"/> <location filename="../src/qt/whyblocked_add.ui" line="59"/>
<source>&amp;Add</source> <source>&amp;Add</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="76"/> <location filename="../src/qt/whyblocked_add.ui" line="79"/>
<source>&amp;Blocked</source> <source>&amp;Blocked</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="95"/> <location filename="../src/qt/whyblocked_add.ui" line="98"/>
<source>&amp;Silenced</source> <source>&amp;Silenced</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="102"/> <location filename="../src/qt/whyblocked_add.ui" line="105"/>
<source>R&amp;eason</source> <source>R&amp;eason</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="131"/> <location filename="../src/qt/whyblocked_add.ui" line="134"/>
<source>Blocked/Silenced</source> <source>Blocked/Silenced</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="141"/> <location filename="../src/qt/whyblocked_add.ui" line="144"/>
<source>&amp;User/Instance</source> <source>&amp;User/Instance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="151"/> <location filename="../src/qt/whyblocked_add.ui" line="154"/>
<source>Remove receipt</source> <source>Remove receipt</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked_add.ui" line="154"/> <location filename="../src/qt/whyblocked_add.ui" line="157"/>
<source>Re&amp;move</source> <source>Re&amp;move</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="218"/> <location filename="../src/qt/whyblocked_add.ui" line="164"/>
<source>Insert receipt here.</source> <source>Del</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="253"/> <location filename="../src/qt/whyblocked_add.ui" line="171"/>
<source>Added %1 to database.</source> <source>You can drag URLs in here</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/dialog_add.cpp" line="79"/>
<source>Insert receipt here.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../src/whyblocked.ui" line="14"/> <location filename="../src/qt/whyblocked.ui" line="17"/>
<source>Whyblocked</source> <source>Whyblocked</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="24"/> <location filename="../src/qt/whyblocked.ui" line="56"/>
<source>Search for Users/Instances</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="69"/>
<source>Search for Reasons</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="88"/>
<source>Click or press enter to view receipts</source> <source>Click or press enter to view receipts</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="67"/> <location filename="../src/qt/whyblocked.ui" line="131"/>
<source>Memory aids, proof</source> <source>Memory aids, proof</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="117"/> <location filename="../src/qt/whyblocked.ui" line="155"/>
<source>Toolbar</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="186"/>
<source>&amp;Database</source> <source>&amp;Database</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="127"/> <location filename="../src/qt/whyblocked.ui" line="197"/>
<source>&amp;Help</source> <source>&amp;Help</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="140"/> <location filename="../src/qt/whyblocked.ui" line="210"/>
<source>&amp;Add</source> <source>&amp;Add</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="143"/> <location filename="../src/qt/whyblocked.ui" line="213"/>
<source>Add user or instance</source> <source>Add user or instance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="146"/> <location filename="../src/qt/whyblocked.ui" line="216"/>
<source>Ctrl+N</source> <source>Ctrl+N</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="155"/> <location filename="../src/qt/whyblocked.ui" line="225"/>
<source>Re&amp;move</source> <source>Re&amp;move</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="158"/> <location filename="../src/qt/whyblocked.ui" line="228"/>
<source>Remove user or instance</source> <source>Remove user or instance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="161"/> <location filename="../src/qt/whyblocked.ui" line="231"/>
<source>Del</source> <source>Del</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="170"/> <location filename="../src/qt/whyblocked.ui" line="240"/>
<source>&amp;About</source> <source>&amp;About</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="173"/> <location filename="../src/qt/whyblocked.ui" line="243"/>
<source>About this application</source> <source>About this application</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="182"/> <location filename="../src/qt/whyblocked.ui" line="252"/>
<source>&amp;Reload</source> <source>&amp;Reload</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="185"/> <location filename="../src/qt/whyblocked.ui" line="255"/>
<source>Reload database</source> <source>Reload database</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="188"/> <location filename="../src/qt/whyblocked.ui" line="258"/>
<source>Ctrl+R</source> <source>Ctrl+R</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="197"/> <location filename="../src/qt/whyblocked.ui" line="267"/>
<source>&amp;Quit</source> <source>&amp;Quit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="200"/> <location filename="../src/qt/whyblocked.ui" line="270"/>
<source>Quit application</source> <source>Quit application</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="203"/> <location filename="../src/qt/whyblocked.ui" line="273"/>
<source>Ctrl+Q</source> <source>Ctrl+Q</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="212"/> <location filename="../src/qt/whyblocked.ui" line="282"/>
<source>&amp;Edit</source> <source>&amp;Edit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="215"/> <location filename="../src/qt/whyblocked.ui" line="285"/>
<location filename="../src/interface_qt.cpp" line="92"/> <location filename="../src/qt/mainwindow.cpp" line="279"/>
<source>Edit entry</source> <source>Edit entry</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/whyblocked.ui" line="218"/> <location filename="../src/qt/whyblocked.ui" line="300"/>
<source>Ctrl+E</source> <source>&amp;Find</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="40"/> <location filename="../src/qt/whyblocked.ui" line="303"/>
<source>Find entries</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="306"/>
<source>Ctrl+F</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="59"/>
<location filename="../src/qt/mainwindow.cpp" line="329"/>
<source>User/Instance</source> <source>User/Instance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="41"/> <location filename="../src/qt/mainwindow.cpp" line="330"/>
<source>Blocked/Silenced</source> <source>Blocked/Silenced</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="42"/> <location filename="../src/qt/whyblocked.ui" line="72"/>
<location filename="../src/qt/mainwindow.cpp" line="331"/>
<source>Reason</source> <source>Reason</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="57"/> <location filename="../src/qt/mainwindow.cpp" line="109"/>
<source>Database loaded.</source> <source>Try dragging an account from your webbrowser into this window.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="66"/> <location filename="../src/qt/mainwindow.cpp" line="184"/>
<source>blocked</source> <source>blocked</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="70"/> <location filename="../src/qt/mainwindow.cpp" line="188"/>
<source>silenced</source> <source>silenced</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="86"/> <location filename="../src/qt/mainwindow.cpp" line="273"/>
<source>Invalid selection</source> <source>Invalid selection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="87"/> <location filename="../src/qt/mainwindow.cpp" line="274"/>
<source>Please select only 1 entry to edit.</source> <source>Please select only 1 entry to edit.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="124"/> <location filename="../src/qt/mainwindow.cpp" line="212"/>
<source>Removed %1 from database.</source> <source>Nothing selected</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="132"/> <location filename="../src/qt/mainwindow.cpp" line="213"/>
<source>Select data to remove.</source> <source>Please select entries to remove.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="138"/> <location filename="../src/qt/mainwindow.cpp" line="292"/>
<source>About Whyblocked</source> <source>About Whyblocked</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/interface_qt.cpp" line="139"/> <location filename="../src/qt/mainwindow.cpp" line="293"/>
<source>&lt;p&gt;&lt;b&gt;Whyblocked&lt;/b&gt; %1&lt;/p&gt;&lt;p&gt;Reminds you why you blocked someone.&lt;/p&gt;&lt;p&gt;Sourcecode: &lt;a href=&quot;https://schlomp.space/tastytea/whyblocked&quot;&gt;https://schlomp.space/tastytea/whyblocked&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;small&gt;Copyright © 2018 &lt;a href=&quot;mailto:tastytea@tastytea.de&quot;&gt;tastytea&lt;/a&gt;.&lt;br&gt;Licence GPLv3: &lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;GNU GPL version 3&lt;/a&gt;.&lt;br&gt;This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions.&lt;/small&gt;&lt;/p&gt;</source> <source>&lt;p&gt;&lt;b&gt;Whyblocked&lt;/b&gt; %1&lt;/p&gt;&lt;p&gt;Reminds you why you blocked someone.&lt;/p&gt;&lt;p&gt;Sourcecode: &lt;a href=&quot;https://schlomp.space/tastytea/whyblocked&quot;&gt;https://schlomp.space/tastytea/whyblocked&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;small&gt;Copyright © 2018 &lt;a href=&quot;mailto:tastytea@tastytea.de&quot;&gt;tastytea&lt;/a&gt;.&lt;br&gt;Licence GPLv3: &lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;GNU GPL version 3&lt;/a&gt;.&lt;br&gt;This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions.&lt;/small&gt;&lt;/p&gt;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context>
<context>
<name>Text</name>
<message> <message>
<location filename="../src/interface_text.cpp" line="51"/> <location filename="../src/qt/mainwindow.cpp" line="314"/>
<source>Blocked(b) or silenced(s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="52"/>
<source>b</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="52"/>
<source>B</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="56"/>
<source>s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="56"/>
<source>S</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="67"/>
<source>Add receipt? [y/n]</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="68"/>
<source>y</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="68"/>
<source>Y</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="70"/>
<source>Receipt</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="74"/>
<source>Receipt added.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="77"/>
<source>n</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="77"/>
<source>N</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="90"/>
<location filename="../src/interface_text.cpp" line="114"/>
<location filename="../src/interface_text.cpp" line="174"/>
<location filename="../src/interface_text.cpp" line="205"/>
<source>User or instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="101"/>
<source>Reason</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="105"/>
<source>added.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="117"/>
<source>A blank line keeps the former value.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="118"/>
<source>Change user or instance to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="134"/>
<source>Old reason was:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="135"/>
<source>Change reason to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="144"/>
<source>Old receipt was:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="145"/>
<source>Change receipt to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="167"/>
<source>Could not remove</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="178"/>
<source>removed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="191"/>
<source> Blocked:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="195"/>
<source>Silenced:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="197"/>
<source>because:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="210"/>
<source>is</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="213"/>
<source>blocked, because:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="217"/>
<source>silenced, because:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="223"/>
<source>Receipts:</source> <source>Receipts:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../src/interface_text.cpp" line="235"/>
<source>Type add, edit, remove, view or details. Or just the first letter.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="238"/>
<source>Type help or h to show this help. Type quit or q to quit the program.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="247"/>
<source>This is Whyblocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="252"/>
<source>a</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="252"/>
<source>A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="256"/>
<source>e</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="256"/>
<source>E</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="260"/>
<source>r</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="260"/>
<source>R</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="264"/>
<source>v</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="264"/>
<source>V</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="268"/>
<source>d</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="268"/>
<source>D</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="272"/>
<source>h</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="272"/>
<source>H</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="276"/>
<source>q</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="276"/>
<source>Q</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/interface_text.cpp" line="282"/>
<source>Response not understood.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
</TS> </TS>

37
whyblocked.1.adoc Normal file
View File

@ -0,0 +1,37 @@
= whyblocked(1)
:Author: tastytea
:Email: tastytea@tastytea.de
:Date: 2019-04-12
:Revision: 0.0.0
:man source: Whyblocked
:man version: {revision}
:man manual: General Commands Manual
== NAME
whyblocked - reminds you why you blocked someone.
== SYNOPSIS
*whyblocked*
== DESCRIPTION
Whyblocked allows you to store the reason why you blocked someone, along with
"receipts", URLs to the posts that led you to block them.
Apart from the obvious method, you can add entries by dropping the link to a
profile into the main window. In the "Add entry" dialog, you can add receipts by
dropping links or text into the receipts list.
== FILES
- *Configuration file*: `${XDG_CONFIG_HOME}/whyblocked.cfg`
- *Database*: `${XDG_DATA_HOME}/whyblocked/database.sqlite`
`${XDG_CONFIG_HOME}` is usually `~/.config` and `${XDG_DATA_HOME}` is usually
`~/.local/share`
== REPORTING BUGS
Bugtracker: https://schlomp.space/tastytea/whyblocked/issues