Compare commits

..

No commits in common. "master" and "0.6.0" have entirely different histories.

25 changed files with 455 additions and 2972 deletions

View File

@ -1,245 +1,87 @@
kind: pipeline
name: build x86_64
volumes:
- name: debian-package-cache
host:
path: /var/cache/debian-package-cache
trigger:
event:
exclude:
- 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 -rf build && mkdir -p build && cd build
- cmake -DCMAKE_INSTALL_PREFIX=/usr ..
- make VERBOSE=1
- make install DESTDIR=install
volumes:
- name: debian-package-cache
path: /var/cache/apt/archives
- name: gcc9
image: debian:stretch-slim
pull: always
environment:
CXX: g++-9
CXXFLAGS: -pipe -O2
commands:
- rm /etc/apt/apt.conf.d/docker-clean
- rm -f /var/cache/apt/archives/lock
- apt-get update -q
- 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
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list
- rm -f /var/cache/apt/archives/lock
- apt-get install -qy gnupg
- 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 -t xenial g++-9
- 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
- name: clang6
image: debian:stretch-slim
pull: always
environment:
CXX: clang++-6.0
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/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
- name: notify
image: drillster/drone-email
pull: always
settings:
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:
pipeline:
gcc8:
image: gcc:8
pull: true
commands:
- apt-get update -q
- apt-get install -qy cmake libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev
- 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
gcc7:
image: gcc:7
pull: true
commands:
- apt-get update -q
- apt-get install -qy cmake libvsqlitepp-dev libboost-all-dev libxdg-basedir-dev
- 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
gcc6:
image: gcc:6
pull: true
commands:
- echo "deb http://deb.debian.org/debian jessie-backports main" >> /etc/apt/sources.list.d/backports.list
- echo "deb http://deb.debian.org/debian stretch main" >> /etc/apt/sources.list.d/stretch.list
- echo "APT::Default-Release \"jessie\";" >> /etc/apt/apt.conf.d/00default_release
- apt-get update -q
- apt-get install -qy -t stretch libvsqlitepp-dev libboost-all-dev
- apt-get install -qy -t jessie-backports cmake
- apt-get install -qy libxdg-basedir-dev
- 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
prepare_release:
image: gcc:6
pull: true
when:
event: tag
commands:
- cp -v build/whyblocked-${DRONE_TAG}_x86_64.tar.gz .
- cp -v build/whyblocked_${DRONE_TAG}-0_amd64.deb .
- cp -v build/whyblocked-${DRONE_TAG}-0.x86_64.rpm .
gitea_release:
image: plugins/gitea-release
pull: true
when:
event: tag
base_url: https://schlomp.space
api_key:
from_secret: gitea_token
secrets: [ gitea_token ]
title: ${DRONE_TAG}
prerelease: true
files:
- 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.sig
- whyblocked-${DRONE_TAG}-0.x86_64.rpm
- whyblocked-${DRONE_TAG}-0.x86_64.rpm.sig
checksum:
- sha256
- sha512
- name: notify
image: drillster/drone-email
pull: always
settings:
notify:
image: drillster/drone-email
pull: true
host: cryptoparty-celle.de
username:
from_secret: email_username
password:
from_secret: email_password
secrets: [ email_username, email_password ]
from: drone@tzend.de
when:
status: [ changed, failure ]
when:
status: [ changed, failure ]

3
.gitmodules vendored
View File

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

View File

@ -1,39 +1,25 @@
cmake_minimum_required (VERSION 3.2)
cmake_minimum_required (VERSION 3.6)
project (whyblocked
VERSION 0.15.0
VERSION 0.6.0
LANGUAGES CXX
)
include(GNUInstallDirs)
find_package(PkgConfig REQUIRED)
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(Qt5Widgets CONFIG REQUIRED)
pkg_check_modules(LIBCONFIG REQUIRED libconfig++)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -Wpedantic -Wall -Wextra -g -Og -fno-omit-frame-pointer")
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -g -Og")
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR})
include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS})
include_directories(${SQLITE3_INCLUDE_DIRS})
include_directories(${LIBCONFIG_INCLUDE_DIRS})
link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS})
link_directories(${SQLITE3_LIBRARY_DIRS})
link_directories(${LIBCONFIG_LIBRARY_DIRS})
# Write version in header
configure_file (
@ -41,47 +27,62 @@ configure_file (
"${PROJECT_BINARY_DIR}/version.hpp"
)
add_executable(${CMAKE_PROJECT_NAME}
src/qt/main.cpp src/qt/mainwindow.cpp src/qt/dialog_add.cpp
src/whyblocked.cpp src/xdgcfg.cpp)
target_link_libraries(${CMAKE_PROJECT_NAME}
${LIBXDG_BASEDIR_LIBRARIES} vsqlitepp Qt5::Widgets
${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)
file(GLOB sources src/*.cpp)
add_executable(whyblocked ${sources})
target_link_libraries(whyblocked
${LIBXDG_BASEDIR_LIBRARIES} vsqlitepp stdc++fs)
install(TARGETS whyblocked DESTINATION ${CMAKE_INSTALL_BINDIR})
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"
)
# Packages
set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME})
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()
install(TARGETS ${CMAKE_PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES "${PROJECT_BINARY_DIR}/whyblocked-gui"
DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(FILES de.tastytea.Whyblocked.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES de.tastytea.Whyblocked.appdata.xml
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)
install(FILES de.tastytea.Whyblocked.svg
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps)
if(WITH_MAN)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/whyblocked.1
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
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")
set(CPACK_RPM_PACKAGE_REQUIRES "vsqlite++ >= 0.3.13 libxdg-basedir, >= 1.2.0")
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()
set(WITH_TRANSLATIONS "YES" CACHE STRING "WITH_TRANSLATIONS defaults to \"YES\"")
if(WITH_TRANSLATIONS)
add_subdirectory(translations)
endif()
include(packages.CMakeLists.txt)
include(CPack)

124
README.md
View File

@ -1,56 +1,55 @@
**Whyblocked** allows you to store the reason why you blocked someone, along
with “receipts”, URLs to the posts that led you to block them.
**whyblocked** reminds you why you blocked someone. It is developed with
Mastodon in mind, but can be used for other contexts, of course.
It has a Qt-interface and uses an SQLite-database.
![Screenshot](https://doc.schlomp.space/whyblocked/whyblocked_screenshot.png)
It has a text interface and uses a SQLite-database.
## Usage
Run `whyblocked`. You can also start it from the menu of your desktop
environment.
### Example
```PLAIN
$ whyblocked
This is whyblocked 0.4.1.
Type add, remove, view or details. Or just the first letter.
Type quit or q to quit the program.
: add
User or instance: @tastytea@soc.ialis.me
Blocked(b) or silenced(s): b
Reason: Too nice
@tastytea@soc.ialis.me added.
Add receipt? [y/n] y
URL: https://tastytea.de/
Receipt added.
Add receipt? [y/n] n
: view
Blocked: @tastytea@soc.ialis.me because: Too nice
: details
User or instance: @tastytea@soc.ialis.me
@tastytea@soc.ialis.me is blocked, because: Too nice
Receipts:
https://tastytea.de/
: remove
User or instance: @tastytea@soc.ialis.me
@tastytea@soc.ialis.me removed.
: view
: details
User or instance: @tastytea@soc.ialis.me
@tastytea@soc.ialis.me is not in the database.
: quit
```
## Install
### Packages
### Dependencies
Every [release](https://schlomp.space/tastytea/whyblocked/releases) includes
a .deb-package, an .rpm-package and a .tar.gz-package with precompiled binaries
for x86_64(amd64)
([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
[repository](https://schlomp.space/tastytea/overlay).
### From source
#### Dependencies
* C++ compiler (tested: [gcc](https://gcc.gnu.org/) 6/8/9,
[clang](https://llvm.org/) 3/6)
* [cmake](https://cmake.org/) (at least 3.2)
* [vsqlite++](http://vsqlite.virtuosic-bytes.com/) (tested: 0.3)
* C++ compiler (tested: gcc 6/7/8)
* [cmake](https://cmake.org/) (at least 3.6)
* [vsqlite++](http://vsqlite.virtuosic-bytes.com/) (tested: 0.3.13)
* [libxdg-basedir](http://repo.or.cz/w/libxdg-basedir.git) (tested: 1.2)
* [qtcore](https://www.qt.io/) (tested: 5.12/5.5)
* [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
### Compile
Download the current
[release](https://schlomp.space/tastytea/whyblocked/releases).
#### Compile
``` zsh
```SH
mkdir build
cd build
cmake ..
@ -58,48 +57,11 @@ make
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
# Copyright
## Contributing
Contributions are always welcome. You can submit them as pull requests or via
email to `tastytea`@`tastytea.de`.
### Translations
To start a new translation, go to `translations/` and copy `whyblocked_en.ts` to
a file [appropriate](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements)
for the new language. If you want to translate to french for example, that file
name would be `whyblocked_fr.ts`.
Use [Linguist](http://doc.qt.io/qt-5/qtlinguist-index.html) to edit the
`.ts`-files.
## Bugs
Please report them on the
[issue tracker](https://schlomp.space/tastytea/whyblocked/issues) or to
`tastytea`@`tastytea.de`.
## Licence & Copyright
``` plain
```PLAIN
Copyright © 2018 tastytea <tastytea@tastytea.de>.
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,
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.

View File

@ -1,10 +0,0 @@
#!/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

@ -1,27 +0,0 @@
<?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

@ -1,13 +0,0 @@
[Desktop Entry]
Type=Application
Version=1.1
Name=Whyblocked
Comment=Reminds you why you blocked someone
Comment[de]=Erinnert dich, warum du jemanden blockiertest
Icon=de.tastytea.Whyblocked
Exec=whyblocked
Terminal=false
Categories=Utility;
Keywords=blocklist;social-network;
StartupNotify=true
StartupWMClass=Whyblocked

View File

@ -1,96 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -1,57 +0,0 @@
# 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)

181
src/interface_text.cpp Normal file
View File

@ -0,0 +1,181 @@
/* 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 "version.hpp"
#include "whyblocked.hpp"
using std::cout;
using std::cerr;
using std::cin;
const void whyblocked_text::print_help()
{
cout << "Type add, remove, view or details. Or just the first letter.\n";
cout << "Type help or h to show this help. Type quit or q to quit the program.\n";
}
const bool whyblocked_text::start()
{
bool keeprunning = true;
cout << "This is whyblocked " << global::version << ".\n";
print_help();
while (keeprunning)
{
string answer = "";
cout << ": ";
cin >> answer;
switch (answer[0])
{
case 'a':
case 'A':
{
string user, reason;
int blocked = -1;
cout << "User or instance: ";
cin >> user;
while (blocked == -1)
{
cout << "Blocked(b) or silenced(s): ";
cin >> answer;
if (answer[0] == 'b' || answer[0] == 'B')
{
blocked = 1;
}
else if (answer[0] == 's' || answer[0] == 'S')
{
blocked = 0;
}
}
cout << "Reason: ";
cin.ignore();
std::getline(cin, reason, '\n');
if (add_block(user, blocked, reason))
{
cout << user << " added.\n";
}
while (true)
{
cout << "Add receipt? [y/n] ";
cin >> answer;
if (answer[0] == 'y' || answer[0] == 'Y')
{
string url;
cout << "URL: ";
cin >> url;
if (add_url(user, url))
{
cout << "Receipt added.\n";
}
}
else if (answer[0] == 'n' || answer[0] == 'N')
{
break;
}
else
{
continue;
}
}
break;
}
case 'r':
case 'R':
{
string user;
cout << "User or instance: ";
cin >> user;
if (remove(user))
{
cout << user << " removed.\n";
}
break;
}
case 'v':
case 'V':
{
result_view result;
if (view(result))
{
for (const std::tuple<string, int, string> &line : result)
{
if (std::get<1>(line) == 1)
{
cout << " Blocked: ";
}
else
{
cout << "Silenced: ";
}
cout << std::get<0>(line) << " because: ";
cout << std::get<2>(line) << '\n';
}
}
break;
}
case 'd':
case 'D':
{
cout << "User or instance: ";
cin >> answer;
{
result_details result;
if (details(answer, result))
{
cout << answer << " is ";
if (std::get<0>(result) == 1)
{
cout << "blocked, because: ";
}
else if (std::get<0>(result) == 0)
{
cout << "silenced, because: ";
}
cout << std::get<1>(result) << '\n';
cout << "Receipts:\n";
for (const string &url : std::get<2>(result))
{
cout << " " << url << '\n';
}
}
}
break;
}
case 'h':
case 'H':
{
print_help();
break;
}
case 'q':
case 'Q':
{
keeprunning = false;
break;
}
default:
cout << "Response not understood.\n";
}
}
return true;
}

View File

@ -1,112 +0,0 @@
/* 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,46 +0,0 @@
/* 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/>.
*/
#ifndef DIALOG_ADD_HPP
#define DIALOG_ADD_HPP
#include "mainwindow.hpp"
#include "ui_whyblocked_add.h"
class DialogAdd : public QDialog, private Ui::DialogAdd
{
Q_OBJECT
public:
explicit DialogAdd(Database &database, QMainWindow *parent = nullptr);
void set_data(const Database::data &data);
private:
const Database::data get_data() const;
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
MainWindow *_parent;
Database &_database;
private slots:
void add_receipt();
void remove_receipt();
void accept();
};
#endif // DIALOG_ADD_HPP

View File

@ -1,42 +0,0 @@
/* 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();
}

View File

@ -1,399 +0,0 @@
/* 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,72 +0,0 @@
/* 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/>.
*/
#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include <string>
#include <memory>
#include <array>
#include <vector>
#include <QMainWindow>
#include <QStandardItemModel>
#include <QDialog>
#include <QtGui/qevent.h>
#include "../xdgcfg.hpp"
#include "../whyblocked.hpp"
#include "ui_whyblocked.h"
using std::string;
using std::vector;
class MainWindow : public QMainWindow, private Ui::MainWindow
{
Q_OBJECT
public:
explicit MainWindow(QMainWindow *parent = nullptr);
~MainWindow();
void add_row(const QString &user, const int &blocked,
const QString &reason);
public slots:
void remove();
private:
const string urls_to_hyperlinks(const string &text);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
QStandardItemModel *_model;
xdgcfg _config;
std::array<int, 3> _headersize;
Database _database;
std::vector<Database::data> &_dbdata;
private slots:
void add();
void edit();
void about();
void show_details(QModelIndex index);
void populate_tableview(const vector<Database::data> &entries);
void reload();
void find();
void update_search(const QString &text);
void update_search();
};
#endif // MAINWINDOW_HPP

View File

@ -1,519 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>600</height>
</rect>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>Whyblocked</string>
</property>
<property name="windowIcon">
<iconset theme="de.tastytea.Whyblocked">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="locale">
<locale language="English" country="UnitedKingdom"/>
</property>
<widget class="QWidget" name="centralwidget">
<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>
<widget class="QTableView" name="tableview">
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Click or press enter to view receipts</string>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>125</number>
</attribute>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QLabel" name="label_receipts">
<property name="focusPolicy">
<enum>Qt::TabFocus</enum>
</property>
<property name="toolTip">
<string>Memory aids, proof</string>
</property>
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolbar">
<property name="windowTitle">
<string>Toolbar</string>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="action_add"/>
<addaction name="action_edit"/>
<addaction name="action_remove"/>
<addaction name="action_reload"/>
<addaction name="action_find"/>
<addaction name="separator"/>
<addaction name="action_about"/>
<addaction name="action_quit"/>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_database">
<property name="title">
<string>&amp;Database</string>
</property>
<addaction name="action_add"/>
<addaction name="action_edit"/>
<addaction name="action_remove"/>
<addaction name="action_reload"/>
<addaction name="action_find"/>
<addaction name="action_quit"/>
</widget>
<widget class="QMenu" name="menu_help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="action_about"/>
</widget>
<addaction name="menu_database"/>
<addaction name="menu_help"/>
</widget>
<action name="action_add">
<property name="icon">
<iconset theme="list-add">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Add</string>
</property>
<property name="toolTip">
<string>Add user or instance</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="action_remove">
<property name="icon">
<iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Re&amp;move</string>
</property>
<property name="toolTip">
<string>Remove user or instance</string>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</action>
<action name="action_about">
<property name="icon">
<iconset theme="help-about">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;About</string>
</property>
<property name="toolTip">
<string>About this application</string>
</property>
</action>
<action name="action_reload">
<property name="icon">
<iconset theme="view-refresh">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Reload</string>
</property>
<property name="toolTip">
<string>Reload database</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
<action name="action_quit">
<property name="icon">
<iconset theme="application-exit">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Quit</string>
</property>
<property name="toolTip">
<string>Quit application</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="action_edit">
<property name="icon">
<iconset theme="edit-redo">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Edit</string>
</property>
<property name="toolTip">
<string>Edit entry</string>
</property>
<property name="shortcut">
<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>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>action_about</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>about()</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>action_add</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>add()</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>action_quit</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>close()</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>action_reload</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>reload()</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>action_remove</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>remove()</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>tableview</sender>
<signal>activated(QModelIndex)</signal>
<receiver>MainWindow</receiver>
<slot>show_details(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>182</x>
<y>390</y>
</hint>
<hint type="destinationlabel">
<x>203</x>
<y>551</y>
</hint>
</hints>
</connection>
<connection>
<sender>tableview</sender>
<signal>clicked(QModelIndex)</signal>
<receiver>MainWindow</receiver>
<slot>show_details(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>387</x>
<y>408</y>
</hint>
<hint type="destinationlabel">
<x>412</x>
<y>551</y>
</hint>
</hints>
</connection>
<connection>
<sender>action_edit</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>edit()</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>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>
<slots>
<slot>add()</slot>
<slot>remove()</slot>
<slot>populate_tableview()</slot>
<slot>about()</slot>
<slot>show_details(QModelIndex)</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>
</ui>

View File

@ -1,262 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogAdd</class>
<widget class="QDialog" name="DialogAdd">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>Add entry</string>
</property>
<property name="locale">
<locale language="English" country="UnitedKingdom"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="layout_grid" rowstretch="0,0,0,0,0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="4" column="0">
<widget class="QLabel" name="label_receipts">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Memory aids, proof</string>
</property>
<property name="text">
<string>Rece&amp;ipts</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="buddy">
<cstring>list_receipts</cstring>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="button_receipt_add">
<property name="toolTip">
<string>Add receipt</string>
</property>
<property name="text">
<string>&amp;Add</string>
</property>
<property name="icon">
<iconset theme="list-add">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QRadioButton" name="radio_blocked">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Blocked</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="text_user"/>
</item>
<item row="2" column="1">
<widget class="QRadioButton" name="radio_silcenced">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Silenced</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_reason">
<property name="text">
<string>R&amp;eason</string>
</property>
<property name="buddy">
<cstring>text_reason</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="text_reason"/>
</item>
<item row="7" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_blocked">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Blocked/Silenced</string>
</property>
<property name="buddy">
<cstring>radio_blocked</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_user">
<property name="text">
<string>&amp;User/Instance</string>
</property>
<property name="buddy">
<cstring>text_user</cstring>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="button_receipt_remove">
<property name="toolTip">
<string>Remove receipt</string>
</property>
<property name="text">
<string>Re&amp;move</string>
</property>
<property name="icon">
<iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</widget>
</item>
<item row="4" column="1" rowspan="3">
<widget class="QListWidget" name="list_receipts">
<property name="toolTip">
<string>You can drag URLs in here</string>
</property>
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>text_user</tabstop>
<tabstop>radio_blocked</tabstop>
<tabstop>radio_silcenced</tabstop>
<tabstop>text_reason</tabstop>
<tabstop>button_receipt_add</tabstop>
<tabstop>button_receipt_remove</tabstop>
<tabstop>list_receipts</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogAdd</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>324</x>
<y>268</y>
</hint>
<hint type="destinationlabel">
<x>331</x>
<y>226</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogAdd</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>255</x>
<y>262</y>
</hint>
<hint type="destinationlabel">
<x>265</x>
<y>224</y>
</hint>
</hints>
</connection>
<connection>
<sender>button_receipt_add</sender>
<signal>clicked()</signal>
<receiver>DialogAdd</receiver>
<slot>add_receipt()</slot>
<hints>
<hint type="sourcelabel">
<x>41</x>
<y>207</y>
</hint>
<hint type="destinationlabel">
<x>115</x>
<y>156</y>
</hint>
</hints>
</connection>
<connection>
<sender>button_receipt_remove</sender>
<signal>clicked()</signal>
<receiver>DialogAdd</receiver>
<slot>remove_receipt()</slot>
<hints>
<hint type="sourcelabel">
<x>95</x>
<y>245</y>
</hint>
<hint type="destinationlabel">
<x>135</x>
<y>190</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>add_receipt()</slot>
<slot>remove_receipt()</slot>
</slots>
</ui>

View File

@ -1,5 +1,5 @@
/* This file is part of whyblocked.
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
* 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
@ -17,36 +17,32 @@
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <tuple>
#include <experimental/filesystem>
#include <basedir.h>
#include <sqlite/connection.hpp>
#include <sqlite/execute.hpp>
#include <sqlite/query.hpp>
#include <boost/shared_ptr.hpp>
#include "whyblocked.hpp"
using std::cerr;
namespace fs = std::experimental::filesystem;
Database::data::operator bool() const
const string get_filepath()
{
return !user.empty();
}
const string Database::get_filepath() const
{
fs::path filepath;
string filepath;
xdgHandle xdg;
xdgInitHandle(&xdg);
filepath = xdgDataHome(&xdg);
xdgWipeHandle(&xdg);
filepath /= "whyblocked";
filepath += "/whyblocked";
if (!fs::exists(filepath))
{
fs::create_directories(filepath);
fs::create_directory(filepath);
}
filepath /= "database.sqlite";
filepath += "/database.sqlite";
if (!fs::exists(filepath))
{
sqlite::connection con(filepath);
@ -58,30 +54,14 @@ const string Database::get_filepath() const
return filepath;
}
bool Database::add_user(const Database::data &userdata)
const bool add_block(const string &user, const int blocked, const string &reason)
{
try
{
int blocked_int = 0;
if (userdata.blocked)
{
blocked_int = 1;
}
sqlite::connection con(get_filepath());
{
sqlite::execute ins(con, "INSERT INTO blocks VALUES(?, ?, ?);");
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);
sqlite::execute ins(con, "INSERT INTO blocks VALUES(?, ?, ?);");
ins % user % blocked % reason;
ins();
}
catch (const std::exception &e)
{
@ -92,7 +72,25 @@ bool Database::add_user(const Database::data &userdata)
return true;
}
bool Database::remove(const string &user)
const bool add_url(const string &user, const string &url)
{
try
{
sqlite::connection con(get_filepath());
sqlite::execute ins(con, "INSERT INTO urls VALUES(?, ?);");
ins % user % url;
ins();
}
catch (const std::exception &e)
{
cerr << "An error occurred: " << e.what() << std::endl;
return false;
}
return true;
}
const bool remove(const string &user)
{
try
{
@ -103,7 +101,6 @@ bool Database::remove(const string &user)
rm_urls % user;
rm_blocks();
rm_urls();
reload();
}
catch (const std::exception &e)
{
@ -114,80 +111,77 @@ bool Database::remove(const string &user)
return true;
}
const vector<Database::data> Database::query(const string &sql_query) const
const bool view(result_view &result)
{
try
{
sqlite::connection con(get_filepath());
sqlite::query q_blocks(con, sql_query);
sqlite::result_type res_blocks = q_blocks.get_result();
std::vector<data> result;
while(res_blocks->next_row())
sqlite::query q(con, "SELECT * FROM blocks;");
boost::shared_ptr<sqlite::result> res = q.get_result();
while(res->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(
{
user,
blocked_bool,
reason,
receipts
res->get_string(0),
res->get_int(1),
res->get_string(2)
});
}
return result;
}
catch (const std::exception &e)
{
cerr << "An error occurred: " << e.what() << std::endl;
return {};
}
}
bool Database::reload()
{
auto buffer = query();
if (buffer.empty())
{
return false;
}
else
{
_data = std::move(buffer);
return true;
}
return true;
}
std::vector<Database::data> &Database::get_data()
const bool details(const string &user, result_details &result)
{
return _data;
}
const Database::data Database::get_user(const string &user) const
{
for (const Database::data &entry : _data)
try
{
if (entry.user == user)
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())
{
return entry;
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
};
}
return {};
catch (const std::exception &e)
{
cerr << "An error occurred: " << e.what() << std::endl;
return false;
}
return true;
}
int main(int argc, char *argv[])
{
if (!whyblocked_text::start())
{
return 1;
}
return 0;
}

View File

@ -1,5 +1,5 @@
/* This file is part of whyblocked.
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
* 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
@ -18,37 +18,24 @@
#define WHYBLOCKED_HPP
#include <vector>
#include <tuple>
#include <string>
using std::string;
using std::vector;
using result_view = std::vector<std::tuple<string, int, string>>;
using result_details = std::tuple<int, string, std::vector<string>>;
class Database
const string get_filepath();
const bool add_block(const string &user, const int blocked, const string &reason);
const bool add_url(const string &user, const string &url);
const bool remove(const string &user);
const bool view(result_view &result);
const bool details(const string &user, result_details &result);
namespace whyblocked_text
{
public:
struct data
{
string user;
bool blocked;
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;
};
const void print_help();
const bool start();
}
#endif // WHYBLOCKED_HPP

View File

@ -1,95 +0,0 @@
/* 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;
}

View File

@ -1,106 +0,0 @@
/* 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

@ -1,12 +0,0 @@
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

@ -1,288 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>DialogAdd</name>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="17"/>
<source>Add entry</source>
<translation>Eintrag hinzufügen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="40"/>
<source>Memory aids, proof</source>
<translation>Gedächtnisstützen, Beweise</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="43"/>
<source>Rece&amp;ipts</source>
<translation>Be&amp;lege</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="56"/>
<source>Add receipt</source>
<translation>Beleg hinzufügen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="59"/>
<source>&amp;Add</source>
<translation>&amp;Hinzufügen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="79"/>
<source>&amp;Blocked</source>
<translation>&amp;Blockiert</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="98"/>
<source>&amp;Silenced</source>
<translation>&amp;Gedämpft</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="105"/>
<source>R&amp;eason</source>
<translation>B&amp;egründung</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="134"/>
<source>Blocked/Silenced</source>
<translation>Blockiert/Gedämpft</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="144"/>
<source>&amp;User/Instance</source>
<translation>Ben&amp;utzer/Instanz</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="154"/>
<source>Remove receipt</source>
<translation>Beleg entfernen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="157"/>
<source>Re&amp;move</source>
<translation>Ent&amp;fernen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="164"/>
<source>Del</source>
<translation></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="171"/>
<source>You can drag URLs in here</source>
<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>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../src/qt/whyblocked.ui" line="17"/>
<source>Whyblocked</source>
<translation></translation>
</message>
<message>
<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>
<translation>Klicken oder Eingabe drücken, um Belege zu anzuzeigen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="131"/>
<source>Memory aids, proof</source>
<translation>Gedächtnisstützen, Beweise</translation>
</message>
<message>
<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>
<translation>&amp;Datenbank</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="197"/>
<source>&amp;Help</source>
<translation>&amp;Hilfe</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="210"/>
<source>&amp;Add</source>
<translation>&amp;Hinzufügen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="213"/>
<source>Add user or instance</source>
<translation>Benutzer oder Instanz hinzufügen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="216"/>
<source>Ctrl+N</source>
<translation></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="225"/>
<source>Re&amp;move</source>
<translation>Ent&amp;fernen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="228"/>
<source>Remove user or instance</source>
<translation>Benutzer oder Instanz entfernen</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="231"/>
<source>Del</source>
<translation></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="240"/>
<source>&amp;About</source>
<translation>&amp;Über</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="243"/>
<source>About this application</source>
<translation>Über dieses Programm</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="252"/>
<source>&amp;Reload</source>
<translation>Neu &amp;laden</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="255"/>
<source>Reload database</source>
<translation>Datenbank neu laden</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="258"/>
<source>Ctrl+R</source>
<translation></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="267"/>
<source>&amp;Quit</source>
<translation>&amp;Beenden</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="270"/>
<source>Quit application</source>
<translation>Programm beenden</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="273"/>
<source>Ctrl+Q</source>
<translation></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="282"/>
<source>&amp;Edit</source>
<translation>B&amp;earbeiten</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="285"/>
<location filename="../src/qt/mainwindow.cpp" line="279"/>
<source>Edit entry</source>
<translation>Eintrag bearbeiten</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="300"/>
<source>&amp;Find</source>
<translation>&amp;Finden</translation>
</message>
<message>
<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>
<translation>Benutzer/Instanz</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="330"/>
<source>Blocked/Silenced</source>
<translation>Blockiert/Gedämpft</translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="72"/>
<location filename="../src/qt/mainwindow.cpp" line="331"/>
<source>Reason</source>
<translation>Begründung</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="109"/>
<source>Try dragging an account from your webbrowser into this window.</source>
<translation>Versuche, einen Account von deinem Webbrowser in dieses Fenster zu ziehen.</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="184"/>
<source>blocked</source>
<translation>blockiert</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="188"/>
<source>silenced</source>
<translation>gedämpft</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="273"/>
<source>Invalid selection</source>
<translation>Ungültige Auswahl</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="274"/>
<source>Please select only 1 entry to edit.</source>
<translation>Bitte nur 1 Eintrag zum bearbeiten auswählen.</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="212"/>
<source>Nothing selected</source>
<translation>Nichts ausgewählt</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="213"/>
<source>Please select entries to remove.</source>
<translation>Bitte wähle Einträge aus, die gelöscht werden sollen.</translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="292"/>
<source>About Whyblocked</source>
<translation>Über Whyblocked</translation>
</message>
<message>
<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>
<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>
<location filename="../src/qt/mainwindow.cpp" line="314"/>
<source>Receipts:</source>
<translation>Belege:</translation>
</message>
</context>
</TS>

View File

@ -1,288 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>DialogAdd</name>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="17"/>
<source>Add entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="40"/>
<source>Memory aids, proof</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="43"/>
<source>Rece&amp;ipts</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="56"/>
<source>Add receipt</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="59"/>
<source>&amp;Add</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="79"/>
<source>&amp;Blocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="98"/>
<source>&amp;Silenced</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="105"/>
<source>R&amp;eason</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="134"/>
<source>Blocked/Silenced</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="144"/>
<source>&amp;User/Instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="154"/>
<source>Remove receipt</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="157"/>
<source>Re&amp;move</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="164"/>
<source>Del</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked_add.ui" line="171"/>
<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>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../src/qt/whyblocked.ui" line="17"/>
<source>Whyblocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="131"/>
<source>Memory aids, proof</source>
<translation type="unfinished"></translation>
</message>
<message>
<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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="197"/>
<source>&amp;Help</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="210"/>
<source>&amp;Add</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="213"/>
<source>Add user or instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="216"/>
<source>Ctrl+N</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="225"/>
<source>Re&amp;move</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="228"/>
<source>Remove user or instance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="231"/>
<source>Del</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="240"/>
<source>&amp;About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="243"/>
<source>About this application</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="252"/>
<source>&amp;Reload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="255"/>
<source>Reload database</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="258"/>
<source>Ctrl+R</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="267"/>
<source>&amp;Quit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="270"/>
<source>Quit application</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="273"/>
<source>Ctrl+Q</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="282"/>
<source>&amp;Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="285"/>
<location filename="../src/qt/mainwindow.cpp" line="279"/>
<source>Edit entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="300"/>
<source>&amp;Find</source>
<translation type="unfinished"></translation>
</message>
<message>
<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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="330"/>
<source>Blocked/Silenced</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/whyblocked.ui" line="72"/>
<location filename="../src/qt/mainwindow.cpp" line="331"/>
<source>Reason</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="109"/>
<source>Try dragging an account from your webbrowser into this window.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="184"/>
<source>blocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="188"/>
<source>silenced</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="273"/>
<source>Invalid selection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="274"/>
<source>Please select only 1 entry to edit.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="212"/>
<source>Nothing selected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="213"/>
<source>Please select entries to remove.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="292"/>
<source>About Whyblocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/qt/mainwindow.cpp" line="314"/>
<source>Receipts:</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -1,37 +0,0 @@
= 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