Compare commits

...

36 Commits

Author SHA1 Message Date
Niklas befc5e5446
Merge pull request #19 from Gurkengewuerz/dev
continuous-integration/drone/push Build is passing Details
removed old ci links (fixed #18)
2020-06-05 15:51:58 +02:00
Niklas 4f9b25190b
removed old ci links (fixed #18)
continuous-integration/drone/push Build is failing Details
2020-06-05 15:48:45 +02:00
Niklas 11c944c122
Merge pull request #17 from Gurkengewuerz/dev
continuous-integration/drone/push Build is passing Details
use droneci with mxe
2020-06-02 18:32:46 +02:00
Niklas df9a7cc096 ci is so trial and error 2020-06-02 18:29:22 +02:00
Niklas 5f2de7de05 updated .drone.yml
continuous-integration/drone/push Build is failing Details
2020-06-02 17:34:04 +02:00
Niklas 613a51b812 init submodule only once
continuous-integration/drone/push Build is failing Details
2020-06-02 17:31:23 +02:00
Niklas 1121c3b8b1 removed appveyor and use mxe
continuous-integration/drone/push Build is failing Details
2020-06-02 17:26:50 +02:00
Niklas e3645a682e Merge pull request 'switched from circleci to selfhosted droneci' (#1) from dev into master
continuous-integration/drone/push Build is passing Details
2020-06-01 22:15:35 +00:00
Niklas 183abda31e fixed branch
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2020-06-01 22:34:26 +02:00
Niklas 878c297f3f updated ci... such wow...
continuous-integration/drone/push Build is passing Details
2020-06-01 20:45:01 +02:00
Niklas e1a9ae803d
updated ci
continuous-integration/drone/push Build is failing Details
2020-06-01 19:48:19 +02:00
Niklas 9df10cc4c8
switched from circleci to selfhosted droneci
continuous-integration/drone/push Build is failing Details
2020-06-01 19:32:37 +02:00
Niklas 317513d5ab
Merge pull request #16 from Gurkengewuerz/dev
almost broke the repo
2020-06-01 19:18:55 +02:00
Niklas b1e97de1e1 bumped version to v5.0.4 2020-06-01 19:11:48 +02:00
Karol Czeryna 44049914e5 initialize QMediaPlayer only once
Resolves: #8
2020-06-01 19:11:07 +02:00
Niklas e196e57a04 delete unused pointers 2020-02-23 20:55:24 +01:00
Niklas 2ed294ea4c appveyor: add version to artifacts 2020-02-23 18:25:04 +01:00
Niklas 1d3e335f3f bumped version to v5.0.3 2020-02-23 17:48:20 +01:00
Niklas 692fa1eda2 use new circleci app 2020-02-23 17:45:07 +01:00
Niklas ab6769c7f8 circleci: added arch build 2020-02-23 17:24:09 +01:00
Niklas 245af995fb rename arch package with branchname 2020-02-23 16:06:34 +01:00
Niklas d80c6b8bc5 circleci: updated to ubuntu 19.10 2020-02-23 15:50:37 +01:00
Niklas f8f034f641 added feature list 🎉🥳 2020-02-23 15:22:51 +01:00
Niklas 41d1bc41e9 fixed filename and folder in imgur upload 2020-02-23 14:14:38 +01:00
Niklas 2587b2c0f2 fixed memory access violation 2020-02-23 14:08:41 +01:00
Niklas aa77c14a51 Clear Hotkeys on Exit 2020-02-23 13:54:09 +01:00
Niklas d3d3f1e833 removed useless PyQT5 Scripts 2020-02-22 14:22:06 +01:00
Niklas b63b82528f added Google Drive API 2020-02-22 14:20:32 +01:00
Niklas d75f993ef8 added option to disable notification sound 2020-02-16 20:55:00 +01:00
Niklas 6d5356f140 updated readme 2020-02-16 20:50:24 +01:00
Niklas b740fbd0d3 redesigned settings dialoge 2020-02-16 03:42:53 +01:00
Niklas fd76a8b187
Merge pull request #3 from Gurkengewuerz/dev
merge v5.0.1 into master
2020-02-16 02:10:44 +01:00
Niklas 284e54303b bumped version to v5.0.1 2020-02-16 02:02:06 +01:00
Niklas 0f8e8901fb fixed ui freezing (WHY DOES THIS LET THE WHOLE TASKBAR FREEZ??? 2020-02-16 01:48:57 +01:00
Niklas b9155dd401 removed outdated docs 2020-02-15 23:03:37 +01:00
Niklas e94a0d67cb added try-for sound and disable via sound 2020-02-15 20:34:21 +01:00
58 changed files with 1309 additions and 16335 deletions

View File

@ -1,67 +0,0 @@
workflows:
version: 2
build:
jobs:
- build
version: 2
jobs:
build:
docker:
- image: buildpack-deps:bionic
steps:
- run:
name: Install pre deps
command: |
apt-get update -yqq \
&& apt-get install -yqq \
build-essential \
cmake \
gcc \
g++ \
qt5-default \
qt5-qmake \
qtmultimedia5-dev \
libqt5svg5-dev \
libx11-dev \
libavformat-dev \
libavcodec-dev \
libavutil-dev \
libswscale-dev \
libqt5x11extras5-dev \
libxcb-util-dev \
libxcb-cursor-dev \
libxcb1-dev \
- run:
name: QMake Version
command: qmake --version
- checkout
- run: git submodule sync
- run: git submodule update --init
- run:
name: LS
command: ls -lahR ~/project
- run:
name: Create Build Env
command: mkdir build && pwd && ls
- run:
name: Build
command: |
cd build && pwd && ls;
qmake ..;
make -j2;
cd ..;
- run:
name: Create Artifact Path
command: mkdir /kshare
- run:
name: Store Build
command: cp build/src/kshare /kshare/
- run:
name: Build Debian Package
command: |
cd packages/;
./makedeb.sh ci;
cp *.deb /kshare/
- store_artifacts:
path: /kshare/

102
.drone.yml Normal file
View File

@ -0,0 +1,102 @@
kind: pipeline
type: docker
name: build
platform:
os: linux
arch: amd64
steps:
- name: submodules
image: alpine/git
commands:
- git submodule update --init --recursive
- name: build-mxe
image: ubuntu:bionic
volumes:
- name: cache
path: /release
commands:
- rm -rf build/ || true
- apt-get update && apt-get install -yqq wget gnupg2 curl rsync p7zip git
- mkdir build && pwd && ls -lahR .
- cd build
- wget -qO - https://pkg.mxe.cc/repos/apt/client-conf/mxeapt.gpg | apt-key add -
- echo 'deb https://pkg.mxe.cc/repos/apt/ bionic main' >> /etc/apt/sources.list
- apt-get update && apt-get install -yqq mxe-x86-64-w64-mingw32.shared-qtbase mxe-x86-64-w64-mingw32.shared-qtmultimedia mxe-x86-64-w64-mingw32.shared-qttools mxe-x86-64-w64-mingw32.shared-qtwinextras
- apt-get install -yqq mxe-x86-64-w64-mingw32.shared-ffmpeg
- export PATH=/usr/lib/mxe/usr/x86_64-w64-mingw32.shared/qt5/bin:$PATH
- export PATH=/usr/lib/mxe/usr/bin:$PATH
- cp /usr/lib/mxe/usr/x86_64-w64-mingw32.shared/include/lmcons.h /usr/lib/mxe/usr/x86_64-w64-mingw32.shared/include/Lmcons.h
- qmake --version
- qmake CONFIG+=nopkg ../KShare.pro
- make -j2
- mkdir dist
- cp src/release/kshare.exe dist/KShare.exe
- /usr/lib/mxe/tools/copydlldeps.sh --infile dist/KShare.exe --destdir dist/ --recursivesrcdir /usr/lib/mxe/usr/x86_64-w64-mingw32.shared/ --srcdir ../src/ --copy --enforcedir /usr/lib/mxe/usr/x86_64-w64-mingw32.shared/qt5/plugins/platforms/ --objdump /usr/lib/mxe/usr/bin/x86_64-w64-mingw32.shared-objdump
- mkdir dist/mediaservice; cp /usr/lib/mxe/usr/x86_64-w64-mingw32.shared/qt5/plugins/mediaservice/dsengine.dll dist/mediaservice
- cd dist/; cp KShare.exe "/release/KShare_v${DRONE_COMMIT_SHA:0:9}.exe"; zip -r "/release/win_kshare_v${DRONE_COMMIT_SHA:0:9}_portable.zip" *
- ls -lahR /release/
- name: build-ubuntu
image: buildpack-deps:19.10
volumes:
- name: cache
path: /release
commands:
- rm -rf build/ || true
- apt-get update -yqq && apt-get install -yqq build-essential cmake \gcc g++ qt5-default qt5-qmake qtmultimedia5-dev libqt5svg5-dev libx11-dev libavformat-dev libavcodec-dev libavutil-dev libswscale-dev libqt5x11extras5-dev libxcb-util-dev libxcb-cursor-dev libxcb1-dev
- qmake --version
- mkdir build && pwd && ls -lahR .
- cd build && pwd && ls; qmake ..; make -j2; cd ..
- mkdir /release || true
- cp build/src/kshare "/release/kshare_v${DRONE_COMMIT_SHA:0:9}"
- cd packages/; ./makedeb.sh ci; cp *.deb /release/; cd ..
- name: build-arch
image: archlinux/base:latest
volumes:
- name: cache
path: /release
commands:
- rm -rf build/ || true
- pacman -Sy && pacman -S --noconfirm base-devel git sudo wget
- "echo 'Set disable_coredump false' >> /etc/sudo.conf"
- "mkdir /home/build && useradd --home /home/build --shell=/bin/false build && usermod -L build && chown build:build /home/build && echo 'build ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers && echo 'root ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers"
- cd /home/build && sudo -u build wget https://raw.githubusercontent.com/Gurkengewuerz/KShare/${DRONE_BRANCH}/packages/arch/${DRONE_BRANCH}-KShare/PKGBUILD
- cd /home/build && pwd && ls -lah
- cd /home/build && sudo -u build makepkg --syncdeps --noconfirm
- mkdir /release || true
- cp /home/build/*.pkg.tar.xz /release/
- name: artifacts
image: alpine:latest
volumes:
- name: cache
path: /release
commands:
- cat /etc/issue
- apk add --no-cache openssh-client ca-certificates sshpass
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- export REMOTE_PATH=/data/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}/${DRONE_BRANCH}/$(date +'%Y%m%d-%H%M%S')-${DRONE_COMMIT_SHA:0:9}/
- export SSHPASS=$${REMOTE_PASSWORD}
- sshpass -e ssh $${REMOTE_USERNAME}@$${REMOTE_HOST} "mkdir -p $REMOTE_PATH"
- "sshpass -e scp -r /release/* $${REMOTE_USERNAME}@$${REMOTE_HOST}:$REMOTE_PATH"
environment:
REMOTE_USERNAME:
from_secret: remote_username
REMOTE_PASSWORD:
from_secret: remote_password
REMOTE_HOST:
from_secret: remote_host
when:
event:
- push
- tag
volumes:
- name: cache
temp: {}

View File

@ -1,32 +0,0 @@
environment:
QTDIR: C:\Qt\5.9\mingw53_32
platform: x86
build_script:
- dir
- mkdir build
- cd build
- set PATH=%PATH%;%QTDIR%\bin;C:\Qt\Tools\mingw530_32\bin;C:\MinGW\msys\1.0\bin
- git submodule update --init --recursive
- curl -kLO https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-3.3.2-win64-dev.zip
- 7z x ffmpeg-3.3.2-win64-dev.zip
- set FFMPEG_DEV_PATH=%CD%\ffmpeg-3.3.2-win64-dev
- curl -kLO https://ffmpeg.zeranoe.com/builds/win64/shared/ffmpeg-3.3.2-win64-shared.zip
- 7z x ffmpeg-3.3.2-win64-shared.zip
- set FFMPEG_SHARED_PATH=%cd%\ffmpeg-3.3.2-win64-shared
- curl -v -L --http1.1 --tlsv1.2 "https://downloads.sourceforge.net/project/qtav/depends/QtAV-depends-windows-x86+x64.7z" -o av.7z
- 7z x av.7z > NUL
- xcopy ffmpeg-3.3.2-win64-shared\* %QTDIR% /e /i /Y
- xcopy ffmpeg-3.3.2-win64-dev\* %QTDIR% /e /i /Y
- xcopy QtAV-depends-windows-x86+x64\* %QTDIR% /e /i /Y
- qmake CONFIG+=nopkg ../KShare.pro
- mingw32-make.exe -j%NUMBER_OF_PROCESSORS%
- copy src\release\kshare.exe ..\KShare.exe
- cd ..
- bash AppVeyor\make_installer.sh
artifacts:
- path: KShare.exe
name: Shared link
- path: installer.exe
name: Installer
- path: portable.zip
name: Portable version

View File

@ -2,17 +2,31 @@
A [ShareX](https://getsharex.com/) inspired cross platform utility written with Qt.
Originally written by [ArsenArsen](https://github.com/ArsenArsen) and here enhanced with [these](https://github.com/Gurkengewuerz/KShare/projects/1) features.
| | Linux | Windows |
|--------|-------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| master | [![CircleCI](https://circleci.com/gh/Gurkengewuerz/KShare/tree/master.svg?style=svg)](https://circleci.com/gh/Gurkengewuerz/KShare/tree/master) | [![Build status](https://ci.appveyor.com/api/projects/status/ujxmg1dk7f5p8ijh/branch/master?svg=true)](https://ci.appveyor.com/project/Gurkengewuerz/kshare/branch/master) |
| dev | [![CircleCI](https://circleci.com/gh/Gurkengewuerz/KShare/tree/dev.svg?style=svg)](https://circleci.com/gh/Gurkengewuerz/KShare/tree/dev) | [![Build status](https://ci.appveyor.com/api/projects/status/ujxmg1dk7f5p8ijh/branch/dev?svg=true)](https://ci.appveyor.com/project/Gurkengewuerz/kshare/branch/dev) |
## Buildstatus (Arch, Ubuntu/Debian and Windows (MXE))
**master**|**dev**
:-----:|:-----:
[![Build Status](https://giteaci.mc8051.de/api/badges/Gurkengewuerz/KShare/status.svg?ref=refs/heads/master)](https://giteaci.mc8051.de/Gurkengewuerz/KShare)| [![Build Status](https://giteaci.mc8051.de/api/badges/Gurkengewuerz/KShare/status.svg?ref=refs/heads/dev)](https://giteaci.mc8051.de/Gurkengewuerz/KShare)
[Artifacts](https://artifacts.mc8051.de/Gurkengewuerz/KShare)
## Screenshot
Made with KShare itself, of course :)
![](https://i.imgur.com/oJrCNkq.png)
## 🎉 Features
* 💻 open source
* 🪶 lightweight
* 🖧 cross-platform
* 🔍 magnifying lense for image capture
* ⌨️ customizable keyboard shortcuts
* ✒️ image annotation (_rectangle_, _ellipse_, _freehand_, _line_, _arrow_, _text_)
* 📂 upload screenshots, files, clipboard or text
* 🤏 color picker
* 📤 multiple destinations implemented (_imgur_, _gdrive_, _clipboard_)
* 🔧 custom uploader (_works perfectly with ![**php_filehost**](https://github.com/Gurkengewuerz/php_filehost)_)
* 🖌️ themes (_dark_, ![_breeze dark_, _breeze light_](https://github.com/Alexhuszagh/BreezeStyleSheets), ![_qdarkstyle_](https://github.com/ColinDuquesnoy/QDarkStyleSheet))
## Usage
See the [wiki](https://github.com/ArsenArsen/KShare/wiki).
Please note that KShare is not compatiable with Wayland due to some permission issues. Please use X.Org instead.
## Dependencies
@ -36,18 +50,13 @@ Additionally, on Linux, you require:
Despite the name implying so, this project does not depend on the KDE API at all.
## Install
|Distro|Link|
|:----:|:--:|
|Arch Linux (development)|[kshare-git](https://aur.archlinux.org/packages/kshare-git/)|
|Ubuntu/Debian (development)|[.deb](https://nativeci.arsenarsen.com/job/KShare%20\(dev\)/main=linux/lastSuccessfulBuild/artifact/packages/simpleName.deb)|
|Arch Linux |[kshare](https://aur.archlinux.org/packages/kshare/)|
|Ubuntu/Debian |[.deb](https://nativeci.arsenarsen.com/job/KShare%20\(master\)/main=linux/lastSuccessfulBuild/artifact/packages/simpleName.deb)|
Download the development versions for Arch Linux, Ubuntu/Debian and Windows [here](https://artifacts.mc8051.de/Gurkengewuerz/KShare/dev/). The stable/master branch is available [here](https://artifacts.mc8051.de/Gurkengewuerz/KShare/master/).
For other UNIX-like platforms, and MSYS2 (for Windows):
You have to obtain the dependencies though.
```bash
git clone --recursive https://github.com/ArsenArsen/KShare.git
git clone --recursive https://github.com/Gurkengewuerz/KShare.git
cd KShare
qmake # Might be qmake-qt5 on your system
make
@ -55,8 +64,6 @@ make
On systems with FFMpeg pre-3.1 you need to apply `OlderSystemFix.patch` to `src/recording/encoders/encoder.cpp`.
On systems with Qt pre-5.7 you need to install the Qt version from their website.
You can attempt to `curl https://raw.githubusercontent.com/ArsenArsen/KShare/master/install.sh | bash`
You can find more details [here](https://blog.arsenarsen.com/posts/compiling-kshare-on-linux-mac-os-x-and-windows-final-revision)
You can attempt to `curl https://raw.githubusercontent.com/Gurkengewuerz/KShare/master/install.sh | bash`
###### Started on 19th of April 2017 by [ArsenArsen](https://github.com/ArsenArsen) to bring some attention and improvement to Linux screenshotting.

View File

@ -1 +0,0 @@
kshare.arsenarsen.com

View File

@ -1,3 +0,0 @@
source 'https://rubygems.org'
gem "github-pages", group: :jekyll_plugins

View File

@ -1,216 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (4.2.8)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
colorator (1.1.0)
ethon (0.10.1)
ffi (>= 1.3.0)
execjs (2.7.0)
faraday (0.13.0)
multipart-post (>= 1.2, < 3)
ffi (1.9.18)
forwardable-extended (2.6.0)
gemoji (3.0.0)
github-pages (155)
activesupport (= 4.2.8)
github-pages-health-check (= 1.3.5)
jekyll (= 3.5.2)
jekyll-avatar (= 0.4.2)
jekyll-coffeescript (= 1.0.1)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.9.2)
jekyll-gist (= 1.4.1)
jekyll-github-metadata (= 2.8.0)
jekyll-mentions (= 1.2.0)
jekyll-optional-front-matter (= 0.2.0)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.1.0)
jekyll-redirect-from (= 0.12.1)
jekyll-relative-links (= 0.4.1)
jekyll-sass-converter (= 1.5.0)
jekyll-seo-tag (= 2.2.3)
jekyll-sitemap (= 1.0.0)
jekyll-swiss (= 0.4.0)
jekyll-theme-architect (= 0.1.0)
jekyll-theme-cayman (= 0.1.0)
jekyll-theme-dinky (= 0.1.0)
jekyll-theme-hacker (= 0.1.0)
jekyll-theme-leap-day (= 0.1.0)
jekyll-theme-merlot (= 0.1.0)
jekyll-theme-midnight (= 0.1.0)
jekyll-theme-minimal (= 0.1.0)
jekyll-theme-modernist (= 0.1.0)
jekyll-theme-primer (= 0.5.0)
jekyll-theme-slate (= 0.1.0)
jekyll-theme-tactile (= 0.1.0)
jekyll-theme-time-machine (= 0.1.0)
jekyll-titles-from-headings (= 0.4.0)
jemoji (= 0.8.0)
kramdown (= 1.13.2)
liquid (= 4.0.0)
listen (= 3.0.6)
mercenary (~> 0.3)
minima (= 2.1.1)
rouge (= 1.11.1)
terminal-table (~> 1.4)
github-pages-health-check (1.3.5)
addressable (~> 2.3)
net-dns (~> 0.8)
octokit (~> 4.0)
public_suffix (~> 2.0)
typhoeus (~> 0.7)
html-pipeline (2.7.0)
activesupport (>= 2)
nokogiri (>= 1.4)
i18n (0.8.6)
jekyll (3.5.2)
addressable (~> 2.4)
colorator (~> 1.0)
jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 1.1)
kramdown (~> 1.3)
liquid (~> 4.0)
mercenary (~> 0.3.3)
pathutil (~> 0.9)
rouge (~> 1.7)
safe_yaml (~> 1.0)
jekyll-avatar (0.4.2)
jekyll (~> 3.0)
jekyll-coffeescript (1.0.1)
coffee-script (~> 2.2)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
jekyll-feed (0.9.2)
jekyll (~> 3.3)
jekyll-gist (1.4.1)
octokit (~> 4.2)
jekyll-github-metadata (2.8.0)
jekyll (~> 3.1)
octokit (~> 4.0, != 4.4.0)
jekyll-mentions (1.2.0)
activesupport (~> 4.0)
html-pipeline (~> 2.3)
jekyll (~> 3.0)
jekyll-optional-front-matter (0.2.0)
jekyll (~> 3.0)
jekyll-paginate (1.1.0)
jekyll-readme-index (0.1.0)
jekyll (~> 3.0)
jekyll-redirect-from (0.12.1)
jekyll (~> 3.3)
jekyll-relative-links (0.4.1)
jekyll (~> 3.3)
jekyll-sass-converter (1.5.0)
sass (~> 3.4)
jekyll-seo-tag (2.2.3)
jekyll (~> 3.3)
jekyll-sitemap (1.0.0)
jekyll (~> 3.3)
jekyll-swiss (0.4.0)
jekyll-theme-architect (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-cayman (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-dinky (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-merlot (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-midnight (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-minimal (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-modernist (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-primer (0.5.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.2)
jekyll-theme-slate (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-tactile (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-time-machine (0.1.0)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.4.0)
jekyll (~> 3.3)
jekyll-watch (1.5.0)
listen (~> 3.0, < 3.1)
jemoji (0.8.0)
activesupport (~> 4.0)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0)
kramdown (1.13.2)
liquid (4.0.0)
listen (3.0.6)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9.7)
mercenary (0.3.6)
mini_portile2 (2.2.0)
minima (2.1.1)
jekyll (~> 3.3)
minitest (5.10.3)
multipart-post (2.0.0)
net-dns (0.8.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
octokit (4.7.0)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.14.0)
forwardable-extended (~> 2.6)
public_suffix (2.0.5)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
rouge (1.11.1)
safe_yaml (1.0.4)
sass (3.5.1)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
typhoeus (0.8.0)
ethon (>= 0.8.0)
tzinfo (1.2.3)
thread_safe (~> 0.1)
unicode-display_width (1.3.0)
PLATFORMS
ruby
DEPENDENCIES
github-pages
BUNDLED WITH
1.15.3

View File

@ -1,2 +0,0 @@
theme: jekyll-theme-minimal
categories: [wiki]

View File

@ -1,66 +0,0 @@
<!doctype html>
<html lang="{{ site.lang | default: "en-US" }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
{% seo %}
<link rel="stylesheet" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
<meta name="viewport" content="width=device-width">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1>{{ site.title | default: site.github.repository_name }}</h1>
<p>{{ site.description | default: site.github.project_tagline }}</p>
<p><a href="/wiki">Click here to visit the wiki</a></p>
{% if site.github.is_project_page %}
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub <small>{{ github_name }}</small></a></p>
{% endif %}
{% if site.github.is_user_page %}
<p class="view"><a href="{{ site.github.owner_url }}">View My GitHub Profile</a></p>
{% endif %}
{% if site.show_downloads %}
<ul>
<li><a href="{{ site.github.zip_url }}">Download <strong>ZIP File</strong></a></li>
<li><a href="{{ site.github.tar_url }}">Download <strong>TAR Ball</strong></a></li>
<li><a href="{{ site.github.repository_url }}">View On <strong>GitHub</strong></a></li>
</ul>
{% endif %}
</header>
<section>
{{ content }}
</section>
<footer>
<p>Copyright (c) ArsenArsen 2017</p>
{% if site.github.is_project_page %}
<p>This project is maintained by <a href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a></p>
{% endif %}
<p><small>Hosted on GitHub Pages &mdash; Theme by <a href="https://github.com/orderedlist">orderedlist</a></small></p>
</footer>
</div>
<script src="{{ '/assets/js/scale.fix.js' | relative_url }}"></script>
{% if site.google_analytics %}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '{{ site.google_analytics }}', 'auto');
ga('send', 'pageview');
</script>
{% endif %}
</body>
</html>

View File

@ -1,75 +0,0 @@
<!doctype html>
<html lang="{{ site.lang | default: "en-US" }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
{% seo %}
<link rel="stylesheet" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
<meta name="viewport" content="width=device-width">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1>{{ site.title | default: site.github.repository_name }}</h1>
<p>{{ site.description | default: site.github.project_tagline }}</p>
<p><a href="/">Click here to go back to the homepage</a></p>
{% for page in site.pages %}
{% if page.categories contains 'wiki' %}
<a href="{{ page.url }}">{{ page.title }}</a><br />
{% endif %}
{% endfor %}
<br />
<br />
{% if site.github.is_project_page %}
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub <small>{{ github_name }}</small></a></p>
{% endif %}
{% if site.github.is_user_page %}
<p class="view"><a href="{{ site.github.owner_url }}">View My GitHub Profile</a></p>
{% endif %}
{% if site.show_downloads %}
<ul>
<li><a href="{{ site.github.zip_url }}">Download <strong>ZIP File</strong></a></li>
<li><a href="{{ site.github.tar_url }}">Download <strong>TAR Ball</strong></a></li>
<li><a href="{{ site.github.repository_url }}">View On <strong>GitHub</strong></a></li>
</ul>
{% endif %}
</header>
<section>
{{ content }}
</section>
<footer>
<p>Copyright (c) ArsenArsen 2017</p>
{% if site.github.is_project_page %}
<p>This project is maintained by <a href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a></p>
{% endif %}
<p><small>Hosted on GitHub Pages &mdash; Theme by <a href="https://github.com/orderedlist">orderedlist</a></small></p>
</footer>
</div>
<script src="{{ '/assets/js/scale.fix.js' | relative_url }}"></script>
{% if site.google_analytics %}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '{{ site.google_analytics }}', 'auto');
ga('send', 'pageview');
</script>
{% endif %}
</body>
</html>

View File

@ -1,13 +0,0 @@
---
---
@import "{{ site.theme }}";
/* stupid css killed the cat */
header ul {
background: none;
border-radius: 0px;
border: 0px solid #e0e0e0;
}

View File

@ -1,54 +0,0 @@
---
layout: layout
---
# **KShare**
## The free open source and cross platform screen sharing software
KShare is a screenshotting utility built using Qt and written in C++.
It has many features, including:
* Area capture,
* Fullscreen capture,
* Active window capture,
* Magnifier, to make those aligments,
* Drawing on screenshots (blur, shapes, text, ...),
* Recording,
* Highly customizable video codecs,
* Automatic upload/clipboard copying,
* Hotkeys,
* Color picker, and last but not least,
* Custom upload destinations,
* Upload from clipboard,
* Upload History,
* Crossplatform,
* Windows 10 Darkmode
## Enough talking, show us how it looks
The main window is rather simple, with only a log, and a button in it:
![image1](https://i.imgur.com/Tnrj90b.png)
The settings have quite a bit more going on:
![image2](https://i.imgur.com/GFN2jCU.png)
The area selection editor is simple:
![image3](https://i.imgur.com/Cbi8YsL.png)
And the color picker is the simplest thing ever:
![image4](http://i.imgur.com/VIeGbdQ.jpg)
The way you select the area to record is by resizing this simple widget:
![image5](http://i.imgur.com/0iXFHnm.png)
And when you start recording there is a simple preview shown:
![image6](http://i.imgur.com/6fu33TR.png)
## Download
Currently, the only good download I provide is for Arch Linux and Ubuntu 17.04
The Arch download is on the AUR as `kshare` and `kshare-git`,
The OS X and Debian/Ubuntu builds can be found here: [CI](https://nativeci.arsenarsen.com/job/KShare%20(master\))
There is a windows build on [AppVeyor]()
## Wait.. how do I actually use this?
Here is the wiki: [`ding`](https://github.com/ArsenArsen/KShare/wiki)

View File

@ -1,42 +0,0 @@
---
title: Basic Usage
categories: [wiki]
layout: wikipage
---
# Basic usage
When you start the app (with no arguments, discussed later) a window is popped up, and a tray icon is made.
## The window
![](http://i.imgur.com/QOebwEM.png)
The main window is a log window with a settings button.
The menu bar has a `File` menu. It has two options, `Quit`, which exits ~~no need to press it :^)~~, and `About`, which contains licensing information:
![](http://i.imgur.com/4fVJb1w.png)
There is a second menu, namely `Screenshot`. It has two options, area, and fullscreen capture. See below.
The third, `Utility`, menu has the color picker in it.
The fourth and final menu, `Recording`, has a start and stop recording button.
## The tray
![](http://i.imgur.com/quVDzRN.png)
The tray consists of a small, but nice, icon made by @BriannaFoxwell. Upon right clicking it you get the context menu shown above. The menu is rather simple, containing basic controls, and screenshotting options.
These options will be explained below.
## Screenshotting options
### Area capture
Area capture takes a snapshot of the screen, and shows you a fullscreen editor for you to select a region in. This editor is explained in a section below.
### Fullscreen capture
Fullscreen capture takes a snapshot of the entire screen and skips the editor part. Straight to the destination (explained later as well).
### Active window capture
Takes the active window and uploads it straight to your destination of choice
## Crop Editor
Crop Editor is a window you can use to select the area of the screen to upload. It consists of a grey overlay and a re-sizable rectangle. The rectangle is resized by holding the mouse buttons. When you let go of the button, a new selection will start replacing the old one. On the first press the same thing happens.
Press `Escape` to cancel, and `Return`, or `Enter` to submit.
Oh. And you can draw with the bar that appears on the top.

View File

@ -1,45 +0,0 @@
---
title: Destinations
categories: [wiki]
layout: wikipage
---
# Destinations
Destinations determine where your image goes
There is a set of default uploaders, two, to be exact.
## Default uploaders:
### imgur
Uploads your image to imgur.
### clipboard
Copies your image to clipboard.
## Custom uploaders
Placed into `CONFIG PATH/KShare/uploaders`
Eg: `$HOME/.config/KShare/uploaders`
All uploaders have to be `.uploader` files!
Custom uploaders can be added, and are made with JSON, and follow this template:
```js
{
"name": "", // String, required
"desc": "", // String, optional
"method": "", // String, default: "POST", for now, just POST. Request more if you need them
"target": "", // URL, required
"format": "", // String, default: "json", can be `x-www-form-urlencoded` or `json` or `multipart-form-data`. Setting to `PLAIN` will make the body ignored and only the image sent.
"base64": false, // Optional, makes the data base64
"body": {}, // A JSON object, where one of the nodes can be a string in the format `/ANYTHING/`. In `ANYTHING`, `%contenttype` is replaced with the image type and `%imagedata` is replaced with the image encoded with `imageformat`. Unless you use multipart, see below
"return": "" // Return pathspec. `|` copies the entire body, `.path.to.node` copies the value of the node. The dot IS IMPORTANT. Without it, nothing happens. If one of the nodes is not a string, the string is copied, if one is an object, recursion continues, if one is null, nothing is copied, otherwise the node is JSON stringified. Only supports JSON for now.
}
```
Note that QJson does not support comments.
### Multipart
Multipart is obviously made out of multiple parts. The way you define a multipart body is:
```js
[
{
"__HeaderName": "HeaderValue", // No limit here. Must start with __, which is removed later.
"body": { /* same way you define it for anything json */ }, // Can be string. Strings matching `/.../` are processed same way as in a json field.
"name": "files[]" // Info to add to Content-Disposition (eg part name, filename, ...)
}
]
```
This would go in the `body` field of the above JSON.

View File

@ -1,29 +0,0 @@
---
title: Encoder Settings
categories: [wiki]
layout: wikipage
---
# Encoder settings
The encoders used can be customized to a high degree. Every encoder besides GIF has some settings.
![](http://i.imgur.com/O8nfeos.png)
## Image encoder settings
The only option here is quality, by default it uses the default for the format you use. You can change it by unticking format default. [More info](http://doc.qt.io/qt-5/qpixmap.html#save)
## Video encoder settings
The common settings are bitrate and GOP size.
GOP Size is the size of a group of pictures.
Bitrate is the target bitrate.
### h264/h265
The H.26[45] MP4 codec has a few presets to choose. The recommended is to choose the slowest one you can cope with.
I recommend medium.
CRF is the constant rate factor of this video stream, and again I recommend leaving the default value, `23`.
### VP9
VP9 is the WebP codec. Only option it has is lossless encoding, and you want it off, trust me.
### GIF
GIF has no options. It's terrible whatever you do to it.

View File

@ -1,23 +0,0 @@
---
title: Hotkeys
categories: [wiki]
layout: wikipage
---
# Hotkeys
Hotkeys are configured in the settings UI.
![](http://i.imgur.com/esYoMWo.png)
Currently available hotkeys are:
## Fullscreen image
This bind lets you take a fullscreen image and upload it instantly.
## Area image
Equivalent to `Take area shot` and `Screenshot -> Area`. Takes a snapshot and opens the crop editor.
## Active window
Equivalent to `Active window` and `Screenshot -> Active window`. Takes a snapshot of the active window and sends it.
## Color picker
Opens the color picker
## Recording start/stop
Starts and stops recording
## Editing hotkeys
All binds can be modified using by double clicking the hotkey name.
You can either type the hotkey in or press record and press the key combination you want on your keyboard

View File

@ -1,23 +0,0 @@
---
title: Settings
categories: [wiki]
layout: wikipage
---
# Settings
## Destination
![](http://i.imgur.com/540REFK.png)
Select the active destination. Adding more is possible and explained it Custom Uploaders
**Default:** `imgur`
## Filename scheme
![](http://i.imgur.com/RHHEO3K.png)
Used to generate filenames. Extensions are placed in place of `%ext`. `%(DATE FORMAT)date` can be used to replace the date format with a format as specified by [this documentation page](http://doc.qt.io/qt-5/qdatetime.html#toString)
**Default:** `Screenshot %(yyyy-MM-dd HH-mm-ss)date.%ext`
## Delay before taking a screenshot
![](http://i.imgur.com/j0D7OqI.png)
Applies only to the buttons in menus. Hotkeys do not follow this rule. In seconds. Mostly used to let animations fade.
Min: `0.00`
Max: `99.99`
**Default:** `0.25`
## Hotkeys
**Explained on a separate page.**

View File

@ -1,34 +0,0 @@
---
title: Tools
categories: [wiki]
layout: wikipage
---
# Drawing
![](http://i.imgur.com/5nWhpqw.png)
On-screen drawing is pretty simple. Right click in the crop editor to show a pen selection tool. When you click on a pen it will stay selected until you press `Reset`.
You can move drawings around by Ctrl+Dragging them
## Available pens:
### Free draw (pen icon)
Makes a path where your mouse went.
### Blur (badly made blurred rectangle icon)
Allows you to set a rectangle to blur out.
### Straight line
A line between where you start and end dragging
### Text
Asks you to insert some text.
**WARNING:** Avoid pressing esc
### Rectangle
Drag to draw a rectangle
### Ellipse
Drag to draw an ellipse
### Arrow
Draws an arrow from start to end of your drag
### Eraser[](https://www.youtube.com/watch?v=OjGrcJ4lZCc)
Removes all items you drag your mouse over
### Clear all drawings
Removes all drawings
### Reset
Allows you to choose a region to cut for the final result.

View File

@ -1,11 +0,0 @@
---
title: Index
categories: [wiki]
layout: wikipage
---
# Welcome to the KShare wiki!
The cross platform screenshotting utility
# Usage
See the [`Basic usage`](/wiki/Basic-Usage.html) page

View File

@ -1,6 +1,6 @@
# Maintainer: Gurkengewuerz <niklas@mc8051.de>
pkgname=kshare-git
pkgver=v4.1.r196.gc38161b
pkgver=v5.0.4+dev
pkgrel=1
pkgdesc="The free and open source and cross platform screen sharing software."
arch=('i686' 'x86_64')
@ -8,14 +8,14 @@ url="https://github.com/Gurkengewuerz/KShare"
license=('MIT')
provides=(kshare)
conflicts=(kshare)
depends=(qt5-base qt5-x11extras qt5-svg xcb-util-cursor ffmpeg libxfixes)
depends=(qt5-base qt5-x11extras qt5-svg qt5-multimedia xcb-util-cursor ffmpeg libxfixes)
makedepends=(git pkg-config)
source=(git+https://github.com/Gurkengewuerz/KShare.git#branch=dev)
sha1sums=('SKIP')
pkgver() {
cd KShare
echo "v4.1.r196.gc38161b"
echo "v5.0.4+dev"
}
prepare() {

View File

@ -1,6 +1,6 @@
# Maintainer: Gurkengewuerz <niklas@mc8051.de>
pkgname=kshare
pkgver=v5.0.0
pkgver=v5.0.4
pkgrel=1
conflicts=("kshare-git")
pkgdesc="The free and open source and cross platform screen sharing software."
@ -8,7 +8,7 @@ arch=('i686' 'x86_64')
url="https://github.com/Gurkengewuerz/KShare"
license=('MIT')
provides=('kshare=$pkgver')
depends=(qt5-base qt5-x11extras qt5-svg xcb-util-cursor ffmpeg libxfixes)
depends=(qt5-base qt5-x11extras qt5-svg qt5-multimedia xcb-util-cursor ffmpeg libxfixes)
makedepends=(git pkg-config)
source=(git+https://github.com/Gurkengewuerz/KShare.git)
sha1sums=('SKIP')

View File

@ -2,7 +2,8 @@
VERSION=$(grep setApplicationVersion ../src/main.cpp | head -n1 | cut -d \" -f2)
echo "Make Debian package for v$VERSION" >&2
cp deb work -r
mkdir work/ || true
cp deb/* work -r
sed "s/%ver/$VERSION/g" deb/DEBIAN/control > work/DEBIAN/control
mkdir -p work/usr/bin
@ -29,8 +30,10 @@ else
fi
cd work
echo "md5sum" >&2
md5sum usr/bin/kshare usr/share/applications/KShare.desktop > DEBIAN/md5sums
cd ..
echo "dpkg-deb" >&2
dpkg-deb -b work/
mv work.deb kshare_v${VERSION}.deb
rm -rf work

View File

@ -55,5 +55,6 @@ echo -----------------
cat installer.iss.pattern.bottom >> installer.iss
"C:\Program Files (x86)\Inno Setup 5\ISCC.exe" installer.iss
cp Output/setup.exe ../../installer.exe || exit 1
cp portable.zip ../../ || exit 2
cp Output/setup.exe ../../win_kshare_v${ver}_installer.exe || exit 1
cp ../../KShare.exe ../../KShare_v${ver}.exe || exit 1
cp portable.zip ../../win_kshare_v${ver}_portable.zip || exit 2

View File

@ -41,6 +41,14 @@ void hotkeying::load(QString seqName, std::function<void()> func, QString def) {
;
}
void hotkeying::clearAll() {
for(QString e : hotkeys.keys()) {
QHotkey *hk = hotkeys.value(e);
hk->setRegistered(false);
delete hk;
}
}
bool hotkeying::valid(QString seq) {
return seq.isEmpty() || !QKeySequence(seq).toString().isEmpty();
}

View File

@ -9,6 +9,7 @@ namespace hotkeying {
void hotkey(QString seqName, QKeySequence seq, std::function<void()> func);
bool valid(QString seq);
void load(QString seqName, std::function<void()> func, QString def = QString());
void clearAll();
QString sequence(QString seqName);
} // namespace hotkeying

View File

@ -3,11 +3,10 @@
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <thread>
#include <logs/requestlogging.hpp>
#include <logs/screenshotfile.h>
QNetworkAccessManager ioutils::networkManager;
QNetworkAccessManager* ioutils::networkManager= new QNetworkAccessManager();
void ioutils::addLogEntry(QNetworkReply* reply, QByteArray data, QString result, ScreenshotFile sf) {
requestlogging::RequestContext ctx;
@ -38,13 +37,13 @@ void ioutils::postMultipart(QUrl target,
for (auto header : headers) {
if (header.first.toLower() != "content-type") req.setRawHeader(header.first.toUtf8(), header.second.toUtf8());
}
QNetworkReply *reply = networkManager.post(req, body);
QNetworkReply *reply = networkManager->post(req, body);
addTask();
QObject::connect(reply, &QNetworkReply::finished, [reply, callback] {
removeTask();
QByteArray data = reply->readAll();
callback(QJsonDocument::fromJson(data), data, reply);
delete reply;
reply->deleteLater();
});
}
@ -56,13 +55,13 @@ void ioutils::postMultipartData(QUrl target,
for (auto header : headers) {
if (header.first.toLower() != "content-type") req.setRawHeader(header.first.toUtf8(), header.second.toUtf8());
}
QNetworkReply *reply = networkManager.post(req, body);
QNetworkReply *reply = networkManager->post(req, body);
addTask();
QObject::connect(reply, &QNetworkReply::finished, [reply, callback] {
removeTask();
QByteArray data = reply->readAll();
callback(data, reply);
delete reply;
reply->deleteLater();
});
}
@ -73,7 +72,7 @@ void ioutils::getJson(QUrl target,
for (auto header : headers) {
req.setRawHeader(header.first.toUtf8(), header.second.toUtf8());
}
QNetworkReply *reply = networkManager.get(req);
QNetworkReply *reply = networkManager->get(req);
addTask();
QObject::connect(reply, &QNetworkReply::finished, [reply, callback] {
removeTask();
@ -91,13 +90,13 @@ void ioutils::postJson(QUrl target,
for (auto header : headers) {
req.setRawHeader(header.first.toUtf8(), header.second.toUtf8());
}
QNetworkReply *reply = networkManager.post(req, body);
QNetworkReply *reply = networkManager->post(req, body);
addTask();
QObject::connect(reply, &QNetworkReply::finished, [reply, callback] {
removeTask();
QByteArray data = reply->readAll();
callback(QJsonDocument::fromJson(data), data, reply);
delete reply;
reply->deleteLater();
});
}
@ -106,13 +105,13 @@ void ioutils::getData(QUrl target, QList<QPair<QString, QString>> headers, std::
for (auto header : headers) {
req.setRawHeader(header.first.toUtf8(), header.second.toUtf8());
}
QNetworkReply *reply = networkManager.get(req);
QNetworkReply *reply = networkManager->get(req);
addTask();
QObject::connect(reply, &QNetworkReply::finished, [reply, callback] {
removeTask();
QByteArray data = reply->readAll();
callback(data, reply);
delete reply;
reply->deleteLater();
});
}
@ -124,16 +123,19 @@ void ioutils::postData(QUrl target,
for (auto header : headers) {
req.setRawHeader(header.first.toUtf8(), header.second.toUtf8());
}
QNetworkReply *reply = networkManager.post(req, body);
QNetworkReply *reply = networkManager->post(req, body);
addTask();
QObject::connect(reply, &QNetworkReply::finished, [reply, callback] {
removeTask();
QByteArray data = reply->readAll();
callback(data, reply);
delete reply;
reply->deleteLater();
});
}
void ioutils::deleteNetworkManger() {
delete networkManager;
}
QString ioutils::methodString(QNetworkAccessManager::Operation operation) {
switch (operation) {

View File

@ -9,7 +9,7 @@
#include <logs/screenshotfile.h>
namespace ioutils {
extern QNetworkAccessManager networkManager;
extern QNetworkAccessManager* networkManager;
void addLogEntry(QNetworkReply* reply, QByteArray data, QString result, ScreenshotFile sf);
void getJson(QUrl target,
QList<QPair<QString, QString>> headers,
@ -28,6 +28,7 @@ namespace ioutils {
QList<QPair<QString, QString>> headers,
QHttpMultiPart *body,
std::function<void(QByteArray, QNetworkReply *)> callback);
void deleteNetworkManger();
QString methodString(QNetworkAccessManager::Operation operation);
QString httpString(int responseCode);
} // namespace ioutils

View File

@ -74,7 +74,7 @@ int main(int argc, char *argv[]) {
a.setQuitOnLastWindowClosed(false);
a.setApplicationName("KShare");
a.setOrganizationName("ArsenArsen");
a.setApplicationVersion("5.0.0");
a.setApplicationVersion("5.0.4");
QString locale = QLocale::system().name();
if (locale != "en_US") loadTranslation(locale);

View File

@ -205,6 +205,8 @@ void MainWindow::closeEvent(QCloseEvent *event) {
}
void MainWindow::quit() {
ioutils::deleteNetworkManger();
hotkeying::clearAll();
QApplication::quit();
}

View File

@ -3,9 +3,12 @@
#include "systemnotification.h"
#include "mainwindow.hpp"
#include "ui_mainwindow.h"
#include <settings.hpp>
#include <QApplication>
#include <QMediaPlayer>
QMediaPlayer *mediaPlayer = nullptr;
void notifications::notify(QString title, QString body, QSystemTrayIcon::MessageIcon icon) {
if (!MainWindow::inst() || !MainWindow::inst()->valid()) return;
notifyNolog(title, body, icon);
@ -24,29 +27,36 @@ void notifications::notifyNolog(QString title, QString body, QSystemTrayIcon::Me
}
void notifications::playSound(notifications::Sound soundType) {
QMediaPlayer*mediaPlayer = new QMediaPlayer(MainWindow::inst());
if(!settings::settings().value("playSound", true).toBool()) return;
switch (soundType) {
case notifications::Sound::CAPTURE:
mediaPlayer->setMedia(QUrl("qrc:/capturesound.wav"));
break;
try {
if (mediaPlayer == nullptr) {
mediaPlayer = new QMediaPlayer(MainWindow::inst());
}
case notifications::Sound::SUCCESS:
mediaPlayer->setMedia(QUrl("qrc:/successsound.wav"));
break;
switch (soundType) {
case notifications::Sound::CAPTURE:
mediaPlayer->setMedia(QUrl("qrc:/capturesound.wav"));
break;
case notifications::Sound::ERROR:
mediaPlayer->setMedia(QUrl("qrc:/errorsound.wav"));
break;
case notifications::Sound::SUCCESS:
mediaPlayer->setMedia(QUrl("qrc:/successsound.wav"));
break;
default:
break;
case notifications::Sound::ERROR:
mediaPlayer->setMedia(QUrl("qrc:/errorsound.wav"));
break;
default:
break;
}
mediaPlayer->setVolume(25);
mediaPlayer->play();
if(mediaPlayer->error() != QMediaPlayer::NoError && mediaPlayer->error() != QMediaPlayer::ServiceMissingError)
notifications::notify(QString::number(mediaPlayer->error()), mediaPlayer->errorString(), QSystemTrayIcon::Warning);
} catch (...) {
notifications::notifyNolog(QObject::tr("KShare: No sound driver"), "No sound driver found. Install libqt5multimedia5-plugins for notifcation sound support.", QSystemTrayIcon::Warning);
}
mediaPlayer->setVolume(25);
mediaPlayer->play();
if(mediaPlayer->error() != QMediaPlayer::NoError && mediaPlayer->error() != QMediaPlayer::ServiceMissingError)
notifications::notify(QString::number(mediaPlayer->error()), mediaPlayer->errorString(), QSystemTrayIcon::Warning);
}

View File

@ -68,6 +68,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Se
ui->quickMode->setChecked(settings::settings().value("quickMode", false).toBool());
ui->hideToTray->setChecked(settings::settings().value("hideOnClose", true).toBool());
ui->captureCursor->setChecked(settings::settings().value("captureCursor", true).toBool());
ui->playSound->setChecked(settings::settings().value("playSound", true).toBool());
ui->saveLocation->setCurrentIndex(settings::settings().value("saveLocation", 1).toInt());
ui->themeSelection->setCurrentIndex(settings::settings().value("theme", 0).toInt());
for (int i = 0; i < (int)formats::Recording::None; i++) {
@ -158,6 +159,10 @@ void SettingsDialog::on_captureCursor_clicked(bool checked) {
settings::settings().setValue("captureCursor", checked);
}
void SettingsDialog::on_playSound_clicked(bool checked) {
settings::settings().setValue("playSound", checked);
}
void SettingsDialog::on_formatBox_currentIndexChanged(int index) {
if (isVisible()) settings::settings().setValue("recording/format", index);
}

View File

@ -26,6 +26,7 @@ private slots:
void on_quickMode_clicked(bool checked);
void on_hideToTray_clicked(bool checked);
void on_captureCursor_clicked(bool checked);
void on_playSound_clicked(bool checked);
void on_formatBox_currentIndexChanged(int index);
void on_imageFormatBox_currentIndexChanged(int index);
void on_pushButton_clicked();

View File

@ -6,195 +6,14 @@
<rect>
<x>0</x>
<y>0</y>
<width>650</width>
<height>759</height>
<width>753</width>
<height>326</height>
</rect>
</property>
<property name="windowTitle">
<string>Crop editor settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="19" column="1" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Advanced</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="0">
<widget class="QSpinBox" name="cropX">
<property name="suffix">
<string/>
</property>
<property name="prefix">
<string notr="true">x: </string>
</property>
<property name="minimum">
<number>-999999</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="cropY">
<property name="prefix">
<string notr="true">y: </string>
</property>
<property name="minimum">
<number>-999999</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Editor Position (tweak if the editor does not cover the entire screen)</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Encoder settings</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="15" column="2">
<widget class="QSpinBox" name="fpsMax">
<property name="suffix">
<string>FPS</string>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Frames Per Second For Recording</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Delay before taking a screenshot</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Recording format</string>
</property>
</widget>
</item>
<item row="11" column="1" colspan="2">
<widget class="QCheckBox" name="captureCursor">
<property name="text">
<string>Capture cursor</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="nameScheme">
<property name="toolTip">
<string>%(date format)date and %ext are supported</string>
</property>
<property name="text">
<string notr="true">Screenshot %(yyyy-MM-dd HH-mm-ss)date.%ext</string>
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QComboBox" name="formatBox">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>File name scheme:</string>
</property>
</widget>
</item>
<item row="17" column="2">
<widget class="QLineEdit" name="fullscreenCapture"/>
</item>
<item row="18" column="1">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Focused capture command (save to %FILE_PATH or print to stdout)</string>
</property>
</widget>
</item>
<item row="18" column="2">
<widget class="QLineEdit" name="focusedCapture"/>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="folderFormat">
<property name="text">
<string>%(yyyy-MM)date</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Screenshot Subfolder</string>
</property>
</widget>
</item>
<item row="12" column="1" colspan="2">
<widget class="QCheckBox" name="hideToTray">
<property name="text">
<string>Pressing &lt;X&gt; hides to tray</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="saveLocation">
<item>
<property name="text">
<string>Pictures folder</string>
</property>
</item>
<item>
<property name="text">
<string>Screenshots folder (In your user folder)</string>
</property>
</item>
<item>
<property name="text">
<string>Do not save</string>
</property>
</item>
</widget>
</item>
<item row="10" column="2">
<widget class="QPushButton" name="settingsButton">
<property name="text">
<string>Open settings directory</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>Destination:</string>
</property>
</widget>
</item>
<item row="20" column="1" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
@ -205,92 +24,355 @@
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>File save location</string>
<item row="0" column="1" colspan="2">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QListWidget" name="uploaderList"/>
</item>
<item row="14" column="2">
<widget class="QComboBox" name="imageFormatBox"/>
</item>
<item row="9" column="1">
<widget class="QDoubleSpinBox" name="delay">
<property name="toolTip">
<string>In seconds</string>
</property>
<property name="whatsThis">
<string>A delay before taking a screenshot, in seconds</string>
</property>
<property name="suffix">
<string notr="true">s</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="quickMode">
<property name="text">
<string>Quick mode (mouse release screenshots)</string>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Fullscreen capture command (save to %FILE_PATH or print to stdout)</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Hotkeys</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Still image format</string>
</property>
</widget>
</item>
<item row="1" column="2" rowspan="7">
<widget class="QListWidget" name="hotkeys"/>
</item>
<item row="8" column="2">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Theme</string>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QComboBox" name="themeSelection">
<item>
<property name="text">
<string>System Default</string>
</property>
</item>
<item>
<property name="text">
<string>QDarkStyle</string>
</property>
</item>
<item>
<property name="text">
<string>Breeze Light</string>
</property>
</item>
<item>
<property name="text">
<string>Breeze Dark</string>
</property>
</item>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="0">
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Theme</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="themeSelection">
<item>
<property name="text">
<string>System Default</string>
</property>
</item>
<item>
<property name="text">
<string>QDarkStyle</string>
</property>
</item>
<item>
<property name="text">
<string>Breeze Light</string>
</property>
</item>
<item>
<property name="text">
<string>Breeze Dark</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="quickMode">
<property name="text">
<string>Quick mode (mouse release screenshots)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="hideToTray">
<property name="text">
<string>Pressing &lt;X&gt; hides to tray</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="captureCursor">
<property name="text">
<string>Capture cursor</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Delay before taking a screenshot</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QDoubleSpinBox" name="delay">
<property name="toolTip">
<string>In seconds</string>
</property>
<property name="whatsThis">
<string>A delay before taking a screenshot, in seconds</string>
</property>
<property name="suffix">
<string notr="true">s</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="playSound">
<property name="text">
<string>Play notification Sound</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="settingsButton">
<property name="text">
<string>Open settings directory</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Hoster</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QListWidget" name="uploaderList"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Hotkeys</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="hotkeys"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Paths</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>File name scheme</string>
</property>
<property name="margin">
<number>0</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="nameScheme">
<property name="toolTip">
<string>%(date format)date and %ext are supported</string>
</property>
<property name="text">
<string notr="true">Screenshot %(yyyy-MM-dd HH-mm-ss)date.%ext</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Screenshot Subfolder</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="folderFormat">
<property name="text">
<string>%(yyyy-MM)date</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>File save location</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="saveLocation">
<item>
<property name="text">
<string>Pictures folder</string>
</property>
</item>
<item>
<property name="text">
<string>Screenshots folder (In your user folder)</string>
</property>
</item>
<item>
<property name="text">
<string>Do not save</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>Recording</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_10">
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Advanced</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="0">
<widget class="QSpinBox" name="cropX">
<property name="suffix">
<string/>
</property>
<property name="prefix">
<string notr="true">x: </string>
</property>
<property name="minimum">
<number>-999999</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="cropY">
<property name="prefix">
<string notr="true">y: </string>
</property>
<property name="minimum">
<number>-999999</number>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Editor Position (tweak if the editor does not cover the entire screen)</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Encoder settings</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_9">
<item row="0" column="1">
<widget class="QComboBox" name="formatBox">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Recording format</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Still image format</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="imageFormatBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Frames Per Second For Recording</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="fpsMax">
<property name="suffix">
<string>FPS</string>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>Advanced</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Fullscreen capture command (save to %FILE_PATH or print to stdout)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Focused capture command (save to %FILE_PATH or print to stdout)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="fullscreenCapture"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="focusedCapture"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

View File

@ -34,6 +34,7 @@ SOURCES += main.cpp\
screenshotter.cpp \
utils.cpp \
uploaders/default/imguruploader.cpp \
uploaders/default/gdriveuploader.cpp \
io/ioutils.cpp \
settings.cpp \
uploaders/default/clipboarduploader.cpp \
@ -65,6 +66,7 @@ SOURCES += main.cpp\
hotkeyinputdialog.cpp \
cropeditor/drawing/arrowitem.cpp \
uploaders/default/imgursettingsdialog.cpp \
uploaders/default/gdrivesettingsdialog.cpp \
filenamevalidator.cpp \
logs/requestlogging.cpp \
monospacetextdialog.cpp \
@ -85,6 +87,7 @@ HEADERS += mainwindow.hpp \
screenshotter.hpp \
utils.hpp \
uploaders/default/imguruploader.hpp \
uploaders/default/gdriveuploader.hpp \
io/ioutils.hpp \
settings.hpp \
uploaders/default/clipboarduploader.hpp \
@ -118,6 +121,7 @@ HEADERS += mainwindow.hpp \
hotkeyinputdialog.hpp \
cropeditor/drawing/arrowitem.hpp \
uploaders/default/imgursettingsdialog.hpp \
uploaders/default/gdrivesettingsdialog.hpp \
filenamevalidator.hpp \
logs/requestlogging.hpp \
monospacetextdialog.hpp \
@ -189,6 +193,7 @@ FORMS += mainwindow.ui \
aboutbox.ui \
hotkeyinputdialog.ui \
uploaders/default/imgursettingsdialog.ui \
uploaders/default/gdrivesettingsdialog.ui \
monospacetextdialog.ui \
screenoverlay/screenoverlaysettings.ui

View File

@ -0,0 +1,177 @@
#include "gdrivesettingsdialog.hpp"
#include "ui_gdrivesettingsdialog.h"
#include <QDesktopServices>
#include <QDialogButtonBox>
#include <QLabel>
#include <QLineEdit>
#include <QNetworkReply>
#include <QPushButton>
#include <QUrl>
#include <io/ioutils.hpp>
#include <settings.hpp>
GDriveSettingsDialog::GDriveSettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::GDriveSettingsDialog) {
ui->setupUi(this);
connect(this, &GDriveSettingsDialog::accepted, this, &GDriveSettingsDialog::deleteLater);
ui->clientId->setText(settings::settings().value("google/cid").toString());
ui->clientSecret->setText(settings::settings().value("google/csecret").toString());
ui->folderId->setText(settings::settings().value("google/folder").toString().toUtf8());
ui->isPublic->setChecked(settings::settings().value("google/public").toBool());
}
GDriveSettingsDialog::~GDriveSettingsDialog() {
delete ui;
}
void GDriveSettingsDialog::on_addApp_clicked() {
QDesktopServices::openUrl(
QUrl(QString("https://accounts.google.com/o/oauth2/auth?client_id=%1&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive").arg(ui->clientId->text())));
}
void GDriveSettingsDialog::on_isPublic_clicked(bool checked) {
settings::settings().setValue("google/public", checked);
}
void GDriveSettingsDialog::on_folderId_textChanged(QString arg1) {
settings::settings().setValue("google/folder", arg1);
}
bool GDriveSettingsDialog::checkAuthorization () {
if (ui->folderId->text().isEmpty()) return false;
settings::settings().setValue("google/folder", ui->folderId->text());
if (settings::settings().contains("google/expire") //
&& settings::settings().contains("google/refresh") //
&& settings::settings().contains("google/access")) {
QDateTime expireTime = settings::settings().value("google/expire").toDateTime();
if (QDateTime::currentDateTimeUtc() > expireTime) {
// Token expired
ui->status->setText(tr("Token expired"));
} else {
ui->buttonBox->setEnabled(false);
ui->testButton->setEnabled(false);
ioutils::getData(QUrl(QString("https://www.googleapis.com/drive/v3/files?q='%1'+in+parents&fields=files(md5Checksum,+originalFilename)").arg(ui->folderId->text())),
QList<QPair<QString, QString>>({ QPair<QString, QString>("Authorization", settings::settings().value("google/access").toString().prepend("Bearer ")) }),
[&](QByteArray a, QNetworkReply *r) {
QVariant statusCode = r->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (!statusCode.isValid()) return;
ui->testButton->setEnabled(true);
int status = statusCode.toInt();
if (status != 200 && status != 400)
{
QString reason = r->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
qDebug() << reason;
ui->buttonBox->setEnabled(true);
ui->status->setText(reason);
return;
}
QJsonDocument response = QJsonDocument::fromJson(a);
if (!response.isObject()) {
ui->buttonBox->setEnabled(true);
ui->status->setText("Invalid JSON");
return;
}
QJsonObject res = response.object();
if (res.contains("error")) {
ui->buttonBox->setEnabled(true);
ui->status->setText(res.value("error_description").toString().toUtf8());
ui->status->setStyleSheet("* { color: red; }");
return;
}
ui->buttonBox->setEnabled(true);
ui->testButton->hide();
ui->status->setText(tr("It works!"));
ui->status->setStyleSheet("* { color: green; }");
});
}
} else {
// No Token set
ui->status->setText(tr("Login with Google needed"));
}
}
void GDriveSettingsDialog::on_testButton_clicked() {
GDriveSettingsDialog::checkAuthorization();
}
void GDriveSettingsDialog::on_authorize_clicked() {
if (ui->pin->text().isEmpty() || ui->folderId->text().isEmpty()) return;
ui->buttonBox->setEnabled(false);
QJsonObject object;
object.insert("client_id", ui->clientId->text());
object.insert("client_secret", ui->clientSecret->text());
object.insert("grant_type", "authorization_code");
object.insert("code", ui->pin->text());
object.insert("redirect_uri", "urn:ietf:wg:oauth:2.0:oob");
settings::settings().setValue("google/cid", ui->clientId->text());
settings::settings().setValue("google/csecret", ui->clientSecret->text());
settings::settings().setValue("google/folder", ui->folderId->text());
settings::settings().setValue("google/public", ui->isPublic->isChecked());
ioutils::postJson(QUrl("https://accounts.google.com/o/oauth2/token"),
QList<QPair<QString, QString>>({ QPair<QString, QString>("Content-Type", "applicaton/json") }),
QJsonDocument::fromVariant(object.toVariantMap()).toJson(),
[&](QJsonDocument response, QByteArray, QNetworkReply *r) {
QVariant statusCode = r->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (!statusCode.isValid()) return;
int status = statusCode.toInt();
if (status != 200 && status != 400)
{
QString reason = r->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
qDebug() << reason;
ui->buttonBox->setEnabled(true);
return;
}
if (!response.isObject()) {
ui->buttonBox->setEnabled(true);
return;
}
QJsonObject res = response.object();
if (res.contains("error")) {
ui->buttonBox->setEnabled(true);
ui->status->setText(res.value("error_description").toString().toUtf8());
ui->status->setStyleSheet("* { color: red; }");
return;
}
if (res.value("success").toBool()) {
ui->buttonBox->setEnabled(true);
return;
}
settings::settings().setValue("google/expire",
QDateTime::currentDateTimeUtc().addSecs(res["expires_in"].toInt()));
settings::settings().setValue("google/refresh", res["refresh_token"].toString().toUtf8());
settings::settings().setValue("google/access", res["access_token"].toString().toUtf8());
ui->status->setText(tr("It works!"));
ui->status->setStyleSheet("* { color: green; }");
ui->authorize->setEnabled(false);
ui->addApp->setEnabled(false);
ui->clientSecret->setEnabled(false);
ui->clientId->setEnabled(false);
ui->buttonBox->setEnabled(true);
ui->testButton->hide();
});
}

View File

@ -0,0 +1,29 @@
#ifndef GDRIVESETTINGSDIALOG_HPP
#define GDRIVESETTINGSDIALOG_HPP
#include <QDialog>
namespace Ui {
class GDriveSettingsDialog;
}
class GDriveSettingsDialog : public QDialog {
Q_OBJECT
public:
explicit GDriveSettingsDialog(QWidget *parent = 0);
~GDriveSettingsDialog();
private slots:
void on_addApp_clicked();
void on_authorize_clicked();
void on_testButton_clicked();
bool checkAuthorization();
void on_isPublic_clicked(bool);
void on_folderId_textChanged(QString);
private:
Ui::GDriveSettingsDialog *ui;
};
#endif // GRDIVESETTINGSDIALOG_HPP

View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GDriveSettingsDialog</class>
<widget class="QDialog" name="GDriveSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>287</width>
<height>389</height>
</rect>
</property>
<property name="windowTitle">
<string>GDrive auth</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" 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="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>OAuth2</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Authentication needed&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="addApp">
<property name="text">
<string>Login with Google</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter verification code&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QLineEdit" name="pin">
<property name="placeholderText">
<string>Authorization code</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QPushButton" name="authorize">
<property name="text">
<string>Authorize</string>
</property>
</widget>
</item>
<item row="14" column="0" colspan="2">
<widget class="QLabel" name="status">
<property name="styleSheet">
<string notr="true">* { color: red; }</string>
</property>
<property name="text">
<string>Not working</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Client ID/Client Secret</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="clientSecret">
<property name="placeholderText">
<string>Client Secret</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="clientId">
<property name="placeholderText">
<string>Client ID</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Upload Public</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Folder ID</string>
</property>
</widget>
</item>
<item row="15" column="0" colspan="2">
<widget class="QPushButton" name="testButton">
<property name="text">
<string>Check Authorization</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLineEdit" name="folderId"/>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="isPublic">
<property name="text">
<string>Is Public</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>GDriveSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>GDriveSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,162 @@
#include "gdriveuploader.hpp"
#include <QBuffer>
#include <QJsonObject>
#include <QJsonValue>
#include <QNetworkReply>
#include <QHttpMultiPart>
#include <QHttpPart>
#include <QString>
#include <formats.hpp>
#include <io/ioutils.hpp>
#include <notifications.hpp>
#include <settings.hpp>
#include <utils.hpp>
#include <logs/screenshotfile.h>
#include <uploaders/default/gdrivesettingsdialog.hpp>
struct SegfaultWorkaround { // I'm a scrub for doing this
SegfaultWorkaround(QByteArray a, GDriveUploader *u, QString m, bool ip, ScreenshotFile f) : byteArray(), dis(u), mime(m), isPublic(ip), sf(f) {
a.swap(byteArray);
QJsonObject object;
object.insert("client_id", settings::settings().value("google/cid").toString());
object.insert("client_secret", settings::settings().value("google/csecret").toString());
object.insert("grant_type", "refresh_token");
object.insert("refresh_token", settings::settings().value("google/refresh").toString());
ioutils::postJson(
QUrl("https://accounts.google.com/o/oauth2/token"),
QList<QPair<QString, QString>>({ QPair<QString, QString>("Content-Type", "applicaton/json") }),
QJsonDocument::fromVariant(object.toVariantMap()).toJson(), [&](QJsonDocument response, QByteArray, QNetworkReply *r) {
qDebug() << response;
if (r->error() != QNetworkReply::NoError || !response.isObject()) {
notifications::notify(QObject::tr("KShare Google Uploader"),
QString(QObject::tr("Failed upload! Error in refresh token")));
notifications::playSound(notifications::Sound::ERROR);
return;
}
QJsonObject res = response.object();
QString token = res["access_token"].toString();
settings::settings().setValue("google/expire", QDateTime::currentDateTimeUtc().addSecs(res["expires_in"].toInt()));
settings::settings().setValue("google/refresh", res["refresh_token"].toString());
settings::settings().setValue("google/access", token);
dis->handleSend(token.prepend("Bearer "), isPublic, mime, byteArray, sf);
QScopedPointer<SegfaultWorkaround>(this);
});
}
private:
QByteArray byteArray;
GDriveUploader *dis;
QString mime;
bool isPublic;
ScreenshotFile sf;
}; // I feel terrible for making this. I am sorry, reader
void GDriveUploader::doUpload(QByteArray byteArray, QString format, ScreenshotFile sf) {
if (byteArray.size() > 1e+7) {
notifications::notify(tr("KShare imgur Uploader"), tr("Failed upload! Image too big"));
return;
}
QString mime;
if (formats::normalFormatFromName(format) != formats::Normal::None)
mime = formats::normalFormatMIME(formats::normalFormatFromName(format));
else
mime = formats::recordingFormatMIME(formats::recordingFormatFromName(format));
if (settings::settings().contains("google/expire") //
&& settings::settings().contains("google/refresh") //
&& settings::settings().contains("google/access")) {
QDateTime expireTime = settings::settings().value("google/expire").toDateTime();
bool isPublic = settings::settings().value("google/public", false).toBool();
if (QDateTime::currentDateTimeUtc() > expireTime) {
qDebug() << "Need to refresh Google Access Token";
new SegfaultWorkaround(byteArray, this, mime, isPublic, sf);
} else handleSend("Bearer " + settings::settings().value("google/access", "").toString().toUtf8(), isPublic, mime, byteArray, sf);
}
}
void GDriveUploader::showSettings() {
(new GDriveSettingsDialog())->show();
}
void GDriveUploader::setPermission(QString fileID, QString auth, QString role, QString type, bool allowFileDiscovery) {
QJsonObject object;
object.insert("role", role);
object.insert("type", type);
object.insert("allowFileDiscovery", QString(allowFileDiscovery));
QJsonDocument doc(object);
ioutils::postData(QUrl(QString("https://www.googleapis.com/drive/v3/files/%1/permissions").arg(fileID)),
QList<QPair<QString, QString>>({ QPair<QString, QString>("Content-Type", "application/json"), QPair<QString, QString>("Authorization", auth) }),
QString(doc.toJson(QJsonDocument::Compact)).toUtf8(),
[&](QByteArray , QNetworkReply *) {
});
}
void GDriveUploader::handleSend(QString auth, bool isPublic, QString mime, QByteArray byteArray, ScreenshotFile sf) {
QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::RelatedType);
QHttpPart metaPart;
metaPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
metaPart.setHeader(
QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"metadata\"")
);
QString data("{name: '"+sf.getFilename()+"', parents: ['"+settings::settings().value("google/folder").toString().toUtf8()+"']}");
metaPart.setBody(data.toUtf8());
multipart->append(metaPart);
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(mime.toUtf8()));
imagePart.setHeader(
QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"file\"; filename=\""+sf.getFilename()+"\"")
);
imagePart.setBody(byteArray);
multipart->append(imagePart);
ioutils::postMultipartData(QUrl("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,webViewLink,webContentLink"),
QList<QPair<QString, QString>>() << QPair<QString, QString>("Authorization", auth),
multipart, [byteArray, this, mime, sf, auth, isPublic](QByteArray res, QNetworkReply *r) {
qDebug() << QString(res).toUtf8();
if (r->error() == QNetworkReply::ContentAccessDenied) {
(new GDriveSettingsDialog())->show();
return;
}
QString result = QString(res).toUtf8();
if (!result.isEmpty()) {
QJsonDocument doc = QJsonDocument::fromJson(result.toUtf8());
if(!doc.isObject()) {
notifications::notify(tr("KShare Google Uploader "),
QString(tr("Failed upload! Invalid JSON")));
notifications::playSound(notifications::Sound::ERROR);
return;
}
if(isPublic) {
setPermission(doc.object()["id"].toString(), auth);
}
result = doc.object()["webViewLink"].toString();
ioutils::addLogEntry(r, res, result, sf);
notifications::notify(tr("KShare Google Uploader"), tr("Uploaded to Google!"));
notifications::playSound(notifications::Sound::SUCCESS);
utils::toClipboard(result);
} else {
ioutils::addLogEntry(r, res, result, sf);
notifications::notify(tr("KShare Google Uploader "),
QString(tr("Failed upload! Google said: HTTP %1: %2"))
.arg(r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt())
.arg(r->errorString()));
notifications::playSound(notifications::Sound::ERROR);
}
});
}

View File

@ -0,0 +1,27 @@
#ifndef GDRIVEUPLOADER_HPP
#define GRIVEUPLOADER_HPP
#include "../uploader.hpp"
#include <QApplication>
#include <logs/screenshotfile.h>
class GDriveUploader : public Uploader {
Q_DECLARE_TR_FUNCTIONS(GDriveUploader)
friend struct SegfaultWorkaround;
public:
QString name() override {
return "Google Drive";
}
QString description() override {
return "drive.google.com uploader";
}
void doUpload(QByteArray byteArray, QString, ScreenshotFile sf) override;
void showSettings() override;
void setPermission(QString, QString, QString = "reader", QString = "anyone", bool = false);
private:
void handleSend(QString auth, bool isPublic, QString mime, QByteArray byteArray, ScreenshotFile sf);
};
#endif // GDRIVEUPLOADER_HPP

View File

@ -14,7 +14,7 @@
#include <logs/screenshotfile.h>
struct SegfaultWorkaround { // I'm a scrub for doing this
SegfaultWorkaround(QByteArray a, ImgurUploader *u, QString m) : byteArray(), dis(u), mime(m) {
SegfaultWorkaround(QByteArray a, ImgurUploader *u, QString m, ScreenshotFile f) : byteArray(), dis(u), mime(m), sf(f) {
a.swap(byteArray);
QJsonObject object;
object.insert("client_id", settings::settings().value("imgur/cid").toString());
@ -26,7 +26,6 @@ struct SegfaultWorkaround { // I'm a scrub for doing this
QUrl("https://api.imgur.com/oauth2/token"),
QList<QPair<QString, QString>>({ QPair<QString, QString>("Content-Type", "applicaton/json") }),
QJsonDocument::fromVariant(object.toVariantMap()).toJson(), [&](QJsonDocument response, QByteArray, QNetworkReply *r) {
ScreenshotFile sf;
qDebug() << response;
if (r->error() != QNetworkReply::NoError || !response.isObject()) {
dis->handleSend(QStringLiteral("Client-ID 8a98f183fc895da"), mime, byteArray, sf);
@ -52,6 +51,7 @@ private:
QByteArray byteArray;
ImgurUploader *dis;
QString mime;
ScreenshotFile sf;
}; // I feel terrible for making this. I am sorry, reader
void ImgurUploader::doUpload(QByteArray byteArray, QString format, ScreenshotFile sf) {
@ -69,7 +69,7 @@ void ImgurUploader::doUpload(QByteArray byteArray, QString format, ScreenshotFil
&& settings::settings().contains("imgur/access")) {
QDateTime expireTime = settings::settings().value("imgur/expire").toDateTime();
if (QDateTime::currentDateTimeUtc() > expireTime) {
new SegfaultWorkaround(byteArray, this, mime);
new SegfaultWorkaround(byteArray, this, mime, sf);
} else
handleSend("Bearer " + settings::settings().value("imgur/access").toString(), mime, byteArray, sf);
} else
@ -87,14 +87,14 @@ void ImgurUploader::handleSend(QString auth, QString mime, QByteArray byteArray,
byteArray, [byteArray, this, mime, sf](QJsonDocument res, QByteArray data, QNetworkReply *r) {
QString result = res.object()["data"].toObject()["link"].toString();
if (r->error() == QNetworkReply::ContentAccessDenied) {
new SegfaultWorkaround(byteArray, this, mime);
new SegfaultWorkaround(byteArray, this, mime, sf);
return;
}
if (!result.isEmpty()) {
ioutils::addLogEntry(r, data, result, sf);
utils::toClipboard(result);
notifications::notify(tr("KShare imgur Uploader"), tr("Uploaded to imgur!"));
notifications::playSound(notifications::Sound::SUCCESS);
utils::toClipboard(result);
} else {
ioutils::addLogEntry(r, data, result, sf);
notifications::notify(tr("KShare imgur Uploader "),

View File

@ -2,6 +2,7 @@
#include "customuploader.hpp"
#include "default/clipboarduploader.hpp"
#include "default/imguruploader.hpp"
#include "default/gdriveuploader.hpp"
#include <QBuffer>
#include <QDir>
#include <QFile>
@ -33,6 +34,7 @@ UploaderSingleton::UploaderSingleton() : QObject() {
// UPLOADERS
registerUploader(new ImgurUploader);
registerUploader(new GDriveUploader);
registerUploader(new ClipboardUploader);
// ---------

View File

@ -1,2 +0,0 @@
__pycache__
*.pyc

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 MiB

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
#!/usr/bin/env python
#
# The MIT License (MIT)
#
# Copyright (c) <2013-2014> <Colin Duquesnoy>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
"""
A simple example of use.
Load an ui made in QtDesigner and apply the DarkStyleSheet.
Requirements:
- Python 2 or Python 3
- PyQt4
.. note.. :: qdarkstyle does not have to be installed to run
the example
"""
import logging
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QFile, QTextStream
# make the example runnable without the need to install
import example
import breeze_resources
def main():
"""
Application entry point
"""
logging.basicConfig(level=logging.DEBUG)
# create the application and the main window
app = QtWidgets.QApplication(sys.argv)
#app.setStyle(QtWidgets.QStyleFactory.create("fusion"))
window = QtWidgets.QMainWindow()
# setup ui
ui = example.Ui_MainWindow()
ui.setupUi(window)
ui.bt_delay_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
ui.bt_instant_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
ui.bt_menu_button_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
window.setWindowTitle("BreezeDark example")
# tabify dock widgets to show bug #6
window.tabifyDockWidget(ui.dockWidget1, ui.dockWidget2)
# setup stylesheet
file = QFile(":/dark.qss")
file.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(file)
app.setStyleSheet(stream.readAll())
# auto quit after 2s when testing on travis-ci
if "--travis" in sys.argv:
QtCore.QTimer.singleShot(2000, app.exit)
# run
window.show()
app.exec_()
if __name__ == "__main__":
main()

View File

@ -1,359 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'example.ui'
#
# Created by: PyQt5 UI code generator 5.4.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1068, 824)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
self.tabWidget.setTabPosition(QtWidgets.QTabWidget.East)
self.tabWidget.setTabsClosable(True)
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.gridLayout = QtWidgets.QGridLayout(self.tab)
self.gridLayout.setObjectName("gridLayout")
self.groupBox = QtWidgets.QGroupBox(self.tab)
self.groupBox.setObjectName("groupBox")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.toolBox = QtWidgets.QToolBox(self.groupBox)
self.toolBox.setObjectName("toolBox")
self.page = QtWidgets.QWidget()
self.page.setGeometry(QtCore.QRect(0, 0, 718, 227))
self.page.setObjectName("page")
self.gridLayout_4 = QtWidgets.QGridLayout(self.page)
self.gridLayout_4.setObjectName("gridLayout_4")
self.lineEdit = QtWidgets.QLineEdit(self.page)
self.lineEdit.setObjectName("lineEdit")
self.gridLayout_4.addWidget(self.lineEdit, 0, 0, 1, 1)
self.toolBox.addItem(self.page, "")
self.page_2 = QtWidgets.QWidget()
self.page_2.setGeometry(QtCore.QRect(0, 0, 718, 227))
self.page_2.setObjectName("page_2")
self.gridLayout_5 = QtWidgets.QGridLayout(self.page_2)
self.gridLayout_5.setObjectName("gridLayout_5")
self.listWidget = QtWidgets.QListWidget(self.page_2)
self.listWidget.setObjectName("listWidget")
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
item = QtWidgets.QListWidgetItem()
self.listWidget.addItem(item)
self.gridLayout_5.addWidget(self.listWidget, 0, 0, 1, 1)
self.toolBox.addItem(self.page_2, "")
self.verticalLayout_3.addWidget(self.toolBox)
self.gridLayout.addWidget(self.groupBox, 1, 0, 1, 1)
self.tabWidget_2 = QtWidgets.QTabWidget(self.tab)
self.tabWidget_2.setObjectName("tabWidget_2")
self.tab_3 = QtWidgets.QWidget()
self.tab_3.setObjectName("tab_3")
self.gridLayout_6 = QtWidgets.QGridLayout(self.tab_3)
self.gridLayout_6.setObjectName("gridLayout_6")
self.checkableButton = QtWidgets.QPushButton(self.tab_3)
self.checkableButton.setCheckable(True)
self.checkableButton.setChecked(True)
self.checkableButton.setObjectName("checkableButton")
self.gridLayout_6.addWidget(self.checkableButton, 1, 0, 1, 1)
self.pushButton = QtWidgets.QPushButton(self.tab_3)
self.pushButton.setObjectName("pushButton")
self.gridLayout_6.addWidget(self.pushButton, 0, 0, 1, 1)
self.pushButton_5 = QtWidgets.QPushButton(self.tab_3)
self.pushButton_5.setObjectName("pushButton_5")
self.gridLayout_6.addWidget(self.pushButton_5, 2, 0, 1, 1)
self.tabWidget_2.addTab(self.tab_3, "")
self.tab_5 = QtWidgets.QWidget()
self.tab_5.setObjectName("tab_5")
self.gridLayout_7 = QtWidgets.QGridLayout(self.tab_5)
self.gridLayout_7.setObjectName("gridLayout_7")
self.tableWidget = QtWidgets.QTableWidget(self.tab_5)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(2)
self.tableWidget.setRowCount(4)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
self.gridLayout_7.addWidget(self.tableWidget, 0, 0, 1, 1)
self.tabWidget_2.addTab(self.tab_5, "")
self.tab_4 = QtWidgets.QWidget()
self.tab_4.setObjectName("tab_4")
self.tabWidget_2.addTab(self.tab_4, "")
self.gridLayout.addWidget(self.tabWidget_2, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.gridLayout_2 = QtWidgets.QGridLayout(self.tab_2)
self.gridLayout_2.setObjectName("gridLayout_2")
self.groupBox_2 = QtWidgets.QGroupBox(self.tab_2)
self.groupBox_2.setObjectName("groupBox_2")
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox_2)
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.label = QtWidgets.QLabel(self.groupBox_2)
self.label.setObjectName("label")
self.verticalLayout_4.addWidget(self.label)
self.radioButton = QtWidgets.QRadioButton(self.groupBox_2)
self.radioButton.setObjectName("radioButton")
self.verticalLayout_4.addWidget(self.radioButton)
self.checkBox = QtWidgets.QCheckBox(self.groupBox_2)
self.checkBox.setObjectName("checkBox")
self.verticalLayout_4.addWidget(self.checkBox)
self.checkBox_2 = QtWidgets.QCheckBox(self.groupBox_2)
self.checkBox_2.setTristate(True)
self.checkBox_2.setObjectName("checkBox_2")
self.verticalLayout_4.addWidget(self.checkBox_2)
self.treeWidget = QtWidgets.QTreeWidget(self.groupBox_2)
self.treeWidget.setObjectName("treeWidget")
item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
item_1 = QtWidgets.QTreeWidgetItem(self.treeWidget)
item_2 = QtWidgets.QTreeWidgetItem(item_1)
item_2.setText(0, "subitem")
self.verticalLayout_4.addWidget(self.treeWidget)
self.gridLayout_2.addWidget(self.groupBox_2, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab_2, "")
self.verticalLayout_5.addWidget(self.tabWidget)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout.addWidget(self.pushButton_2)
self.bt_delay_popup = QtWidgets.QToolButton(self.centralwidget)
self.bt_delay_popup.setObjectName("bt_delay_popup")
self.horizontalLayout.addWidget(self.bt_delay_popup)
self.bt_instant_popup = QtWidgets.QToolButton(self.centralwidget)
self.bt_instant_popup.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.bt_instant_popup.setObjectName("bt_instant_popup")
self.horizontalLayout.addWidget(self.bt_instant_popup)
self.bt_menu_button_popup = QtWidgets.QToolButton(self.centralwidget)
self.bt_menu_button_popup.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
self.bt_menu_button_popup.setObjectName("bt_menu_button_popup")
self.horizontalLayout.addWidget(self.bt_menu_button_popup)
self.line_2 = QtWidgets.QFrame(self.centralwidget)
self.line_2.setFrameShape(QtWidgets.QFrame.VLine)
self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line_2.setObjectName("line_2")
self.horizontalLayout.addWidget(self.line_2)
self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_3.setEnabled(False)
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout.addWidget(self.pushButton_3)
self.doubleSpinBox = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.doubleSpinBox.setObjectName("doubleSpinBox")
self.horizontalLayout.addWidget(self.doubleSpinBox)
self.toolButton = QtWidgets.QToolButton(self.centralwidget)
self.toolButton.setPopupMode(QtWidgets.QToolButton.InstantPopup)
self.toolButton.setObjectName("toolButton")
self.horizontalLayout.addWidget(self.toolButton)
self.verticalLayout_5.addLayout(self.horizontalLayout)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1068, 29))
self.menubar.setObjectName("menubar")
self.menuMenu = QtWidgets.QMenu(self.menubar)
self.menuMenu.setObjectName("menuMenu")
self.menuSubmenu_2 = QtWidgets.QMenu(self.menuMenu)
self.menuSubmenu_2.setObjectName("menuSubmenu_2")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.dockWidget1 = QtWidgets.QDockWidget(MainWindow)
self.dockWidget1.setObjectName("dockWidget1")
self.dockWidgetContents = QtWidgets.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.dockWidgetContents)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.comboBox = QtWidgets.QComboBox(self.dockWidgetContents)
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.verticalLayout.addWidget(self.comboBox)
self.horizontalSlider = QtWidgets.QSlider(self.dockWidgetContents)
self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
self.horizontalSlider.setObjectName("horizontalSlider")
self.verticalLayout.addWidget(self.horizontalSlider)
self.textEdit = QtWidgets.QTextEdit(self.dockWidgetContents)
self.textEdit.setObjectName("textEdit")
self.verticalLayout.addWidget(self.textEdit)
self.line = QtWidgets.QFrame(self.dockWidgetContents)
self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line.setObjectName("line")
self.verticalLayout.addWidget(self.line)
self.progressBar = QtWidgets.QProgressBar(self.dockWidgetContents)
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.verticalLayout.addWidget(self.progressBar)
self.verticalLayout_2.addLayout(self.verticalLayout)
self.frame = QtWidgets.QFrame(self.dockWidgetContents)
self.frame.setMinimumSize(QtCore.QSize(0, 100))
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setLineWidth(3)
self.frame.setObjectName("frame")
self.verticalLayout_2.addWidget(self.frame)
self.dockWidget1.setWidget(self.dockWidgetContents)
MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockWidget1)
self.toolBar = QtWidgets.QToolBar(MainWindow)
self.toolBar.setObjectName("toolBar")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
self.dockWidget2 = QtWidgets.QDockWidget(MainWindow)
self.dockWidget2.setObjectName("dockWidget2")
self.dockWidgetContents_2 = QtWidgets.QWidget()
self.dockWidgetContents_2.setObjectName("dockWidgetContents_2")
self.gridLayout_3 = QtWidgets.QGridLayout(self.dockWidgetContents_2)
self.gridLayout_3.setObjectName("gridLayout_3")
self.verticalSlider = QtWidgets.QSlider(self.dockWidgetContents_2)
self.verticalSlider.setOrientation(QtCore.Qt.Vertical)
self.verticalSlider.setObjectName("verticalSlider")
self.gridLayout_3.addWidget(self.verticalSlider, 0, 0, 1, 1)
self.dockWidget2.setWidget(self.dockWidgetContents_2)
MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockWidget2)
self.actionAction = QtWidgets.QAction(MainWindow)
self.actionAction.setObjectName("actionAction")
self.actionSub_menu = QtWidgets.QAction(MainWindow)
self.actionSub_menu.setObjectName("actionSub_menu")
self.actionAction_C = QtWidgets.QAction(MainWindow)
self.actionAction_C.setObjectName("actionAction_C")
self.menuSubmenu_2.addAction(self.actionSub_menu)
self.menuSubmenu_2.addAction(self.actionAction_C)
self.menuMenu.addAction(self.actionAction)
self.menuMenu.addAction(self.menuSubmenu_2.menuAction())
self.menubar.addAction(self.menuMenu.menuAction())
self.toolBar.addAction(self.actionAction)
self.toolBar.addAction(self.actionSub_menu)
self.retranslateUi(MainWindow)
self.tabWidget.setCurrentIndex(0)
self.toolBox.setCurrentIndex(1)
self.tabWidget_2.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
MainWindow.setTabOrder(self.pushButton, self.checkableButton)
MainWindow.setTabOrder(self.checkableButton, self.pushButton_5)
MainWindow.setTabOrder(self.pushButton_5, self.tabWidget_2)
MainWindow.setTabOrder(self.tabWidget_2, self.tableWidget)
MainWindow.setTabOrder(self.tableWidget, self.radioButton)
MainWindow.setTabOrder(self.radioButton, self.checkBox)
MainWindow.setTabOrder(self.checkBox, self.checkBox_2)
MainWindow.setTabOrder(self.checkBox_2, self.treeWidget)
MainWindow.setTabOrder(self.treeWidget, self.pushButton_2)
MainWindow.setTabOrder(self.pushButton_2, self.bt_delay_popup)
MainWindow.setTabOrder(self.bt_delay_popup, self.bt_instant_popup)
MainWindow.setTabOrder(self.bt_instant_popup, self.bt_menu_button_popup)
MainWindow.setTabOrder(self.bt_menu_button_popup, self.pushButton_3)
MainWindow.setTabOrder(self.pushButton_3, self.doubleSpinBox)
MainWindow.setTabOrder(self.doubleSpinBox, self.toolButton)
MainWindow.setTabOrder(self.toolButton, self.comboBox)
MainWindow.setTabOrder(self.comboBox, self.horizontalSlider)
MainWindow.setTabOrder(self.horizontalSlider, self.textEdit)
MainWindow.setTabOrder(self.textEdit, self.verticalSlider)
MainWindow.setTabOrder(self.verticalSlider, self.tabWidget)
MainWindow.setTabOrder(self.tabWidget, self.lineEdit)
MainWindow.setTabOrder(self.lineEdit, self.listWidget)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.groupBox.setTitle(_translate("MainWindow", "ToolBox"))
self.toolBox.setItemText(self.toolBox.indexOf(self.page), _translate("MainWindow", "Page 1"))
__sortingEnabled = self.listWidget.isSortingEnabled()
self.listWidget.setSortingEnabled(False)
item = self.listWidget.item(0)
item.setText(_translate("MainWindow", "New Item"))
item = self.listWidget.item(1)
item.setText(_translate("MainWindow", "New Item"))
item = self.listWidget.item(2)
item.setText(_translate("MainWindow", "New Item"))
item = self.listWidget.item(3)
item.setText(_translate("MainWindow", "New Item"))
item = self.listWidget.item(4)
item.setText(_translate("MainWindow", "New Item"))
item = self.listWidget.item(5)
item.setText(_translate("MainWindow", "New Item"))
item = self.listWidget.item(6)
item.setText(_translate("MainWindow", "New Item"))
item = self.listWidget.item(7)
item.setText(_translate("MainWindow", "New Item"))
self.listWidget.setSortingEnabled(__sortingEnabled)
self.toolBox.setItemText(self.toolBox.indexOf(self.page_2), _translate("MainWindow", "Page 2"))
self.checkableButton.setText(_translate("MainWindow", "Checkable button"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
self.pushButton_5.setText(_translate("MainWindow", "PushButton"))
self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_3), _translate("MainWindow", "Tab 1"))
item = self.tableWidget.verticalHeaderItem(0)
item.setText(_translate("MainWindow", "New Row"))
item = self.tableWidget.verticalHeaderItem(1)
item.setText(_translate("MainWindow", "New Row"))
item = self.tableWidget.verticalHeaderItem(2)
item.setText(_translate("MainWindow", "New Row"))
item = self.tableWidget.verticalHeaderItem(3)
item.setText(_translate("MainWindow", "New Row"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "New Column"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "New Column 2"))
self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_5), _translate("MainWindow", "Page"))
self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_4), _translate("MainWindow", "Tab 2"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Tab 1"))
self.groupBox_2.setTitle(_translate("MainWindow", "GroupBox"))
self.label.setText(_translate("MainWindow", "TextLabel"))
self.radioButton.setText(_translate("MainWindow", "RadioB&utton"))
self.checkBox.setText(_translate("MainWindow", "CheckBox"))
self.checkBox_2.setText(_translate("MainWindow", "CheckBox Tristate"))
self.treeWidget.headerItem().setText(0, _translate("MainWindow", "qdz"))
__sortingEnabled = self.treeWidget.isSortingEnabled()
self.treeWidget.setSortingEnabled(False)
self.treeWidget.topLevelItem(0).setText(0, _translate("MainWindow", "qzd"))
self.treeWidget.topLevelItem(1).setText(0, _translate("MainWindow", "effefe"))
self.treeWidget.setSortingEnabled(__sortingEnabled)
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Tab 2"))
self.pushButton_2.setText(_translate("MainWindow", "PushButton"))
self.bt_delay_popup.setText(_translate("MainWindow", "Delayed popup "))
self.bt_instant_popup.setText(_translate("MainWindow", "Instant popup"))
self.bt_menu_button_popup.setText(_translate("MainWindow", "MenuButtonPopup"))
self.pushButton_3.setText(_translate("MainWindow", "Disabled"))
self.toolButton.setText(_translate("MainWindow", "..."))
self.menuMenu.setTitle(_translate("MainWindow", "&Menu"))
self.menuSubmenu_2.setTitle(_translate("MainWindow", "&Submenu 2"))
self.dockWidget1.setWindowTitle(_translate("MainWindow", "&Dock widget 1"))
self.comboBox.setItemText(0, _translate("MainWindow", "Item 0"))
self.comboBox.setItemText(1, _translate("MainWindow", "Item 2"))
self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
self.dockWidget2.setWindowTitle(_translate("MainWindow", "Dock widget &2"))
self.actionAction.setText(_translate("MainWindow", "&Action"))
self.actionSub_menu.setText(_translate("MainWindow", "&Action B"))
self.actionSub_menu.setToolTip(_translate("MainWindow", "submenu"))
self.actionAction_C.setText(_translate("MainWindow", "Action &C"))

View File

@ -1,94 +0,0 @@
#!/usr/bin/env python
#
# The MIT License (MIT)
#
# Copyright (c) <2013-2014> <Colin Duquesnoy>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
"""
A simple example of use.
Load an ui made in QtDesigner and apply the DarkStyleSheet.
Requirements:
- Python 2 or Python 3
- PyQt4
.. note.. :: qdarkstyle does not have to be installed to run
the example
"""
import logging
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QFile, QTextStream
# make the example runnable without the need to install
import example
import breeze_resources
def main():
"""
Application entry point
"""
logging.basicConfig(level=logging.DEBUG)
# create the application and the main window
app = QtWidgets.QApplication(sys.argv)
#app.setStyle(QtWidgets.QStyleFactory.create("fusion"))
window = QtWidgets.QMainWindow()
# setup ui
ui = example.Ui_MainWindow()
ui.setupUi(window)
ui.bt_delay_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
ui.bt_instant_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
ui.bt_menu_button_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
window.setWindowTitle("Breeze example")
# tabify dock widgets to show bug #6
window.tabifyDockWidget(ui.dockWidget1, ui.dockWidget2)
# setup stylesheet
file = QFile(":/light.qss")
file.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(file)
app.setStyleSheet(stream.readAll())
# auto quit after 2s when testing on travis-ci
if "--travis" in sys.argv:
QtCore.QTimer.singleShot(2000, app.exit)
# run
window.show()
app.exec_()
if __name__ == "__main__":
main()

View File

@ -1,87 +0,0 @@
#!/usr/bin/env python
#
# The MIT License (MIT)
#
# Copyright (c) <2013-2014> <Colin Duquesnoy>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
"""
A simple example of use.
Load an ui made in QtDesigner and apply the DarkStyleSheet.
Requirements:
- Python 2 or Python 3
- PyQt4
.. note.. :: qdarkstyle does not have to be installed to run
the example
"""
import logging
import sys
from PyQt5 import QtWidgets, QtCore
# make the example runnable without the need to install
import example
def main():
"""
Application entry point
"""
logging.basicConfig(level=logging.DEBUG)
# create the application and the main window
app = QtWidgets.QApplication(sys.argv)
#app.setStyle(QtWidgets.QStyleFactory.create("fusion"))
window = QtWidgets.QMainWindow()
# setup ui
ui = example.Ui_MainWindow()
ui.setupUi(window)
ui.bt_delay_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
ui.bt_instant_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
ui.bt_menu_button_popup.addActions([
ui.actionAction,
ui.actionAction_C
])
window.setWindowTitle("Native example")
# tabify dock widgets to show bug #6
window.tabifyDockWidget(ui.dockWidget1, ui.dockWidget2)
# auto quit after 2s when testing on travis-ci
if "--travis" in sys.argv:
QtCore.QTimer.singleShot(2000, app.exit)
# run
window.show()
app.exec_()
if __name__ == "__main__":
main()

View File

@ -1,473 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""QDarkStyle is a dark stylesheet for Python and Qt applications.
This module provides a function to transparently load the stylesheets
with the correct rc file.
First, start importing our module
.. code-block:: python
import qdarkstyle
Then you can get stylesheet provided by QDarkStyle for various Qt wrappers
as shown bellow
.. code-block:: python
# PySide
dark_stylesheet = qdarkstyle.load_stylesheet_pyside()
# PySide 2
dark_stylesheet = qdarkstyle.load_stylesheet_pyside2()
# PyQt4
dark_stylesheet = qdarkstyle.load_stylesheet_pyqt()
# PyQt5
dark_stylesheet = qdarkstyle.load_stylesheet_pyqt5()
Or from environment variables provided for QtPy or PyQtGraph, see
.. code-block:: python
# QtPy
dark_stylesheet = qdarkstyle.load_stylesheet_from_environment()
# PyQtGraph
dark_stylesheet = qdarkstyle.load_stylesheet_from_environment(is_pyqtgraph)
Finally, set your QApplication with it
.. code-block:: python
app.setStyleSheet(dark_stylesheet)
Enjoy!
"""
import logging
import os
import platform
import sys
import warnings
import copy
if sys.version_info >= (3, 4):
import importlib
__version__ = "2.6.8"
QT_BINDINGS = ['PyQt4', 'PyQt5', 'PySide', 'PySide2']
"""list: values of all Qt bindings to import."""
QT_ABSTRACTIONS = ['qtpy', 'pyqtgraph', 'Qt']
"""list: values of all Qt abstraction layers to import."""
QT4_IMPORT_API = ['QtCore', 'QtGui']
"""list: which subpackage to import for Qt4 API."""
QT5_IMPORT_API = ['QtCore', 'QtGui', 'QtWidgets']
"""list: which subpackage to import for Qt5 API."""
QT_API_VALUES = ['pyqt', 'pyqt5', 'pyside', 'pyside2']
"""list: values for QT_API environment variable used by QtPy."""
QT_LIB_VALUES = ['PyQt', 'PyQt5', 'PySide', 'PySide2']
"""list: values for PYQTGRAPH_QT_LIB environment variable used by PyQtGraph."""
QT_BINDING = 'Not set or nonexistent'
"""str: Qt binding in use."""
QT_ABSTRACTION = 'Not set or nonexistent'
"""str: Qt abstraction layer in use."""
def _logger():
return logging.getLogger('qdarkstyle')
def _qt_wrapper_import(qt_api):
"""
Check if Qt API defined can be imported.
:param qt_api: Qt API string to test import
:return load function fot given qt_api, otherwise empty string
"""
qt_wrapper = ''
loader = ""
try:
if qt_api == 'PyQt' or qt_api == 'pyqt':
import PyQt4
qt_wrapper = 'PyQt4'
loader = load_stylesheet_pyqt()
elif qt_api == 'PyQt5' or qt_api == 'pyqt5':
import PyQt5
qt_wrapper = 'PyQt5'
loader = load_stylesheet_pyqt5()
elif qt_api == 'PySide' or qt_api == 'pyside':
import PySide
qt_wrapper = 'PySide'
loader = load_stylesheet_pyside()
elif qt_api == 'PySide2' or qt_api == 'pyside2':
import PySide2
qt_wrapper = 'PySide2'
loader = load_stylesheet_pyside2()
except ImportError as err:
_logger().error("Impossible import Qt wrapper.\n %s", str(err))
else:
_logger().info("Using Qt wrapper = %s ", qt_wrapper)
QT_BINDING = qt_wrapper
finally:
return loader
def load_stylesheet_from_environment(is_pyqtgraph=False):
"""
Load the stylesheet from QT_API (or PYQTGRAPH_QT_LIB) environment variable.
:param is_pyqtgraph: True if it is to be set using PYQTGRAPH_QT_LIB
:raise KeyError: if QT_API/PYQTGRAPH_QT_LIB does not exist
:return the stylesheet string
"""
warnings.warn(
"load_stylesheet_from_environment() will be deprecated in version 3,"
"use load_stylesheet()",
PendingDeprecationWarning
)
qt_api = ''
pyqtgraph_qt_lib = ''
loader = ""
# Get values from QT_API
try:
qt_api = os.environ['QT_API']
except KeyError as err:
# Log this error just if using QT_API
if not is_pyqtgraph:
_logger().error("QT_API does not exist, do os.environ['QT_API']= "
"and choose one option from %s", QT_API_VALUES)
else:
if not is_pyqtgraph:
if qt_api in QT_API_VALUES:
QT_ABSTRACTION = "qtpy"
_logger().info("Found QT_API='%s'", qt_api)
loader = _qt_wrapper_import(qt_api)
else:
# Raise this error because the function need this key/value
raise KeyError("QT_API=%s is unknown, please use a value "
"from %s",
(qt_api, QT_API_VALUES))
# Get values from PYQTGRAPH_QT_LIB
try:
pyqtgraph_qt_lib = os.environ['PYQTGRAPH_QT_LIB']
except KeyError as err:
# Log this error just if using PYQTGRAPH_QT_LIB
if is_pyqtgraph:
_logger().error("PYQTGRAP_QT_API does not exist, do "
"os.environ['PYQTGRAPH_QT_LIB']= "
"and choose one option from %s",
QT_LIB_VALUES)
else:
if is_pyqtgraph:
if pyqtgraph_qt_lib in QT_LIB_VALUES:
QT_ABSTRACTION = "pyqtgraph"
_logger().info("Found PYQTGRAPH_QT_LIB='%s'", pyqtgraph_qt_lib)
loader = _qt_wrapper_import(pyqtgraph_qt_lib)
else:
# Raise this error because the function need this key/value
raise KeyError("PYQTGRAPH_QT_LIB=%s is unknown, please use a "
"value from %s", (
pyqtgraph_qt_lib,
QT_LIB_VALUES))
# Just a warning if both are set but differs each other
if qt_api and pyqtgraph_qt_lib:
if qt_api != pyqtgraph_qt_lib.lower():
_logger().warning("Both QT_API=%s and PYQTGRAPH_QT_LIB=%s are set, "
"but with different values, this could cause "
"some issues if using them in the same project!",
qt_api, pyqtgraph_qt_lib)
return loader
def load_stylesheet(pyside=True):
"""
Load the stylesheet. Takes care of importing the rc module.
:param pyside: True to load the pyside rc file, False to load the PyQt rc file
:return the stylesheet string
"""
warnings.warn(
"load_stylesheet() will not receive pyside parameter in version 3. "
"Set QtPy environment variable to specify the Qt binding insteady.",
PendingDeprecationWarning
)
# Smart import of the rc file
pyside_ver = None
if pyside:
# Detect the PySide version available
try:
import PySide
except ImportError: # Compatible with py27
import PySide2
pyside_ver = 2
else:
pyside_ver = 1
if pyside_ver == 1:
import qdarkstyle.pyside_style_rc
else:
import qdarkstyle.pyside2_style_rc
else:
import qdarkstyle.pyqt_style_rc
# Load the stylesheet content from resources
if not pyside:
from PyQt4.QtCore import QFile, QTextStream
else:
if pyside_ver == 1:
from PySide.QtCore import QFile, QTextStream
else:
from PySide2.QtCore import QFile, QTextStream
f = QFile(":qdarkstyle/style.qss")
if not f.exists():
_logger().error("Unable to load stylesheet, file not found in "
"resources")
return ""
else:
f.open(QFile.ReadOnly | QFile.Text)
ts = QTextStream(f)
stylesheet = ts.readAll()
if platform.system().lower() == 'darwin': # see issue #12 on github
mac_fix = '''
QDockWidget::title
{
background-color: #32414B;
text-align: center;
height: 12px;
}
'''
stylesheet += mac_fix
return stylesheet
def load_stylesheet_pyside():
"""
Load the stylesheet for use in a pyside application.
:return the stylesheet string
"""
warnings.warn(
"load_stylesheet_pyside() will be deprecated in version 3,"
"set QtPy environment variable to specify the Qt binding and "
"use load_stylesheet()",
PendingDeprecationWarning
)
return load_stylesheet(pyside=True)
def load_stylesheet_pyside2():
"""
Load the stylesheet for use in a pyside2 application.
:raise NotImplementedError: Because it is not supported yet
"""
warnings.warn(
"load_stylesheet_pyside2() will be deprecated in version 3,"
"set QtPy environment variable to specify the Qt binding and "
"use load_stylesheet()",
PendingDeprecationWarning
)
return load_stylesheet(pyside=True)
def load_stylesheet_pyqt():
"""
Load the stylesheet for use in a pyqt4 application.
:return the stylesheet string
"""
warnings.warn(
"load_stylesheet_pyqt() will be deprecated in version 3,"
"set QtPy environment variable to specify the Qt binding and "
"use load_stylesheet()",
PendingDeprecationWarning
)
return load_stylesheet(pyside=False)
def load_stylesheet_pyqt5():
"""
Load the stylesheet for use in a pyqt5 application.
:param pyside: True to load the pyside rc file, False to load the PyQt rc file
:return the stylesheet string
"""
warnings.warn(
"load_stylesheet_pyqt5() will be deprecated in version 3,"
"set QtPy environment variable to specify the Qt binding and "
"use load_stylesheet()",
PendingDeprecationWarning
)
# Smart import of the rc file
import qdarkstyle.pyqt5_style_rc
# Load the stylesheet content from resources
from PyQt5.QtCore import QFile, QTextStream
f = QFile(":qdarkstyle/style.qss")
if not f.exists():
_logger().error("Unable to load stylesheet, file not found in "
"resources")
return ""
else:
f.open(QFile.ReadOnly | QFile.Text)
ts = QTextStream(f)
stylesheet = ts.readAll()
if platform.system().lower() == 'darwin': # see issue #12 on github
mac_fix = '''
QDockWidget::title
{
background-color: #32414B;
text-align: center;
height: 12px;
}
'''
stylesheet += mac_fix
return stylesheet
def information():
"""Get system and runtime information."""
info = []
qt_api = ''
qt_lib = ''
qt_bin = ''
try:
qt_api = os.environ['QT_API']
except KeyError:
qt_api = 'Not set or nonexistent'
try:
from Qt import __binding__
except Exception:
# It should be (KeyError, ModuleNotFoundError, ImportError)
# but each python version have a different one, and not define others
qt_lib = 'Not set or nonexistent'
else:
qt_lib = __binding__
try:
qt_bin = os.environ['PYQTGRAPH_QT_LIB']
except KeyError:
qt_bin = 'Not set or nonexistent'
info.append('QDarkStyle: %s' % __version__)
info.append('OS: %s %s %s' % (platform.system(), platform.release(), platform.machine()))
info.append('Platform: %s' % sys.platform)
info.append('Python: %s' % '.'.join(str(e) for e in sys.version_info[:]))
info.append('Python API: %s' % sys.api_version)
info.append('Binding in use: %s' % QT_BINDING)
info.append('Abstraction in use: %s' % QT_ABSTRACTION)
info.append('qtpy (QT_API): %s' % qt_api)
info.append('pyqtgraph (PYQTGRAPH_QT_LIB): %s' % qt_lib)
info.append('Qt.py (__binding__): %s' % qt_bin)
return info
def qt_bindings():
"""Return a list of qt bindings available."""
return _check_imports(import_list=QT_BINDINGS)
def qt_abstractions():
"""Return a list of qt abstraction layers available."""
return _check_imports(import_list=QT_ABSTRACTIONS)
def _check_imports(import_list):
"""Return a list of imports available."""
# Disable warnings here
warnings.filterwarnings("ignore")
import_list_return = copy.deepcopy(import_list)
# Using import_list_return var in for, does not work in py2.7
# when removing the element, it reflects on for list
# so it skips next element
for current_import in import_list:
spec = True
# Copy the sys path to make sure to not insert anything
sys_path = sys.path
# Check import
if sys.version_info >= (3, 4):
spec = importlib.util.find_spec(current_import)
else:
try:
__import__(current_import)
except RuntimeWarning:
spec = True
except Exception:
spec = None
else:
spec = True
if spec is None:
# Remove if not available
import_list_return.remove(current_import)
# Restore sys path
sys.path = sys_path
# Restore warnings
warnings.resetwarnings()
return import_list_return
def _import_qt_modules_from(use_binding='pyqt5', use_abstraction='qtpy'):
"""New approach to import modules using importlib."""
if not sys.version_info >= (3, 4):
print('Function not available for Python < 3.4')
spec_binding = importlib.util.find_spec(use_binding)
spec_abstraction = importlib.util.find_spec(use_abstraction)
if spec_binding is None:
print("Cannot find Qt binding: ", use_binding)
else:
module = importlib.util.module_from_spec(spec_binding)
spec.loader.exec_module(module)
# Adding the module to sys.modules is optional.
sys.modules[name] = module
if spec_abstraction is None:
print("Cannot find Qt abstraction layer: ", use_abstraction)
else:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Adding the module to sys.modules is optional.
sys.modules[name] = module

View File

@ -1,65 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from qdarkstyle import qt_bindings, qt_abstractions, information, __version__
import qdarkstyle
import argparse
import sys
from os.path import abspath, dirname
sys.path.insert(0, abspath(dirname(abspath(__file__)) + '/..'))
def print_list_md(info):
"""Print a list of information, line by line."""
for item in info:
print(' - ' + item)
def main():
"""Execute QDarkStyle example."""
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-i', '--information', action='store_true',
help="Show information about environment (important for bug report)")
parser.add_argument('-b', '--bindings', action='store_true',
help="Show available bindings for Qt")
parser.add_argument('-a', '--abstractions', action='store_true',
help="Show available abstraction layers for Qt bindings")
# parser.add_argument('-e', '--example', action='store_true',
# help="Show qdarkstyle example, subcommand.")
parser.add_argument('-v', '--version', action='store_true',
help="Show qdarkstyle version")
parser.add_argument('--all', action='store_true',
help="Show all information options at once")
# parsing arguments from command line
args = parser.parse_args()
parser.print_help()
if args.information or args.all:
info = information()
print('\nInformation about your current environment setup:')
print_list_md(info)
if args.bindings or args.all:
info = qt_bindings()
print('\nQt bindings available:')
print_list_md(info)
if args.abstractions or args.all:
info = qt_abstractions()
print('\nQt abstraction layers available:')
print_list_md(info)
if args.version:
info = __version__
print('\nVersion: %s' % info)
# if args.example:
# example.main()
if __name__ == "__main__":
sys.exit(main())

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -211,7 +211,7 @@
<context>
<name>ClipboardUploader</name>
<message>
<location filename="../src/uploaders/default/clipboarduploader.cpp" line="18"/>
<location filename="../src/uploaders/default/clipboarduploader.cpp" line="19"/>
<source>Copied to clipboard!</source>
<translation>In die Zwischenablage kopiert!</translation>
</message>
@ -340,150 +340,150 @@
<context>
<name>CustomUploader</name>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="34"/>
<location filename="../src/uploaders/customuploader.cpp" line="33"/>
<source>Root not an object</source>
<translation>Root (Wurzel) ist kein JSON Objekt</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="38"/>
<location filename="../src/uploaders/customuploader.cpp" line="37"/>
<source>name is not a string</source>
<translation>&quot;name&quot; ist keine Zeichenkette</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="43"/>
<location filename="../src/uploaders/customuploader.cpp" line="42"/>
<source>desc not a string</source>
<translation>&quot;desc&quot; ist keine Zeichenkette</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="51"/>
<location filename="../src/uploaders/customuploader.cpp" line="50"/>
<source>method not a string</source>
<translation>&quot;method&quot; ist keine Zeichenkette</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="56"/>
<location filename="../src/uploaders/customuploader.cpp" line="55"/>
<source>method invalid</source>
<translation>&quot;method&quot; ist ungültig</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="60"/>
<location filename="../src/uploaders/customuploader.cpp" line="59"/>
<source>target missing</source>
<translation>Das Ziel fehlt</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="63"/>
<location filename="../src/uploaders/customuploader.cpp" line="62"/>
<source>target not URL</source>
<translation>Das Ziel ist keine URL</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="78"/>
<location filename="../src/uploaders/customuploader.cpp" line="77"/>
<source>format invalid</source>
<translation>&quot;format&quot; ist ungültig</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="81"/>
<location filename="../src/uploaders/customuploader.cpp" line="80"/>
<source>format provided but not string</source>
<translation>&quot;format&quot; ist keine Zeichenkette</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="84"/>
<location filename="../src/uploaders/customuploader.cpp" line="83"/>
<source>body not set</source>
<translation>Die Antwort hatte keinen &quot;body&quot;</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="88"/>
<location filename="../src/uploaders/customuploader.cpp" line="87"/>
<source>all elements of body must be objects</source>
<translation>Alle Teile des &quot;body&quot;s müssen Objekte sein</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="90"/>
<location filename="../src/uploaders/customuploader.cpp" line="89"/>
<source>all parts must have a body which is object or string!</source>
<translation>Alle Teile müssen einen &quot;body&quot; haben, welcher eine Zeichenkette oder ein Objekt ist!</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="94"/>
<location filename="../src/uploaders/customuploader.cpp" line="93"/>
<source>all parts of body must be string or object</source>
<translation>Alle Teile des &quot;body&quot;s müssen eine Zeichenkette oder ein Objekt sein</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="98"/>
<location filename="../src/uploaders/customuploader.cpp" line="97"/>
<source>all __headers must be strings</source>
<translation>Alle mit &quot;__&quot; beginnenden Kopfzeilen müssen Zeichenketten sein</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="102"/>
<location filename="../src/uploaders/customuploader.cpp" line="101"/>
<source>body not array (needed for multipart)</source>
<translation>Der &quot;body&quot;ist kein Array (für &quot;multipart&quot; benötigt)</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="107"/>
<location filename="../src/uploaders/customuploader.cpp" line="106"/>
<source>body not object</source>
<translation>Der &quot;body&quot; ist kein Objekt</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="114"/>
<location filename="../src/uploaders/customuploader.cpp" line="113"/>
<source>body not string (reason: format: PLAIN)</source>
<extracomment>`format: PLAIN` should stay the same</extracomment>
<translation>Antwort &quot;body&quot; ist keine Zeichenkette (Grund: &quot;format: PLAIN&quot;)</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="118"/>
<location filename="../src/uploaders/customuploader.cpp" line="117"/>
<source>headers must be object</source>
<translation>&quot;headers&quot; ist kein JSON Objekt</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="126"/>
<location filename="../src/uploaders/customuploader.cpp" line="125"/>
<source>return invalid</source>
<translation>Antwort ungültig</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="130"/>
<location filename="../src/uploaders/customuploader.cpp" line="129"/>
<source>fileLimit not decimal</source>
<extracomment>fileLimit stays English</extracomment>
<translation>&quot;fileLimit&quot; ist keine Dezimalzahl</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="135"/>
<location filename="../src/uploaders/customuploader.cpp" line="134"/>
<source>base64 must be boolean</source>
<translation>Base64 muss ein Wahrheitswert sein</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="137"/>
<location filename="../src/uploaders/customuploader.cpp" line="136"/>
<source>base64 required with json</source>
<translation>Base64 für JSON benötigt</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="220"/>
<location filename="../src/uploaders/customuploader.cpp" line="223"/>
<location filename="../src/uploaders/customuploader.cpp" line="229"/>
<location filename="../src/uploaders/customuploader.cpp" line="353"/>
<location filename="../src/uploaders/customuploader.cpp" line="371"/>
<location filename="../src/uploaders/customuploader.cpp" line="381"/>
<location filename="../src/uploaders/customuploader.cpp" line="219"/>
<location filename="../src/uploaders/customuploader.cpp" line="222"/>
<location filename="../src/uploaders/customuploader.cpp" line="228"/>
<location filename="../src/uploaders/customuploader.cpp" line="352"/>
<location filename="../src/uploaders/customuploader.cpp" line="370"/>
<location filename="../src/uploaders/customuploader.cpp" line="380"/>
<source>KShare Custom Uploader </source>
<translation>KShare benutzerdefinierter Uploader </translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="220"/>
<location filename="../src/uploaders/customuploader.cpp" line="219"/>
<source>Copied upload link to clipboard!</source>
<translation>Link in die Zwischenablage kopiert!</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="223"/>
<location filename="../src/uploaders/customuploader.cpp" line="222"/>
<source>Upload done, but result empty!</source>
<translation>Hochgeladen, aber eine leere Antwort erhalten!</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="230"/>
<location filename="../src/uploaders/customuploader.cpp" line="229"/>
<source>Upload done, but result is not JSON Object! Result in clipboard.</source>
<translation>Hochgeladen, aber die Antwort war kein JSON-Objekt! Die Antwort wurde in die Zwischenablage kopiert.</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="354"/>
<location filename="../src/uploaders/customuploader.cpp" line="381"/>
<location filename="../src/uploaders/customuploader.cpp" line="353"/>
<location filename="../src/uploaders/customuploader.cpp" line="380"/>
<source>Copied upload result to clipboard!</source>
<translation>Ergebnis in die Zwischenablage kopiert!</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="371"/>
<location filename="../src/uploaders/customuploader.cpp" line="370"/>
<source>File limit exceeded!</source>
<translation>Dateigröße überschritten!</translation>
</message>
@ -657,7 +657,7 @@ p, li { white-space: pre-wrap; }
<name>ImgurUploader</name>
<message>
<location filename="../src/uploaders/default/imguruploader.cpp" line="59"/>
<location filename="../src/uploaders/default/imguruploader.cpp" line="96"/>
<location filename="../src/uploaders/default/imguruploader.cpp" line="95"/>
<source>KShare imgur Uploader</source>
<translation>KShare imgur Uploader</translation>
</message>
@ -667,17 +667,17 @@ p, li { white-space: pre-wrap; }
<translation>Hochladen fehlgeschlagen! Das Bild überschreitet die maximale Größe</translation>
</message>
<message>
<location filename="../src/uploaders/default/imguruploader.cpp" line="96"/>
<location filename="../src/uploaders/default/imguruploader.cpp" line="95"/>
<source>Uploaded to imgur!</source>
<translation>Auf imgur hochgeladen!</translation>
</message>
<message>
<location filename="../src/uploaders/default/imguruploader.cpp" line="99"/>
<location filename="../src/uploaders/default/imguruploader.cpp" line="100"/>
<source>KShare imgur Uploader </source>
<translation>KShare imgur Uploader </translation>
</message>
<message>
<location filename="../src/uploaders/default/imguruploader.cpp" line="100"/>
<location filename="../src/uploaders/default/imguruploader.cpp" line="101"/>
<source>Failed upload! imgur said: HTTP %1: %2</source>
<translation>Hochladen fehlgeschlagen! Imgur hat hiermit geantwortet: &quot;HTTP %1:%2&quot;</translation>
</message>
@ -746,7 +746,7 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<location filename="../src/mainwindow.ui" line="85"/>
<location filename="../src/mainwindow.cpp" line="94"/>
<location filename="../src/mainwindow.cpp" line="99"/>
<source>About</source>
<translation type="unfinished">Über</translation>
</message>
@ -836,75 +836,75 @@ p, li { white-space: pre-wrap; }
<translation type="unfinished">&amp;Breche Aufnahme ab</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="39"/>
<location filename="../src/mainwindow.cpp" line="44"/>
<source>Recording format not set in settings. Aborting.</source>
<translation>Das Format für die Aufnahmen wurde nicht in den Einstellungen definiert. Aufnahme wird abgebrochen.</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="93"/>
<location filename="../src/mainwindow.cpp" line="98"/>
<source>Quit</source>
<translation>Beenden</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="71"/>
<location filename="../src/mainwindow.cpp" line="76"/>
<source>Show/Hide</source>
<translation>Zeigen / Verstecken</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="72"/>
<location filename="../src/mainwindow.cpp" line="77"/>
<source>Take fullscreen shot</source>
<translation>Screenshot des ganzen Bildschirms</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="73"/>
<location filename="../src/mainwindow.cpp" line="78"/>
<source>Take area shot</source>
<translation>Screenshot eines Gebietes</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="76"/>
<location filename="../src/mainwindow.cpp" line="81"/>
<source>Screenshot active window</source>
<translation>Screenshot des aktiven Fensters</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="79"/>
<location filename="../src/mainwindow.cpp" line="84"/>
<source>Copy from Clipbaord</source>
<translation type="unfinished">Zwischenablage hochladen</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="80"/>
<location filename="../src/mainwindow.cpp" line="85"/>
<source>Show color picker</source>
<translation>Zeige die Farbpipette</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="81"/>
<location filename="../src/mainwindow.cpp" line="86"/>
<source>Record screen</source>
<translation>Bildschirm aufnehmen</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="82"/>
<location filename="../src/mainwindow.cpp" line="87"/>
<source>Stop recording</source>
<translation>Stoppe Aufnahme</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="83"/>
<location filename="../src/mainwindow.cpp" line="88"/>
<source>Abort recording</source>
<translation>Breche Aufnahme ab</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="238"/>
<location filename="../src/mainwindow.cpp" line="272"/>
<location filename="../src/mainwindow.cpp" line="275"/>
<location filename="../src/mainwindow.cpp" line="309"/>
<source>Cannot determine location for pictures</source>
<translation type="unfinished">Die Position des Ordners für Bilder kann nicht bestimmt werden</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="243"/>
<location filename="../src/mainwindow.cpp" line="277"/>
<location filename="../src/mainwindow.cpp" line="280"/>
<location filename="../src/mainwindow.cpp" line="314"/>
<source>Cannot determine location of your home directory</source>
<translation type="unfinished">Die Position des Benutzerverzeichnisses kann nicht bestimmt werden</translation>
</message>
<message>
<location filename="../src/mainwindow.cpp" line="248"/>
<location filename="../src/mainwindow.cpp" line="282"/>
<location filename="../src/mainwindow.cpp" line="285"/>
<location filename="../src/mainwindow.cpp" line="319"/>
<source>Invalid config [saveLocation not int or is not in range]</source>
<translation type="unfinished">Ungültige Config (Speicherziel ist keine natürliche Zahl oder nicht in einem gültigen Bereich)</translation>
</message>
@ -923,7 +923,7 @@ p, li { white-space: pre-wrap; }
<translation>Konnte den Ordner für die Konfigurationsdateien nicht erstellen</translation>
</message>
<message>
<location filename="../src/uploaders/customuploader.cpp" line="25"/>
<location filename="../src/uploaders/customuploader.cpp" line="24"/>
<source>Invalid file: </source>
<translation>Ungültige Datei: </translation>
</message>
@ -971,6 +971,11 @@ p, li { white-space: pre-wrap; }
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/notifications.cpp" line="56"/>
<source>KShare: No sound driver</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RecordingFormats</name>
@ -1098,166 +1103,236 @@ Stopptaste: %3</translation>
<translation>Zuschneideeditor Einstellungen</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="39"/>
<location filename="../src/settingsdialog.ui" line="34"/>
<source>General</source>
<translatorcomment>Allgemein</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="42"/>
<source>Theme</source>
<translatorcomment>Erscheinungsbild</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="50"/>
<source>System Default</source>
<translation type="unfinished">System</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="55"/>
<source>QDarkStyle</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="60"/>
<source>Breeze Light</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="65"/>
<source>Breeze Dark</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="73"/>
<source>Quick mode (mouse release screenshots)</source>
<translation>Schneller Modus (Maus loslassen reicht)</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="70"/>
<location filename="../src/settingsdialog.ui" line="94"/>
<source>Delay before taking a screenshot</source>
<translation>Verzögerung vor einem Screenshot</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="26"/>
<location filename="../src/settingsdialog.ui" line="101"/>
<source>In seconds</source>
<translation>In Sekunden</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="29"/>
<location filename="../src/settingsdialog.ui" line="104"/>
<source>A delay before taking a screenshot, in seconds</source>
<translation>Verzögerung vor einem Screenshot in Sekunden</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="46"/>
<location filename="../src/settingsdialog.ui" line="124"/>
<source>Hoster</source>
<translation type="unfinished">Hoster</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="152"/>
<source>Paths</source>
<translation type="unfinished">Pfade</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="160"/>
<source>File name scheme</source>
<translation type="unfinished">Dateibennenung</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="180"/>
<source>Screenshot Subfolder</source>
<translation type="unfinished">Unterordnermuster</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="187"/>
<source>%(yyyy-MM)date</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="223"/>
<source>Recording</source>
<translatorcomment>Aufzeichnung</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="348"/>
<source>Fullscreen capture command (save to %FILE_PATH or print to stdout)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="53"/>
<location filename="../src/settingsdialog.ui" line="138"/>
<source>Hotkeys</source>
<translation>Hotkeys</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="60"/>
<location filename="../src/settingsdialog.ui" line="297"/>
<source>Still image format</source>
<translation>Format für Bilder</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="77"/>
<location filename="../src/settingsdialog.ui" line="290"/>
<source>Recording format</source>
<translation>Aufnahmeformate</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="84"/>
<location filename="../src/settingsdialog.ui" line="87"/>
<source>Capture cursor</source>
<translation>Mauszeiger aufnehmen</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="91"/>
<location filename="../src/settingsdialog.ui" line="170"/>
<source>%(date format)date and %ext are supported</source>
<translation>%(Datumsformat)Datum ujnd %ext werden unterstützt</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="108"/>
<source>File name scheme:</source>
<translation>Benennungsschema:</translation>
<translation type="vanished">Benennungsschema:</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="115"/>
<location filename="../src/settingsdialog.ui" line="80"/>
<source>Pressing &lt;X&gt; hides to tray</source>
<translation>Drücke &lt;X&gt; um dieses Fenster in die Taskleiste zu minimieren</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="133"/>
<location filename="../src/settingsdialog.ui" line="212"/>
<source>Do not save</source>
<translation type="unfinished"></translation>
<translation>Nicht speichern</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="141"/>
<location filename="../src/settingsdialog.ui" line="116"/>
<source>Open settings directory</source>
<translation>Öffne Konfigurationsordner</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="148"/>
<source>Destination:</source>
<translation>Speicherziel:</translation>
<translation type="vanished">Speicherziel:</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="244"/>
<location filename="../src/settingsdialog.ui" line="355"/>
<source>Focused capture command (save to %FILE_PATH or print to stdout)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="123"/>
<location filename="../src/settingsdialog.ui" line="202"/>
<source>Pictures folder</source>
<translation>Ordner für Bilder</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="128"/>
<location filename="../src/settingsdialog.ui" line="207"/>
<source>Screenshots folder (In your user folder)</source>
<translation>Screenshot ordner (In deinem Benutzerordner)</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="165"/>
<location filename="../src/settingsdialog.ui" line="194"/>
<source>File save location</source>
<translation>Speicherort für Bilder</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="172"/>
<location filename="../src/settingsdialog.ui" line="229"/>
<location filename="../src/settingsdialog.ui" line="340"/>
<source>Advanced</source>
<translation>Erweiterte Einstellungen</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="207"/>
<location filename="../src/settingsdialog.ui" line="264"/>
<source>Editor Position (tweak if the editor does not cover the entire screen)</source>
<translation>Editor Position (Ändern, wenn nicht der ganzen Bildschirm ausgefüllt ist)</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="214"/>
<location filename="../src/settingsdialog.ui" line="271"/>
<source>Encoder settings</source>
<translation>Kodierer Einstellungen</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="224"/>
<location filename="../src/settingsdialog.ui" line="314"/>
<source>FPS</source>
<translation type="unfinished"></translation>
<translation>FPS</translation>
</message>
<message>
<location filename="../src/settingsdialog.ui" line="234"/>
<location filename="../src/settingsdialog.ui" line="307"/>
<source>Frames Per Second For Recording</source>
<translation type="unfinished"></translation>
<translation>FPS für Aufnahmen</translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="56"/>
<location filename="../src/settingsdialog.cpp" line="58"/>
<source>Fullscreen image</source>
<translation>Screenshot des ganzen Bildschirms</translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="57"/>
<location filename="../src/settingsdialog.cpp" line="59"/>
<source>Area image</source>
<translation>Screenshot eines Gebietes</translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="59"/>
<location filename="../src/settingsdialog.cpp" line="61"/>
<source>Active window</source>
<translation>Screenshot des aktiven Fensters</translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="61"/>
<location filename="../src/settingsdialog.cpp" line="63"/>
<source>Copy from Clipboard</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="62"/>
<location filename="../src/settingsdialog.cpp" line="64"/>
<source>Color picker</source>
<translation>Farbpipette</translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="63"/>
<location filename="../src/settingsdialog.cpp" line="65"/>
<source>Stop Recording</source>
<translation>Stoppe Aufnahme</translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="64"/>
<location filename="../src/settingsdialog.cpp" line="66"/>
<source>Start Recording</source>
<translation>Starte Aufnahme</translation>
</message>
<message>
<location filename="../src/settingsdialog.cpp" line="86"/>
<location filename="../src/settingsdialog.cpp" line="89"/>
<source>Capture cursor (disabled: implementation missing)</source>
<translation>Mauszeiger aufnehmen (Deaktiviert: Implementierung fehlt)</translation>
</message>
</context>
<context>
<name>SystemNotification</name>
<message>
<location filename="../src/systemnotification.cpp" line="29"/>
<source>KShare Info</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TextItem</name>
<message>
@ -1274,39 +1349,39 @@ Stopptaste: %3</translation>
<context>
<name>UploaderSingleton</name>
<message>
<location filename="../src/uploaders/uploadersingleton.cpp" line="127"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="128"/>
<source>KShare - Failed to open File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/uploaders/uploadersingleton.cpp" line="167"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="180"/>
<source>Cannot determine location for pictures</source>
<translation>Die Position des Ordners für Bilder kann nicht bestimmt werden</translation>
</message>
<message>
<location filename="../src/uploaders/uploadersingleton.cpp" line="172"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="185"/>
<source>Cannot determine location of your home directory</source>
<translation>Die Position des Benutzerverzeichnisses kann nicht bestimmt werden</translation>
</message>
<message>
<location filename="../src/uploaders/uploadersingleton.cpp" line="177"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="190"/>
<source>Invalid config [saveLocation not int or is not in range]</source>
<translation>Ungültige Config (Speicherziel ist keine natürliche Zahl oder nicht in einem gültigen Bereich)</translation>
</message>
<message>
<location filename="../src/uploaders/uploadersingleton.cpp" line="50"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="51"/>
<source>Ambigious uploader </source>
<translation>Unklarer Uploadername </translation>
</message>
<message>
<location filename="../src/uploaders/uploadersingleton.cpp" line="61"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="62"/>
<source>Currently selected uploader is not set up properly! Falling back to imgur</source>
<translation>Ausgewählter Uploader ist nicht korrekt eingestellt! Nutze imgur als Ersatz</translation>
</message>
<message>
<location filename="../src/uploaders/uploadersingleton.cpp" line="79"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="115"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="117"/>
<location filename="../src/uploaders/uploadersingleton.cpp" line="119"/>
<source>KShare - Failed to save picture</source>
<translation>KShare - Speichern des Bildes fehlgeschlagen</translation>
</message>