From 4b701ac8aabf0c5248af0e2f52186ac66d21f8c6 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Fri, 22 Feb 2019 08:56:01 +0800 Subject: [PATCH 01/60] First PR --- .gitignore | 3 +++ README.md | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 894a44cc..7826430f 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,6 @@ venv.bak/ # mypy .mypy_cache/ + +# IDEA workspace +.idea/ diff --git a/README.md b/README.md index 697c2bf7..76bf1833 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ You should be using [Pipenv](https://pipenv.readthedocs.io/en/latest/). Take a l * Running the application (assuming you use our project layout): `pipenv run start` # Project Information +##### Team Name +Knowledgeable Kois `# TODO` From 9b29bed967e34372227df07ecc301dde6901bec5 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Fri, 22 Feb 2019 19:45:52 +0800 Subject: [PATCH 02/60] Add pytest for unit testing and sphinx for docs as dependencies --- .gitignore | 3 + Pipfile | 7 +- Pipfile.lock | 207 +++++++++++++++++++++++++++++++++- README.md | 13 +++ docs/Makefile | 19 ++++ docs/make.bat | 35 ++++++ docs/source/conf.py | 178 +++++++++++++++++++++++++++++ docs/source/index.rst | 20 ++++ docs/source/modules.rst | 8 ++ docs/source/tests.rst | 22 ++++ docs/source/utils.rst | 7 ++ project/__main__.py | 5 + project/tests/__init__.py | 0 project/tests/test_example.py | 38 +++++++ project/utils.py | 11 ++ 15 files changed, 571 insertions(+), 2 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst create mode 100644 docs/source/modules.rst create mode 100644 docs/source/tests.rst create mode 100644 docs/source/utils.rst create mode 100644 project/tests/__init__.py create mode 100644 project/tests/test_example.py create mode 100644 project/utils.py diff --git a/.gitignore b/.gitignore index 7826430f..a86f590e 100644 --- a/.gitignore +++ b/.gitignore @@ -105,3 +105,6 @@ venv.bak/ # IDEA workspace .idea/ + +# compiled sphinx HTML documentation +docs/build diff --git a/Pipfile b/Pipfile index 72b70b6f..4aea9ebc 100644 --- a/Pipfile +++ b/Pipfile @@ -5,6 +5,8 @@ verify_ssl = true [dev-packages] flake8 = "*" +pytest = "*" +sphinx = "*" [packages] @@ -12,4 +14,7 @@ flake8 = "*" python_version = "3.7" [scripts] -lint = "python -m flake8" \ No newline at end of file +lint = "python -m flake8" +start = "python -m project" +test = "pytest project/tests/" +gendoc = "pydoc -g" diff --git a/Pipfile.lock b/Pipfile.lock index 79354a3c..7daa74b7 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a376db0bd471e38a7080cd854c46349b46922db98afeaf83d17b84923fbe9710" + "sha256": "56d7e03b04f77118c08c4eb19d8d650f865ebd8a771b1c2dad8415204cbf2b25" }, "pipfile-spec": 6, "requires": { @@ -17,6 +17,56 @@ }, "default": {}, "develop": { + "alabaster": { + "hashes": [ + "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", + "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" + ], + "version": "==0.7.12" + }, + "atomicwrites": { + "hashes": [ + "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", + "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" + ], + "version": "==1.3.0" + }, + "attrs": { + "hashes": [ + "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", + "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb" + ], + "version": "==18.2.0" + }, + "babel": { + "hashes": [ + "sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669", + "sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23" + ], + "version": "==2.6.0" + }, + "certifi": { + "hashes": [ + "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", + "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" + ], + "version": "==2018.11.29" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "docutils": { + "hashes": [ + "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", + "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", + "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + ], + "version": "==0.14" + }, "entrypoints": { "hashes": [ "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", @@ -32,6 +82,60 @@ "index": "pypi", "version": "==3.7.6" }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "imagesize": { + "hashes": [ + "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", + "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5" + ], + "version": "==1.1.0" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "markupsafe": { + "hashes": [ + "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", + "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", + "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", + "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", + "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", + "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", + "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", + "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", + "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", + "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", + "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", + "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", + "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", + "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", + "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", + "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", + "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", + "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", + "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", + "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", + "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", + "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", + "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", + "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", + "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", + "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", + "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", + "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" + ], + "version": "==1.1.0" + }, "mccabe": { "hashes": [ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", @@ -39,6 +143,35 @@ ], "version": "==0.6.1" }, + "more-itertools": { + "hashes": [ + "sha256:0125e8f60e9e031347105eb1682cef932f5e97d7b9a1a28d9bf00c22a5daef40", + "sha256:590044e3942351a1bdb1de960b739ff4ce277960f2425ad4509446dbace8d9d1" + ], + "markers": "python_version > '2.7'", + "version": "==6.0.0" + }, + "packaging": { + "hashes": [ + "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", + "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3" + ], + "version": "==19.0" + }, + "pluggy": { + "hashes": [ + "sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616", + "sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a" + ], + "version": "==0.8.1" + }, + "py": { + "hashes": [ + "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", + "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" + ], + "version": "==1.8.0" + }, "pycodestyle": { "hashes": [ "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", @@ -52,6 +185,78 @@ "sha256:f277f9ca3e55de669fba45b7393a1449009cff5a37d1af10ebb76c52765269cd" ], "version": "==2.1.0" + }, + "pygments": { + "hashes": [ + "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", + "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d" + ], + "version": "==2.3.1" + }, + "pyparsing": { + "hashes": [ + "sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a", + "sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3" + ], + "version": "==2.3.1" + }, + "pytest": { + "hashes": [ + "sha256:067a1d4bf827ffdd56ad21bd46674703fce77c5957f6c1eef731f6146bfcef1c", + "sha256:9687049d53695ad45cf5fdc7bbd51f0c49f1ea3ecfc4b7f3fde7501b541f17f4" + ], + "index": "pypi", + "version": "==4.3.0" + }, + "pytz": { + "hashes": [ + "sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9", + "sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c" + ], + "version": "==2018.9" + }, + "requests": { + "hashes": [ + "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", + "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + ], + "version": "==2.21.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "snowballstemmer": { + "hashes": [ + "sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", + "sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89" + ], + "version": "==1.2.1" + }, + "sphinx": { + "hashes": [ + "sha256:b53904fa7cb4b06a39409a492b949193a1b68cc7241a1a8ce9974f86f0d24287", + "sha256:c1c00fc4f6e8b101a0d037065043460dffc2d507257f2f11acaed71fd2b0c83c" + ], + "index": "pypi", + "version": "==1.8.4" + }, + "sphinxcontrib-websupport": { + "hashes": [ + "sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd", + "sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9" + ], + "version": "==1.1.0" + }, + "urllib3": { + "hashes": [ + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + ], + "version": "==1.24.1" } } } diff --git a/README.md b/README.md index 76bf1833..e392a059 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,19 @@ Knowledgeable Kois `# TODO` +Unit tests are written using the [pytest](https://docs.pytest.org/en/latest/) framework. + +`pipenv run test` runs the available tests. + ## How do I use this thing? `# TODO` + +## Documentation + +Documentation is generated using [Sphinx](http://www.sphinx-doc.org/en/master/). To build: +```sh +cd docs +sphinx-apidoc -f -o source/ ../project/ +make html +``` \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..69fe55ec --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..543c6b13 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..11d77ae8 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../../project')) + + +# -- Project information ----------------------------------------------------- + +project = 'Knowledgeable Kois - CodeJam 4' +copyright = '2019, The Team' +author = 'The Team' + +# The short X.Y version +version = '' +# The full version, including alpha/beta/rc tags +release = '' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.coverage', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'KnowledgeableKois-CodeJam4doc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'KnowledgeableKois-CodeJam4.tex', 'Knowledgeable Kois - CodeJam 4 Documentation', + 'The Team', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'knowledgeablekois-codejam4', 'Knowledgeable Kois - CodeJam 4 Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'KnowledgeableKois-CodeJam4', 'Knowledgeable Kois - CodeJam 4 Documentation', + author, 'KnowledgeableKois-CodeJam4', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + + +# -- Extension configuration ------------------------------------------------- diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..71b5a8f5 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,20 @@ +.. Knowledgeable Kois - CodeJam 4 documentation master file, created by + sphinx-quickstart on Fri Feb 22 19:29:14 2019. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Knowledgeable Kois - CodeJam 4's documentation! +========================================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 00000000..8bd9ed5d --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,8 @@ +project +======= + +.. toctree:: + :maxdepth: 4 + + tests + utils diff --git a/docs/source/tests.rst b/docs/source/tests.rst new file mode 100644 index 00000000..ba78f1e3 --- /dev/null +++ b/docs/source/tests.rst @@ -0,0 +1,22 @@ +tests package +============= + +Submodules +---------- + +tests.test\_example module +-------------------------- + +.. automodule:: tests.test_example + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: tests + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/utils.rst b/docs/source/utils.rst new file mode 100644 index 00000000..87aedafa --- /dev/null +++ b/docs/source/utils.rst @@ -0,0 +1,7 @@ +utils module +============ + +.. automodule:: utils + :members: + :undoc-members: + :show-inheritance: diff --git a/project/__main__.py b/project/__main__.py index e69de29b..d721de4f 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -0,0 +1,5 @@ +import sys +from .utils import add + +print("hello %s" % sys.argv[1]) +print(add(2, 2)) diff --git a/project/tests/__init__.py b/project/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/project/tests/test_example.py b/project/tests/test_example.py new file mode 100644 index 00000000..4890919e --- /dev/null +++ b/project/tests/test_example.py @@ -0,0 +1,38 @@ +""" +.. module:: utils + :synopsis: File containing constants and static functions. + +.. moduleauthor:: Bryan Kok +""" + +import pytest + + +@pytest.fixture +def error_fixture(): + assert 0 + + +def test_ok(): + print("ok") + + +def test_fail(): + assert 0 + + +def test_error(error_fixture): + pass + + +def test_skip(): + pytest.skip("skipping this test") + + +def test_xfail(): + pytest.xfail("xfailing this test") + + +@pytest.mark.xfail(reason="always xfail") +def test_xpass(): + pass diff --git a/project/utils.py b/project/utils.py new file mode 100644 index 00000000..c823a84b --- /dev/null +++ b/project/utils.py @@ -0,0 +1,11 @@ +""" +.. module:: utils + :synopsis: File containing constants and static functions. + +.. moduleauthor:: Bryan Kok +""" + + +def add(x, y): + """Adds two numbers.""" + return 5 From 49130499dee0ecfbd473a353dc325ba8f7d34646 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Fri, 22 Feb 2019 20:23:23 +0800 Subject: [PATCH 03/60] Fix linting issue --- docs/source/conf.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 11d77ae8..02663392 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -130,7 +130,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'KnowledgeableKois-CodeJam4.tex', 'Knowledgeable Kois - CodeJam 4 Documentation', + (master_doc, 'KnowledgeableKois-CodeJam4.tex', + 'Knowledgeable Kois - CodeJam 4 Documentation', 'The Team', 'manual'), ] @@ -140,7 +141,8 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'knowledgeablekois-codejam4', 'Knowledgeable Kois - CodeJam 4 Documentation', + (master_doc, 'knowledgeablekois-codejam4', + 'Knowledgeable Kois - CodeJam 4 Documentation', [author], 1) ] @@ -151,7 +153,8 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'KnowledgeableKois-CodeJam4', 'Knowledgeable Kois - CodeJam 4 Documentation', + (master_doc, 'KnowledgeableKois-CodeJam4', + 'Knowledgeable Kois - CodeJam 4 Documentation', author, 'KnowledgeableKois-CodeJam4', 'One line description of project.', 'Miscellaneous'), ] From 18a7fc5b602c155e75e430933916256ec8db1014 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Fri, 22 Feb 2019 20:00:17 -0800 Subject: [PATCH 04/60] Create filename.py --- work in progress/filename.py | 106 +++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 work in progress/filename.py diff --git a/work in progress/filename.py b/work in progress/filename.py new file mode 100644 index 00000000..16caad4b --- /dev/null +++ b/work in progress/filename.py @@ -0,0 +1,106 @@ +'''sorry for not adding comments or making code look nice, it was generated by designer :0''' + + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(640, 481) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.Add = QtWidgets.QPushButton(self.centralwidget) + self.Add.setGeometry(QtCore.QRect(0, 0, 51, 20)) + self.Add.clicked.connect(self.add_item) + self.Add.setObjectName("Add") + self.Remove = QtWidgets.QPushButton(self.centralwidget) + self.Remove.setGeometry(QtCore.QRect(50, 0, 61, 20)) + self.Remove.setObjectName("Remove") + self.Edit = QtWidgets.QPushButton(self.centralwidget) + self.Edit.setGeometry(QtCore.QRect(110, 0, 51, 20)) + self.Edit.setObjectName("Edit") + self.MoveUp = QtWidgets.QPushButton(self.centralwidget) + self.MoveUp.setGeometry(QtCore.QRect(160, 0, 71, 20)) + self.MoveUp.setObjectName("MoveUp") + self.MoveDown = QtWidgets.QPushButton(self.centralwidget) + self.MoveDown.setGeometry(QtCore.QRect(230, 0, 71, 20)) + self.MoveDown.setObjectName("MoveDown") + self.Objects = QtWidgets.QListWidget(self.centralwidget) + self.Objects.setGeometry(QtCore.QRect(0, 21, 641, 441)) + self.Objects.setObjectName("Objects") + item = QtWidgets.QListWidgetItem() + self.Objects.addItem(item) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile.setObjectName("menuFile") + self.menuPlugins = QtWidgets.QMenu(self.menubar) + self.menuPlugins.setObjectName("menuPlugins") + self.menuItem = QtWidgets.QMenu(self.menubar) + self.menuItem.setObjectName("menuItem") + MainWindow.setMenuBar(self.menubar) + self.actionAdd = QtWidgets.QAction(MainWindow) + self.actionAdd.setObjectName("actionAdd") + self.actionDelete = QtWidgets.QAction(MainWindow) + self.actionDelete.setObjectName("actionDelete") + self.action_todo = QtWidgets.QAction(MainWindow) + self.action_todo.setObjectName("action_todo") + self.actionSettings = QtWidgets.QAction(MainWindow) + self.actionSettings.setObjectName("actionSettings") + self.actionAdd_2 = QtWidgets.QAction(MainWindow) + self.actionAdd_2.setObjectName("actionAdd_2") + self.actionRemove = QtWidgets.QAction(MainWindow) + self.actionRemove.setObjectName("actionRemove") + self.menuFile.addAction(self.actionSettings) + self.menuPlugins.addAction(self.action_todo) + self.menuItem.addAction(self.actionAdd_2) + self.menuItem.addAction(self.actionRemove) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuPlugins.menuAction()) + self.menubar.addAction(self.menuItem.menuAction()) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.Add.setText(_translate("MainWindow", "Add")) + self.Remove.setText(_translate("MainWindow", "Remove")) + self.Edit.setText(_translate("MainWindow", "Edit")) + self.MoveUp.setText(_translate("MainWindow", "Move Up")) + self.MoveDown.setText(_translate("MainWindow", " Move Down")) + + + __sortingEnabled = self.Objects.isSortingEnabled() + self.Objects.setSortingEnabled(False) + item = self.Objects.item(0) + item.setText(_translate("MainWindow", "New Item")) + self.Objects.setSortingEnabled(__sortingEnabled) + + + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) + self.menuItem.setTitle(_translate("MainWindow", "Items")) + self.actionAdd.setText(_translate("MainWindow", "Add")) + self.actionDelete.setText(_translate("MainWindow", "Delete")) + self.action_todo.setText(_translate("MainWindow", "Install #todo")) + self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) + self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) + self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + + def add_item(self): + item = self.Objects.item(0) + item.setText("MainWindow", "New Item") + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + MainWindow = QtWidgets.QMainWindow() + ui = Ui_MainWindow() + ui.setupUi(MainWindow) + MainWindow.show() + sys.exit(app.exec_()) + From 45f33a26c6f41dcfa61440bd40d1485d2c23cd3d Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sat, 23 Feb 2019 12:28:19 +0800 Subject: [PATCH 05/60] Begin structuring the project and display a QMainWindow --- Pipfile | 1 + Pipfile.lock | 32 ++++- docs/source/ClipboardManager.rst | 30 +++++ docs/source/PluginManager.rst | 22 ++++ docs/source/Stack.rst | 22 ++++ docs/source/Widgets.rst | 10 ++ docs/source/conf.py | 3 +- docs/source/modules.rst | 4 + project/ClipboardManager/ClipboardManager.py | 15 +++ project/ClipboardManager/HistoryManager.py | 7 ++ project/ClipboardManager/__init__.py | 2 + project/PluginManager/PluginManager.py | 0 project/PluginManager/__init__.py | 0 project/Stack/Stack.py | 61 ++++++++++ project/Stack/__init__.py | 2 + project/Widgets/__init__.py | 0 project/__main__.py | 119 ++++++++++++++++++- project/utils.py | 6 + 18 files changed, 330 insertions(+), 6 deletions(-) create mode 100644 docs/source/ClipboardManager.rst create mode 100644 docs/source/PluginManager.rst create mode 100644 docs/source/Stack.rst create mode 100644 docs/source/Widgets.rst create mode 100644 project/ClipboardManager/ClipboardManager.py create mode 100644 project/ClipboardManager/HistoryManager.py create mode 100644 project/ClipboardManager/__init__.py create mode 100644 project/PluginManager/PluginManager.py create mode 100644 project/PluginManager/__init__.py create mode 100644 project/Stack/Stack.py create mode 100644 project/Stack/__init__.py create mode 100644 project/Widgets/__init__.py diff --git a/Pipfile b/Pipfile index 4aea9ebc..6f335661 100644 --- a/Pipfile +++ b/Pipfile @@ -9,6 +9,7 @@ pytest = "*" sphinx = "*" [packages] +pyqt5 = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 7daa74b7..26e45bdd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "56d7e03b04f77118c08c4eb19d8d650f865ebd8a771b1c2dad8415204cbf2b25" + "sha256": "ce2c7c13183491802df185b32bd2fad6bc367bcb8983c77391117376d2e30e9e" }, "pipfile-spec": 6, "requires": { @@ -15,7 +15,35 @@ } ] }, - "default": {}, + "default": { + "pyqt5": { + "hashes": [ + "sha256:1402f1613698ca64e3cec0ee27a60b5454e782c16fbd1bdee4a270a058947939", + "sha256:8872c78f204bf8b660164d6dfae87e1be5a9dbc3e20fd2823bd4e851b3647eba", + "sha256:912ead29f8ed86be178faeb2be83793fb633c11059ae54c3bd8e81c1e224e339", + "sha256:acbefac6c780f04709441aa7d8a147c0801f01f8db93f8f000e4a4391db27345" + ], + "index": "pypi", + "version": "==5.12" + }, + "pyqt5-sip": { + "hashes": [ + "sha256:04bd0bb8b6f8fa03c2dfbdfff0c8c9bfb3f46a21dd4cac73983dae93bf949523", + "sha256:058d450c26be92193605f4628ff690d77080f599ffe381a1029cea8eeb71ab8e", + "sha256:0b838ef8a55461785e78b4e347cf52ce228a5d4392c57e07cc46de51433dc8ac", + "sha256:40504f96ecb834e54491ead558589bfd773056dba7f2df76599a06fdd8ed1ead", + "sha256:49b2151bd0a0e439efc9d4c22c33a048d8e8ede5c7296851c221fa0988887edb", + "sha256:6540b510f9436fe2d65801af55ecbf8c43bdda47294e994ed3851403a93e4a8b", + "sha256:6b3063b12e700944172d57cdbeafb363229669af933f873d01c7a6d8a91c4c87", + "sha256:6b65d2b14084eb583bf4cf68b97ade295fabae5f5bf2aae0ab00ab30533f1c60", + "sha256:6ca796071b21761917ee486e57bfa2fc694580e65c462e4173cf849ed8fe201c", + "sha256:6d3013a6820ea614f46fdc73cc16dd57c36a0c74bcbd38bd0b9f2d46b6e6dd16", + "sha256:84f7401afdd5f31e961de75e9c6b1610849e8883fbe0ed675bbb7d7d97286347", + "sha256:bb81cfc4d35ca59f1c419b6abeb6ca6a726a63b712cf979f2b5ab24b81c36f49" + ], + "version": "==4.19.14" + } + }, "develop": { "alabaster": { "hashes": [ diff --git a/docs/source/ClipboardManager.rst b/docs/source/ClipboardManager.rst new file mode 100644 index 00000000..583f8969 --- /dev/null +++ b/docs/source/ClipboardManager.rst @@ -0,0 +1,30 @@ +ClipboardManager package +======================== + +Submodules +---------- + +ClipboardManager.ClipboardManager module +---------------------------------------- + +.. automodule:: ClipboardManager.ClipboardManager + :members: + :undoc-members: + :show-inheritance: + +ClipboardManager.HistoryManager module +-------------------------------------- + +.. automodule:: ClipboardManager.HistoryManager + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: ClipboardManager + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/PluginManager.rst b/docs/source/PluginManager.rst new file mode 100644 index 00000000..c14c5cc4 --- /dev/null +++ b/docs/source/PluginManager.rst @@ -0,0 +1,22 @@ +PluginManager package +===================== + +Submodules +---------- + +PluginManager.PluginManager module +---------------------------------- + +.. automodule:: PluginManager.PluginManager + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: PluginManager + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/Stack.rst b/docs/source/Stack.rst new file mode 100644 index 00000000..a69825d5 --- /dev/null +++ b/docs/source/Stack.rst @@ -0,0 +1,22 @@ +Stack package +============= + +Submodules +---------- + +Stack.Stack module +------------------ + +.. automodule:: Stack.Stack + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: Stack + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/Widgets.rst b/docs/source/Widgets.rst new file mode 100644 index 00000000..7d387afa --- /dev/null +++ b/docs/source/Widgets.rst @@ -0,0 +1,10 @@ +Widgets package +=============== + +Module contents +--------------- + +.. automodule:: Widgets + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/conf.py b/docs/source/conf.py index 02663392..90a4627f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -14,7 +14,8 @@ # import os import sys -sys.path.insert(0, os.path.abspath('../../project')) +sys.path.insert(0, os.path.abspath('../../')) +sys.path.insert(1, os.path.abspath('../../project')) # -- Project information ----------------------------------------------------- diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 8bd9ed5d..12d360d3 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -4,5 +4,9 @@ project .. toctree:: :maxdepth: 4 + ClipboardManager + PluginManager + Stack + Widgets tests utils diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py new file mode 100644 index 00000000..7a756deb --- /dev/null +++ b/project/ClipboardManager/ClipboardManager.py @@ -0,0 +1,15 @@ +"""Class encapsulating clipboard events""" +from PyQt5.Qt import QApplication, QClipboard # noqa: F401 +from project.Stack import Stack + + +def _clipboard_changed(): + print("Current Text", QApplication.clipboard().text()) + print("Current Image Info", QApplication.clipboard().pixmap()) + + +class ClipboardManager: + + def __init__(self): + QApplication.clipboard().dataChanged.connect(_clipboard_changed) + self._clipboard_stack = Stack() diff --git a/project/ClipboardManager/HistoryManager.py b/project/ClipboardManager/HistoryManager.py new file mode 100644 index 00000000..d9f27a49 --- /dev/null +++ b/project/ClipboardManager/HistoryManager.py @@ -0,0 +1,7 @@ +""" +.. module:: HistoryManager + :synopsis: Persists and loads the state of the clipboard \ + and history upon app close. + +.. moduleauthor:: TBD +""" diff --git a/project/ClipboardManager/__init__.py b/project/ClipboardManager/__init__.py new file mode 100644 index 00000000..009f2596 --- /dev/null +++ b/project/ClipboardManager/__init__.py @@ -0,0 +1,2 @@ + +from .ClipboardManager import ClipboardManager # noqa: F401 diff --git a/project/PluginManager/PluginManager.py b/project/PluginManager/PluginManager.py new file mode 100644 index 00000000..e69de29b diff --git a/project/PluginManager/__init__.py b/project/PluginManager/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/project/Stack/Stack.py b/project/Stack/Stack.py new file mode 100644 index 00000000..fd898b8c --- /dev/null +++ b/project/Stack/Stack.py @@ -0,0 +1,61 @@ +""" +.. module:: Stack + :synopsis: Class encapsulating the behavior of the stack. + +.. moduleauthor:: Bryan Kok +""" +import enum + + +class Stack: + class SHIFT_DIRECTION(enum.Enum): + UP: 1 + DOWN: 2 + + def __init__(self, existing_stack=None, cur_stack_pointer=None): + if existing_stack: + self._stack = existing_stack + else: + self._stack = [] + + if cur_stack_pointer: + self._stack_pointer = cur_stack_pointer + else: + # By default the stack pointer is at the top of the stack + self._stack_pointer = len(self._stack) - 1 + + def items(self): + return self._stack + + def set_current_item(self, idx): + if not 0 <= idx < len(self._stack): + raise Exception("Index is out of bounds") + + self._stack_pointer = idx + + def shift_current_item(self, idx, shift_direction: SHIFT_DIRECTION): + _temp = self._stack[self._stack_pointer] + if shift_direction == Stack.SHIFT_DIRECTION.UP: + self._stack[idx] = self._stack[idx + 1] + self._stack[idx + 1] = _temp + + elif shift_direction == Stack.SHIFT_DIRECTION.DOWN: + self._stack[idx] = self._stack[idx - 1] + self._stack[idx - 1] = _temp + + def swap_items(self, idx, target_idx): + _temp = self._stack[idx] + self._stack[idx] = self._stack[target_idx] + self._stack[target_idx] = _temp + + def push_item(self, item): + self._stack.append(item) + + def peek(self): + return self._stack[-1] + + def pop(self): + return self._stack.pop() + + def clear(self): + self._stack = [] diff --git a/project/Stack/__init__.py b/project/Stack/__init__.py new file mode 100644 index 00000000..8a92fdf4 --- /dev/null +++ b/project/Stack/__init__.py @@ -0,0 +1,2 @@ + +from .Stack import Stack # noqa: F401 diff --git a/project/Widgets/__init__.py b/project/Widgets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/project/__main__.py b/project/__main__.py index d721de4f..92805135 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,5 +1,118 @@ +from PyQt5.QtWidgets import QMainWindow, QApplication + import sys -from .utils import add -print("hello %s" % sys.argv[1]) -print(add(2, 2)) +from project import ClipboardManager +from .utils import CONSTANTS + +from PyQt5 import QtCore, QtWidgets + + +# print("hello %s" % sys.argv[1]) +# print(add(2, 2)) + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + self.title = CONSTANTS['NAME'] + # self.left = 10 + # self.top = 10 + # self.width = 640 + # self.height = 480 + self._init_ui() + + def _init_ui(self): + self.setWindowTitle(self.title) + # self.setGeometry(self.left, self.top, self.width, self.height) + self.setupUi() + self.show() + + def setupUi(self): + # MainWindow.setObjectName("MainWindow") + self.resize(640, 480) + self.centralwidget = QtWidgets.QWidget(self) + self.centralwidget.setObjectName("centralwidget") + self.Add = QtWidgets.QPushButton(self.centralwidget) + self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + self.Add.setObjectName("Add") + self.Remove = QtWidgets.QPushButton(self.centralwidget) + self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) + self.Remove.setObjectName("Remove") + self.Edit = QtWidgets.QPushButton(self.centralwidget) + self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) + self.Edit.setObjectName("Edit") + self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget) + self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) + self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.treeWidget.setObjectName("treeWidget") + # item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) + self.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(self) + self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile.setObjectName("menuFile") + self.menuPlugins = QtWidgets.QMenu(self.menubar) + self.menuPlugins.setObjectName("menuPlugins") + self.menuItem = QtWidgets.QMenu(self.menubar) + self.menuItem.setObjectName("menuItem") + self.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(self) + self.statusbar.setObjectName("statusbar") + self.setStatusBar(self.statusbar) + self.actionAdd = QtWidgets.QAction(self) + self.actionAdd.setObjectName("actionAdd") + self.actionDelete = QtWidgets.QAction(self) + self.actionDelete.setObjectName("actionDelete") + self.action_todo = QtWidgets.QAction(self) + self.action_todo.setObjectName("action_todo") + self.actionSettings = QtWidgets.QAction(self) + self.actionSettings.setObjectName("actionSettings") + self.actionAdd_2 = QtWidgets.QAction(self) + self.actionAdd_2.setObjectName("actionAdd_2") + self.actionRemove = QtWidgets.QAction(self) + self.actionRemove.setObjectName("actionRemove") + self.menuFile.addAction(self.actionSettings) + self.menuPlugins.addAction(self.action_todo) + self.menuItem.addAction(self.actionAdd_2) + self.menuItem.addAction(self.actionRemove) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuPlugins.menuAction()) + self.menubar.addAction(self.menuItem.menuAction()) + + self.retranslateUi() + QtCore.QMetaObject.connectSlotsByName(self) + + def retranslateUi(self): + _translate = QtCore.QCoreApplication.translate + # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.Add.setText(_translate("MainWindow", "Add")) + self.Remove.setText(_translate("MainWindow", "Remove")) + self.Edit.setText(_translate("MainWindow", "Edit")) + self.treeWidget.headerItem()\ + .setText(0, _translate("MainWindow", "Items:")) + __sortingEnabled = self.treeWidget.isSortingEnabled() + self.treeWidget.setSortingEnabled(False) + self.treeWidget.topLevelItem(0)\ + .setText(0, _translate("MainWindow", "Test copy")) + self.treeWidget.setSortingEnabled(__sortingEnabled) + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) + self.menuItem.setTitle(_translate("MainWindow", "Items")) + self.actionAdd.setText(_translate("MainWindow", "Add")) + self.actionDelete.setText(_translate("MainWindow", "Delete")) + self.action_todo.setText(_translate("MainWindow", "Install #todo")) + self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) + self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) + self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + # label = QLabel('Hello World!') + # label.show() + + clipboard_mgr = ClipboardManager.ClipboardManager() + main_window = MainWindow() + + sys.exit(app.exec_()) diff --git a/project/utils.py b/project/utils.py index c823a84b..754fe938 100644 --- a/project/utils.py +++ b/project/utils.py @@ -9,3 +9,9 @@ def add(x, y): """Adds two numbers.""" return 5 + + +CONSTANTS = { + 'NAME': 'Clipboard Mangler', + 'HISTORY_MAX_ITEMS': 10, +} From f77f6708616e99545adabaccaa8c7ae19d586666 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sat, 23 Feb 2019 12:35:01 +0800 Subject: [PATCH 06/60] Add an item to TreeWidget to show the dummy interface --- project/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/__main__.py b/project/__main__.py index 92805135..356fa3d8 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -45,7 +45,7 @@ def setupUi(self): self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) self.treeWidget.setObjectName("treeWidget") - # item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) + item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) self.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) From 8347faa82da4b596405a76fdc6fcc79b0566c7cd Mon Sep 17 00:00:00 2001 From: BWACpro Date: Fri, 22 Feb 2019 20:58:01 -0800 Subject: [PATCH 07/60] renamed file --- {work in progress => work in progress by BWAC}/filename.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {work in progress => work in progress by BWAC}/filename.py (100%) diff --git a/work in progress/filename.py b/work in progress by BWAC/filename.py similarity index 100% rename from work in progress/filename.py rename to work in progress by BWAC/filename.py From 02ff84aa3503b76a4ca17b9de9f9c15f0454c096 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Fri, 22 Feb 2019 21:08:05 -0800 Subject: [PATCH 08/60] mm? --- work in progress by BWAC/filename.py | 106 ------------ .../.ui files/untitled.ui | 163 ++++++++++++++++++ .../ClipboardManager/ClipboardManager.py | 15 ++ .../ClipboardManager/HistoryManager.py | 7 + .../project/ClipboardManager/__init__.py | 2 + .../project/PluginManager/PluginManager.py | 0 .../project/PluginManager/__init__.py | 0 .../project/Stack/Stack.py | 61 +++++++ .../project/Stack/__init__.py | 2 + .../project/Widgets/__init__.py | 0 work_in_progress_by_BWAC/project/__main__.py | 118 +++++++++++++ .../project/tests/__init__.py | 0 .../project/tests/test_example.py | 38 ++++ work_in_progress_by_BWAC/project/utils.py | 17 ++ 14 files changed, 423 insertions(+), 106 deletions(-) delete mode 100644 work in progress by BWAC/filename.py create mode 100644 work_in_progress_by_BWAC/.ui files/untitled.ui create mode 100644 work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py create mode 100644 work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py create mode 100644 work_in_progress_by_BWAC/project/ClipboardManager/__init__.py create mode 100644 work_in_progress_by_BWAC/project/PluginManager/PluginManager.py create mode 100644 work_in_progress_by_BWAC/project/PluginManager/__init__.py create mode 100644 work_in_progress_by_BWAC/project/Stack/Stack.py create mode 100644 work_in_progress_by_BWAC/project/Stack/__init__.py create mode 100644 work_in_progress_by_BWAC/project/Widgets/__init__.py create mode 100644 work_in_progress_by_BWAC/project/__main__.py create mode 100644 work_in_progress_by_BWAC/project/tests/__init__.py create mode 100644 work_in_progress_by_BWAC/project/tests/test_example.py create mode 100644 work_in_progress_by_BWAC/project/utils.py diff --git a/work in progress by BWAC/filename.py b/work in progress by BWAC/filename.py deleted file mode 100644 index 16caad4b..00000000 --- a/work in progress by BWAC/filename.py +++ /dev/null @@ -1,106 +0,0 @@ -'''sorry for not adding comments or making code look nice, it was generated by designer :0''' - - -from PyQt5 import QtCore, QtGui, QtWidgets - -class Ui_MainWindow(object): - def setupUi(self, MainWindow): - MainWindow.setObjectName("MainWindow") - MainWindow.resize(640, 481) - self.centralwidget = QtWidgets.QWidget(MainWindow) - self.centralwidget.setObjectName("centralwidget") - self.Add = QtWidgets.QPushButton(self.centralwidget) - self.Add.setGeometry(QtCore.QRect(0, 0, 51, 20)) - self.Add.clicked.connect(self.add_item) - self.Add.setObjectName("Add") - self.Remove = QtWidgets.QPushButton(self.centralwidget) - self.Remove.setGeometry(QtCore.QRect(50, 0, 61, 20)) - self.Remove.setObjectName("Remove") - self.Edit = QtWidgets.QPushButton(self.centralwidget) - self.Edit.setGeometry(QtCore.QRect(110, 0, 51, 20)) - self.Edit.setObjectName("Edit") - self.MoveUp = QtWidgets.QPushButton(self.centralwidget) - self.MoveUp.setGeometry(QtCore.QRect(160, 0, 71, 20)) - self.MoveUp.setObjectName("MoveUp") - self.MoveDown = QtWidgets.QPushButton(self.centralwidget) - self.MoveDown.setGeometry(QtCore.QRect(230, 0, 71, 20)) - self.MoveDown.setObjectName("MoveDown") - self.Objects = QtWidgets.QListWidget(self.centralwidget) - self.Objects.setGeometry(QtCore.QRect(0, 21, 641, 441)) - self.Objects.setObjectName("Objects") - item = QtWidgets.QListWidgetItem() - self.Objects.addItem(item) - MainWindow.setCentralWidget(self.centralwidget) - self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) - self.menubar.setObjectName("menubar") - self.menuFile = QtWidgets.QMenu(self.menubar) - self.menuFile.setObjectName("menuFile") - self.menuPlugins = QtWidgets.QMenu(self.menubar) - self.menuPlugins.setObjectName("menuPlugins") - self.menuItem = QtWidgets.QMenu(self.menubar) - self.menuItem.setObjectName("menuItem") - MainWindow.setMenuBar(self.menubar) - self.actionAdd = QtWidgets.QAction(MainWindow) - self.actionAdd.setObjectName("actionAdd") - self.actionDelete = QtWidgets.QAction(MainWindow) - self.actionDelete.setObjectName("actionDelete") - self.action_todo = QtWidgets.QAction(MainWindow) - self.action_todo.setObjectName("action_todo") - self.actionSettings = QtWidgets.QAction(MainWindow) - self.actionSettings.setObjectName("actionSettings") - self.actionAdd_2 = QtWidgets.QAction(MainWindow) - self.actionAdd_2.setObjectName("actionAdd_2") - self.actionRemove = QtWidgets.QAction(MainWindow) - self.actionRemove.setObjectName("actionRemove") - self.menuFile.addAction(self.actionSettings) - self.menuPlugins.addAction(self.action_todo) - self.menuItem.addAction(self.actionAdd_2) - self.menuItem.addAction(self.actionRemove) - self.menubar.addAction(self.menuFile.menuAction()) - self.menubar.addAction(self.menuPlugins.menuAction()) - self.menubar.addAction(self.menuItem.menuAction()) - - self.retranslateUi(MainWindow) - QtCore.QMetaObject.connectSlotsByName(MainWindow) - - def retranslateUi(self, MainWindow): - _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.Add.setText(_translate("MainWindow", "Add")) - self.Remove.setText(_translate("MainWindow", "Remove")) - self.Edit.setText(_translate("MainWindow", "Edit")) - self.MoveUp.setText(_translate("MainWindow", "Move Up")) - self.MoveDown.setText(_translate("MainWindow", " Move Down")) - - - __sortingEnabled = self.Objects.isSortingEnabled() - self.Objects.setSortingEnabled(False) - item = self.Objects.item(0) - item.setText(_translate("MainWindow", "New Item")) - self.Objects.setSortingEnabled(__sortingEnabled) - - - self.menuFile.setTitle(_translate("MainWindow", "File")) - self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) - self.menuItem.setTitle(_translate("MainWindow", "Items")) - self.actionAdd.setText(_translate("MainWindow", "Add")) - self.actionDelete.setText(_translate("MainWindow", "Delete")) - self.action_todo.setText(_translate("MainWindow", "Install #todo")) - self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) - self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) - self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) - - def add_item(self): - item = self.Objects.item(0) - item.setText("MainWindow", "New Item") - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - MainWindow = QtWidgets.QMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) - diff --git a/work_in_progress_by_BWAC/.ui files/untitled.ui b/work_in_progress_by_BWAC/.ui files/untitled.ui new file mode 100644 index 00000000..c6c81993 --- /dev/null +++ b/work_in_progress_by_BWAC/.ui files/untitled.ui @@ -0,0 +1,163 @@ + + + MainWindow + + + + 0 + 0 + 640 + 481 + + + + MainWindow + + + + + + 0 + 0 + 51 + 20 + + + + Add + + + + + + 50 + 0 + 61 + 20 + + + + Remove + + + + + + 110 + 0 + 51 + 20 + + + + Edit + + + + + + 160 + 0 + 71 + 20 + + + + Move Up + + + + + + 230 + 0 + 71 + 20 + + + + Move Down + + + + + + 0 + 21 + 641 + 441 + + + + + New Item + + + + + + + + 0 + 0 + 640 + 21 + + + + + File + + + + + + Plugins + + + + + + Items + + + + + + + + + + + Add + + + + + Delete + + + + + Install #todo + + + + + Settings #todo + + + + + Add #todo + + + + + Remove #todo + + + + + + diff --git a/work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py b/work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py new file mode 100644 index 00000000..7a756deb --- /dev/null +++ b/work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py @@ -0,0 +1,15 @@ +"""Class encapsulating clipboard events""" +from PyQt5.Qt import QApplication, QClipboard # noqa: F401 +from project.Stack import Stack + + +def _clipboard_changed(): + print("Current Text", QApplication.clipboard().text()) + print("Current Image Info", QApplication.clipboard().pixmap()) + + +class ClipboardManager: + + def __init__(self): + QApplication.clipboard().dataChanged.connect(_clipboard_changed) + self._clipboard_stack = Stack() diff --git a/work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py b/work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py new file mode 100644 index 00000000..d9f27a49 --- /dev/null +++ b/work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py @@ -0,0 +1,7 @@ +""" +.. module:: HistoryManager + :synopsis: Persists and loads the state of the clipboard \ + and history upon app close. + +.. moduleauthor:: TBD +""" diff --git a/work_in_progress_by_BWAC/project/ClipboardManager/__init__.py b/work_in_progress_by_BWAC/project/ClipboardManager/__init__.py new file mode 100644 index 00000000..009f2596 --- /dev/null +++ b/work_in_progress_by_BWAC/project/ClipboardManager/__init__.py @@ -0,0 +1,2 @@ + +from .ClipboardManager import ClipboardManager # noqa: F401 diff --git a/work_in_progress_by_BWAC/project/PluginManager/PluginManager.py b/work_in_progress_by_BWAC/project/PluginManager/PluginManager.py new file mode 100644 index 00000000..e69de29b diff --git a/work_in_progress_by_BWAC/project/PluginManager/__init__.py b/work_in_progress_by_BWAC/project/PluginManager/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/work_in_progress_by_BWAC/project/Stack/Stack.py b/work_in_progress_by_BWAC/project/Stack/Stack.py new file mode 100644 index 00000000..fd898b8c --- /dev/null +++ b/work_in_progress_by_BWAC/project/Stack/Stack.py @@ -0,0 +1,61 @@ +""" +.. module:: Stack + :synopsis: Class encapsulating the behavior of the stack. + +.. moduleauthor:: Bryan Kok +""" +import enum + + +class Stack: + class SHIFT_DIRECTION(enum.Enum): + UP: 1 + DOWN: 2 + + def __init__(self, existing_stack=None, cur_stack_pointer=None): + if existing_stack: + self._stack = existing_stack + else: + self._stack = [] + + if cur_stack_pointer: + self._stack_pointer = cur_stack_pointer + else: + # By default the stack pointer is at the top of the stack + self._stack_pointer = len(self._stack) - 1 + + def items(self): + return self._stack + + def set_current_item(self, idx): + if not 0 <= idx < len(self._stack): + raise Exception("Index is out of bounds") + + self._stack_pointer = idx + + def shift_current_item(self, idx, shift_direction: SHIFT_DIRECTION): + _temp = self._stack[self._stack_pointer] + if shift_direction == Stack.SHIFT_DIRECTION.UP: + self._stack[idx] = self._stack[idx + 1] + self._stack[idx + 1] = _temp + + elif shift_direction == Stack.SHIFT_DIRECTION.DOWN: + self._stack[idx] = self._stack[idx - 1] + self._stack[idx - 1] = _temp + + def swap_items(self, idx, target_idx): + _temp = self._stack[idx] + self._stack[idx] = self._stack[target_idx] + self._stack[target_idx] = _temp + + def push_item(self, item): + self._stack.append(item) + + def peek(self): + return self._stack[-1] + + def pop(self): + return self._stack.pop() + + def clear(self): + self._stack = [] diff --git a/work_in_progress_by_BWAC/project/Stack/__init__.py b/work_in_progress_by_BWAC/project/Stack/__init__.py new file mode 100644 index 00000000..8a92fdf4 --- /dev/null +++ b/work_in_progress_by_BWAC/project/Stack/__init__.py @@ -0,0 +1,2 @@ + +from .Stack import Stack # noqa: F401 diff --git a/work_in_progress_by_BWAC/project/Widgets/__init__.py b/work_in_progress_by_BWAC/project/Widgets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/work_in_progress_by_BWAC/project/__main__.py b/work_in_progress_by_BWAC/project/__main__.py new file mode 100644 index 00000000..356fa3d8 --- /dev/null +++ b/work_in_progress_by_BWAC/project/__main__.py @@ -0,0 +1,118 @@ +from PyQt5.QtWidgets import QMainWindow, QApplication + +import sys + +from project import ClipboardManager +from .utils import CONSTANTS + +from PyQt5 import QtCore, QtWidgets + + +# print("hello %s" % sys.argv[1]) +# print(add(2, 2)) + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + self.title = CONSTANTS['NAME'] + # self.left = 10 + # self.top = 10 + # self.width = 640 + # self.height = 480 + self._init_ui() + + def _init_ui(self): + self.setWindowTitle(self.title) + # self.setGeometry(self.left, self.top, self.width, self.height) + self.setupUi() + self.show() + + def setupUi(self): + # MainWindow.setObjectName("MainWindow") + self.resize(640, 480) + self.centralwidget = QtWidgets.QWidget(self) + self.centralwidget.setObjectName("centralwidget") + self.Add = QtWidgets.QPushButton(self.centralwidget) + self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + self.Add.setObjectName("Add") + self.Remove = QtWidgets.QPushButton(self.centralwidget) + self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) + self.Remove.setObjectName("Remove") + self.Edit = QtWidgets.QPushButton(self.centralwidget) + self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) + self.Edit.setObjectName("Edit") + self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget) + self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) + self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.treeWidget.setObjectName("treeWidget") + item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) + self.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(self) + self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile.setObjectName("menuFile") + self.menuPlugins = QtWidgets.QMenu(self.menubar) + self.menuPlugins.setObjectName("menuPlugins") + self.menuItem = QtWidgets.QMenu(self.menubar) + self.menuItem.setObjectName("menuItem") + self.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(self) + self.statusbar.setObjectName("statusbar") + self.setStatusBar(self.statusbar) + self.actionAdd = QtWidgets.QAction(self) + self.actionAdd.setObjectName("actionAdd") + self.actionDelete = QtWidgets.QAction(self) + self.actionDelete.setObjectName("actionDelete") + self.action_todo = QtWidgets.QAction(self) + self.action_todo.setObjectName("action_todo") + self.actionSettings = QtWidgets.QAction(self) + self.actionSettings.setObjectName("actionSettings") + self.actionAdd_2 = QtWidgets.QAction(self) + self.actionAdd_2.setObjectName("actionAdd_2") + self.actionRemove = QtWidgets.QAction(self) + self.actionRemove.setObjectName("actionRemove") + self.menuFile.addAction(self.actionSettings) + self.menuPlugins.addAction(self.action_todo) + self.menuItem.addAction(self.actionAdd_2) + self.menuItem.addAction(self.actionRemove) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuPlugins.menuAction()) + self.menubar.addAction(self.menuItem.menuAction()) + + self.retranslateUi() + QtCore.QMetaObject.connectSlotsByName(self) + + def retranslateUi(self): + _translate = QtCore.QCoreApplication.translate + # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.Add.setText(_translate("MainWindow", "Add")) + self.Remove.setText(_translate("MainWindow", "Remove")) + self.Edit.setText(_translate("MainWindow", "Edit")) + self.treeWidget.headerItem()\ + .setText(0, _translate("MainWindow", "Items:")) + __sortingEnabled = self.treeWidget.isSortingEnabled() + self.treeWidget.setSortingEnabled(False) + self.treeWidget.topLevelItem(0)\ + .setText(0, _translate("MainWindow", "Test copy")) + self.treeWidget.setSortingEnabled(__sortingEnabled) + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) + self.menuItem.setTitle(_translate("MainWindow", "Items")) + self.actionAdd.setText(_translate("MainWindow", "Add")) + self.actionDelete.setText(_translate("MainWindow", "Delete")) + self.action_todo.setText(_translate("MainWindow", "Install #todo")) + self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) + self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) + self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + # label = QLabel('Hello World!') + # label.show() + + clipboard_mgr = ClipboardManager.ClipboardManager() + main_window = MainWindow() + + sys.exit(app.exec_()) diff --git a/work_in_progress_by_BWAC/project/tests/__init__.py b/work_in_progress_by_BWAC/project/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/work_in_progress_by_BWAC/project/tests/test_example.py b/work_in_progress_by_BWAC/project/tests/test_example.py new file mode 100644 index 00000000..4890919e --- /dev/null +++ b/work_in_progress_by_BWAC/project/tests/test_example.py @@ -0,0 +1,38 @@ +""" +.. module:: utils + :synopsis: File containing constants and static functions. + +.. moduleauthor:: Bryan Kok +""" + +import pytest + + +@pytest.fixture +def error_fixture(): + assert 0 + + +def test_ok(): + print("ok") + + +def test_fail(): + assert 0 + + +def test_error(error_fixture): + pass + + +def test_skip(): + pytest.skip("skipping this test") + + +def test_xfail(): + pytest.xfail("xfailing this test") + + +@pytest.mark.xfail(reason="always xfail") +def test_xpass(): + pass diff --git a/work_in_progress_by_BWAC/project/utils.py b/work_in_progress_by_BWAC/project/utils.py new file mode 100644 index 00000000..754fe938 --- /dev/null +++ b/work_in_progress_by_BWAC/project/utils.py @@ -0,0 +1,17 @@ +""" +.. module:: utils + :synopsis: File containing constants and static functions. + +.. moduleauthor:: Bryan Kok +""" + + +def add(x, y): + """Adds two numbers.""" + return 5 + + +CONSTANTS = { + 'NAME': 'Clipboard Mangler', + 'HISTORY_MAX_ITEMS': 10, +} From 6665c871218cf870a21f608ef7cbf9fa362f77e8 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Fri, 22 Feb 2019 21:28:41 -0800 Subject: [PATCH 09/60] Update __main__.py --- work_in_progress_by_BWAC/project/__main__.py | 37 +++++++++++++++----- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/work_in_progress_by_BWAC/project/__main__.py b/work_in_progress_by_BWAC/project/__main__.py index 356fa3d8..15024d11 100644 --- a/work_in_progress_by_BWAC/project/__main__.py +++ b/work_in_progress_by_BWAC/project/__main__.py @@ -2,8 +2,10 @@ import sys -from project import ClipboardManager -from .utils import CONSTANTS +#from project import ClipboardManager +#from .utils import CONSTANTS + +#also these errored from PyQt5 import QtCore, QtWidgets @@ -14,7 +16,7 @@ class MainWindow(QMainWindow): def __init__(self): super().__init__() - self.title = CONSTANTS['NAME'] + self.title = 'Enter name' #enter the name of the window (i dont know why the CONSTANTS['NAME'] is for) # self.left = 10 # self.top = 10 # self.width = 640 @@ -29,37 +31,56 @@ def _init_ui(self): def setupUi(self): # MainWindow.setObjectName("MainWindow") - self.resize(640, 480) + + self.setFixedSize(631, 462) + '''makes it non resize able, change to self.resize(640, 480) for it not to be + it is 631, 761 because it looks nice + ''' + self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setObjectName("centralwidget") + self.Add = QtWidgets.QPushButton(self.centralwidget) self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) self.Add.setObjectName("Add") + self.Remove = QtWidgets.QPushButton(self.centralwidget) self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) self.Remove.setObjectName("Remove") + self.Edit = QtWidgets.QPushButton(self.centralwidget) self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) self.Edit.setObjectName("Edit") + self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget) self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) self.treeWidget.setObjectName("treeWidget") item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) + self.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") + self.menuPlugins = QtWidgets.QMenu(self.menubar) self.menuPlugins.setObjectName("menuPlugins") + self.menuItem = QtWidgets.QMenu(self.menubar) self.menuItem.setObjectName("menuItem") + self.setMenuBar(self.menubar) - self.statusbar = QtWidgets.QStatusBar(self) - self.statusbar.setObjectName("statusbar") - self.setStatusBar(self.statusbar) + + #self.statusbar = QtWidgets.QStatusBar(self) + #self.statusbar.setObjectName("statusbar") + #self.setStatusBar(self.statusbar) + + #if you want the status bar back, set the size of the window to 640, 280 + self.actionAdd = QtWidgets.QAction(self) self.actionAdd.setObjectName("actionAdd") self.actionDelete = QtWidgets.QAction(self) @@ -112,7 +133,7 @@ def retranslateUi(self): # label = QLabel('Hello World!') # label.show() - clipboard_mgr = ClipboardManager.ClipboardManager() + #clipboard_mgr = ClipboardManager.ClipboardManager() main_window = MainWindow() sys.exit(app.exec_()) From f444cb86569584077efa0a53e75e7dd665c89585 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Fri, 22 Feb 2019 22:39:40 -0800 Subject: [PATCH 10/60] updated --- .gitignore | 2 +- .../project/ObjectManipulation/__init__.py | 0 work_in_progress_by_BWAC/project/__main__.py | 18 +++++++++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 work_in_progress_by_BWAC/project/ObjectManipulation/__init__.py diff --git a/.gitignore b/.gitignore index a86f590e..63ce0a01 100644 --- a/.gitignore +++ b/.gitignore @@ -107,4 +107,4 @@ venv.bak/ .idea/ # compiled sphinx HTML documentation -docs/build +docs/build \ No newline at end of file diff --git a/work_in_progress_by_BWAC/project/ObjectManipulation/__init__.py b/work_in_progress_by_BWAC/project/ObjectManipulation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/work_in_progress_by_BWAC/project/__main__.py b/work_in_progress_by_BWAC/project/__main__.py index 15024d11..abdd08fc 100644 --- a/work_in_progress_by_BWAC/project/__main__.py +++ b/work_in_progress_by_BWAC/project/__main__.py @@ -2,8 +2,8 @@ import sys -#from project import ClipboardManager -#from .utils import CONSTANTS +from project import ClipboardManager +from .utils import CONSTANTS #also these errored @@ -42,6 +42,7 @@ def setupUi(self): self.Add = QtWidgets.QPushButton(self.centralwidget) self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + self.Add.clicked.connect(self.addObject) self.Add.setObjectName("Add") self.Remove = QtWidgets.QPushButton(self.centralwidget) @@ -74,7 +75,7 @@ def setupUi(self): self.menuItem.setObjectName("menuItem") self.setMenuBar(self.menubar) - + #self.statusbar = QtWidgets.QStatusBar(self) #self.statusbar.setObjectName("statusbar") #self.setStatusBar(self.statusbar) @@ -83,20 +84,28 @@ def setupUi(self): self.actionAdd = QtWidgets.QAction(self) self.actionAdd.setObjectName("actionAdd") + self.actionDelete = QtWidgets.QAction(self) self.actionDelete.setObjectName("actionDelete") + self.action_todo = QtWidgets.QAction(self) self.action_todo.setObjectName("action_todo") + self.actionSettings = QtWidgets.QAction(self) self.actionSettings.setObjectName("actionSettings") + self.actionAdd_2 = QtWidgets.QAction(self) self.actionAdd_2.setObjectName("actionAdd_2") + self.actionRemove = QtWidgets.QAction(self) self.actionRemove.setObjectName("actionRemove") + self.menuFile.addAction(self.actionSettings) self.menuPlugins.addAction(self.action_todo) + self.menuItem.addAction(self.actionAdd_2) self.menuItem.addAction(self.actionRemove) + self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuPlugins.menuAction()) self.menubar.addAction(self.menuItem.menuAction()) @@ -128,6 +137,9 @@ def retranslateUi(self): self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + def addObject(self): + + if __name__ == '__main__': app = QApplication(sys.argv) # label = QLabel('Hello World!') From 8512be8bd4ea7d57ee365b4cfba61b02e71ae884 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Sat, 23 Feb 2019 01:35:37 -0800 Subject: [PATCH 11/60] updated, the 'add' button now works :0 the 'add' button now works :0 --- Pipfile | 1 + Pipfile.lock | 46 ++++- project/__main__.py | 31 +++- project/utils.py | 1 + .../.ui files/untitled.ui | 163 ------------------ .../ClipboardManager/ClipboardManager.py | 15 -- .../ClipboardManager/HistoryManager.py | 7 - .../project/ClipboardManager/__init__.py | 2 - .../project/ObjectManipulation/__init__.py | 0 .../project/PluginManager/PluginManager.py | 0 .../project/PluginManager/__init__.py | 0 .../project/Stack/Stack.py | 61 ------- .../project/Stack/__init__.py | 2 - .../project/Widgets/__init__.py | 0 work_in_progress_by_BWAC/project/__main__.py | 151 ---------------- .../project/tests/__init__.py | 0 .../project/tests/test_example.py | 38 ---- work_in_progress_by_BWAC/project/utils.py | 17 -- 18 files changed, 73 insertions(+), 462 deletions(-) delete mode 100644 work_in_progress_by_BWAC/.ui files/untitled.ui delete mode 100644 work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py delete mode 100644 work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py delete mode 100644 work_in_progress_by_BWAC/project/ClipboardManager/__init__.py delete mode 100644 work_in_progress_by_BWAC/project/ObjectManipulation/__init__.py delete mode 100644 work_in_progress_by_BWAC/project/PluginManager/PluginManager.py delete mode 100644 work_in_progress_by_BWAC/project/PluginManager/__init__.py delete mode 100644 work_in_progress_by_BWAC/project/Stack/Stack.py delete mode 100644 work_in_progress_by_BWAC/project/Stack/__init__.py delete mode 100644 work_in_progress_by_BWAC/project/Widgets/__init__.py delete mode 100644 work_in_progress_by_BWAC/project/__main__.py delete mode 100644 work_in_progress_by_BWAC/project/tests/__init__.py delete mode 100644 work_in_progress_by_BWAC/project/tests/test_example.py delete mode 100644 work_in_progress_by_BWAC/project/utils.py diff --git a/Pipfile b/Pipfile index 6f335661..9c0abe9f 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,7 @@ sphinx = "*" [packages] pyqt5 = "*" +flake8 = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 26e45bdd..5bdb2bfb 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "ce2c7c13183491802df185b32bd2fad6bc367bcb8983c77391117376d2e30e9e" + "sha256": "17ce94e1fc71663d21aa757654ae465c3575be6c1b6275bb1f808794655b7e96" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,42 @@ ] }, "default": { + "entrypoints": { + "hashes": [ + "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", + "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451" + ], + "version": "==0.3" + }, + "flake8": { + "hashes": [ + "sha256:6d8c66a65635d46d54de59b027a1dda40abbe2275b3164b634835ac9c13fd048", + "sha256:6eab21c6e34df2c05416faa40d0c59963008fff29b6f0ccfe8fa28152ab3e383" + ], + "index": "pypi", + "version": "==3.7.6" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", + "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" + ], + "version": "==2.5.0" + }, + "pyflakes": { + "hashes": [ + "sha256:5e8c00e30c464c99e0b501dc160b13a14af7f27d4dffb529c556e30a159e231d", + "sha256:f277f9ca3e55de669fba45b7393a1449009cff5a37d1af10ebb76c52765269cd" + ], + "version": "==2.1.0" + }, "pyqt5": { "hashes": [ "sha256:1402f1613698ca64e3cec0ee27a60b5454e782c16fbd1bdee4a270a058947939", @@ -87,6 +123,14 @@ ], "version": "==3.0.4" }, + "colorama": { + "hashes": [ + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.1" + }, "docutils": { "hashes": [ "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", diff --git a/project/__main__.py b/project/__main__.py index 356fa3d8..c70f7a5d 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -12,6 +12,8 @@ # print(add(2, 2)) class MainWindow(QMainWindow): + num_of_objects = 0 + items = [] def __init__(self): super().__init__() self.title = CONSTANTS['NAME'] @@ -29,23 +31,28 @@ def _init_ui(self): def setupUi(self): # MainWindow.setObjectName("MainWindow") - self.resize(640, 480) + self.setFixedSize(640, 480) self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setObjectName("centralwidget") self.Add = QtWidgets.QPushButton(self.centralwidget) self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + self.Add.clicked.connect(self.addObject) self.Add.setObjectName("Add") + self.Remove = QtWidgets.QPushButton(self.centralwidget) self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) + self.Remove.clicked.connect(self.removeObject) self.Remove.setObjectName("Remove") + self.Edit = QtWidgets.QPushButton(self.centralwidget) self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) self.Edit.setObjectName("Edit") + self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget) self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) self.treeWidget.setObjectName("treeWidget") - item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) + self.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) @@ -93,9 +100,6 @@ def retranslateUi(self): .setText(0, _translate("MainWindow", "Items:")) __sortingEnabled = self.treeWidget.isSortingEnabled() self.treeWidget.setSortingEnabled(False) - self.treeWidget.topLevelItem(0)\ - .setText(0, _translate("MainWindow", "Test copy")) - self.treeWidget.setSortingEnabled(__sortingEnabled) self.menuFile.setTitle(_translate("MainWindow", "File")) self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) self.menuItem.setTitle(_translate("MainWindow", "Items")) @@ -106,6 +110,23 @@ def retranslateUi(self): self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + def addObject(self): + exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') + + self.num_of_objects + 1 + + def removeObject(self): + + #TODO make it remove instead of add + + if self.items == []: + return + + exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') + + self.num_of_objects + 1 if __name__ == '__main__': app = QApplication(sys.argv) diff --git a/project/utils.py b/project/utils.py index 754fe938..bf9d8a93 100644 --- a/project/utils.py +++ b/project/utils.py @@ -13,5 +13,6 @@ def add(x, y): CONSTANTS = { 'NAME': 'Clipboard Mangler', + 'NUMOFOBJECTS': 0, 'HISTORY_MAX_ITEMS': 10, } diff --git a/work_in_progress_by_BWAC/.ui files/untitled.ui b/work_in_progress_by_BWAC/.ui files/untitled.ui deleted file mode 100644 index c6c81993..00000000 --- a/work_in_progress_by_BWAC/.ui files/untitled.ui +++ /dev/null @@ -1,163 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 640 - 481 - - - - MainWindow - - - - - - 0 - 0 - 51 - 20 - - - - Add - - - - - - 50 - 0 - 61 - 20 - - - - Remove - - - - - - 110 - 0 - 51 - 20 - - - - Edit - - - - - - 160 - 0 - 71 - 20 - - - - Move Up - - - - - - 230 - 0 - 71 - 20 - - - - Move Down - - - - - - 0 - 21 - 641 - 441 - - - - - New Item - - - - - - - - 0 - 0 - 640 - 21 - - - - - File - - - - - - Plugins - - - - - - Items - - - - - - - - - - - Add - - - - - Delete - - - - - Install #todo - - - - - Settings #todo - - - - - Add #todo - - - - - Remove #todo - - - - - - diff --git a/work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py b/work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py deleted file mode 100644 index 7a756deb..00000000 --- a/work_in_progress_by_BWAC/project/ClipboardManager/ClipboardManager.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Class encapsulating clipboard events""" -from PyQt5.Qt import QApplication, QClipboard # noqa: F401 -from project.Stack import Stack - - -def _clipboard_changed(): - print("Current Text", QApplication.clipboard().text()) - print("Current Image Info", QApplication.clipboard().pixmap()) - - -class ClipboardManager: - - def __init__(self): - QApplication.clipboard().dataChanged.connect(_clipboard_changed) - self._clipboard_stack = Stack() diff --git a/work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py b/work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py deleted file mode 100644 index d9f27a49..00000000 --- a/work_in_progress_by_BWAC/project/ClipboardManager/HistoryManager.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -.. module:: HistoryManager - :synopsis: Persists and loads the state of the clipboard \ - and history upon app close. - -.. moduleauthor:: TBD -""" diff --git a/work_in_progress_by_BWAC/project/ClipboardManager/__init__.py b/work_in_progress_by_BWAC/project/ClipboardManager/__init__.py deleted file mode 100644 index 009f2596..00000000 --- a/work_in_progress_by_BWAC/project/ClipboardManager/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -from .ClipboardManager import ClipboardManager # noqa: F401 diff --git a/work_in_progress_by_BWAC/project/ObjectManipulation/__init__.py b/work_in_progress_by_BWAC/project/ObjectManipulation/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/work_in_progress_by_BWAC/project/PluginManager/PluginManager.py b/work_in_progress_by_BWAC/project/PluginManager/PluginManager.py deleted file mode 100644 index e69de29b..00000000 diff --git a/work_in_progress_by_BWAC/project/PluginManager/__init__.py b/work_in_progress_by_BWAC/project/PluginManager/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/work_in_progress_by_BWAC/project/Stack/Stack.py b/work_in_progress_by_BWAC/project/Stack/Stack.py deleted file mode 100644 index fd898b8c..00000000 --- a/work_in_progress_by_BWAC/project/Stack/Stack.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -.. module:: Stack - :synopsis: Class encapsulating the behavior of the stack. - -.. moduleauthor:: Bryan Kok -""" -import enum - - -class Stack: - class SHIFT_DIRECTION(enum.Enum): - UP: 1 - DOWN: 2 - - def __init__(self, existing_stack=None, cur_stack_pointer=None): - if existing_stack: - self._stack = existing_stack - else: - self._stack = [] - - if cur_stack_pointer: - self._stack_pointer = cur_stack_pointer - else: - # By default the stack pointer is at the top of the stack - self._stack_pointer = len(self._stack) - 1 - - def items(self): - return self._stack - - def set_current_item(self, idx): - if not 0 <= idx < len(self._stack): - raise Exception("Index is out of bounds") - - self._stack_pointer = idx - - def shift_current_item(self, idx, shift_direction: SHIFT_DIRECTION): - _temp = self._stack[self._stack_pointer] - if shift_direction == Stack.SHIFT_DIRECTION.UP: - self._stack[idx] = self._stack[idx + 1] - self._stack[idx + 1] = _temp - - elif shift_direction == Stack.SHIFT_DIRECTION.DOWN: - self._stack[idx] = self._stack[idx - 1] - self._stack[idx - 1] = _temp - - def swap_items(self, idx, target_idx): - _temp = self._stack[idx] - self._stack[idx] = self._stack[target_idx] - self._stack[target_idx] = _temp - - def push_item(self, item): - self._stack.append(item) - - def peek(self): - return self._stack[-1] - - def pop(self): - return self._stack.pop() - - def clear(self): - self._stack = [] diff --git a/work_in_progress_by_BWAC/project/Stack/__init__.py b/work_in_progress_by_BWAC/project/Stack/__init__.py deleted file mode 100644 index 8a92fdf4..00000000 --- a/work_in_progress_by_BWAC/project/Stack/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -from .Stack import Stack # noqa: F401 diff --git a/work_in_progress_by_BWAC/project/Widgets/__init__.py b/work_in_progress_by_BWAC/project/Widgets/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/work_in_progress_by_BWAC/project/__main__.py b/work_in_progress_by_BWAC/project/__main__.py deleted file mode 100644 index abdd08fc..00000000 --- a/work_in_progress_by_BWAC/project/__main__.py +++ /dev/null @@ -1,151 +0,0 @@ -from PyQt5.QtWidgets import QMainWindow, QApplication - -import sys - -from project import ClipboardManager -from .utils import CONSTANTS - -#also these errored - -from PyQt5 import QtCore, QtWidgets - - -# print("hello %s" % sys.argv[1]) -# print(add(2, 2)) - -class MainWindow(QMainWindow): - def __init__(self): - super().__init__() - self.title = 'Enter name' #enter the name of the window (i dont know why the CONSTANTS['NAME'] is for) - # self.left = 10 - # self.top = 10 - # self.width = 640 - # self.height = 480 - self._init_ui() - - def _init_ui(self): - self.setWindowTitle(self.title) - # self.setGeometry(self.left, self.top, self.width, self.height) - self.setupUi() - self.show() - - def setupUi(self): - # MainWindow.setObjectName("MainWindow") - - self.setFixedSize(631, 462) - '''makes it non resize able, change to self.resize(640, 480) for it not to be - it is 631, 761 because it looks nice - ''' - - self.centralwidget = QtWidgets.QWidget(self) - self.centralwidget.setObjectName("centralwidget") - - self.Add = QtWidgets.QPushButton(self.centralwidget) - self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) - self.Add.clicked.connect(self.addObject) - self.Add.setObjectName("Add") - - self.Remove = QtWidgets.QPushButton(self.centralwidget) - self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) - self.Remove.setObjectName("Remove") - - self.Edit = QtWidgets.QPushButton(self.centralwidget) - self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) - self.Edit.setObjectName("Edit") - - self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget) - self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) - self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.treeWidget.setObjectName("treeWidget") - item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) - - self.setCentralWidget(self.centralwidget) - - self.menubar = QtWidgets.QMenuBar(self) - self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) - self.menubar.setObjectName("menubar") - - self.menuFile = QtWidgets.QMenu(self.menubar) - self.menuFile.setObjectName("menuFile") - - self.menuPlugins = QtWidgets.QMenu(self.menubar) - self.menuPlugins.setObjectName("menuPlugins") - - self.menuItem = QtWidgets.QMenu(self.menubar) - self.menuItem.setObjectName("menuItem") - - self.setMenuBar(self.menubar) - - #self.statusbar = QtWidgets.QStatusBar(self) - #self.statusbar.setObjectName("statusbar") - #self.setStatusBar(self.statusbar) - - #if you want the status bar back, set the size of the window to 640, 280 - - self.actionAdd = QtWidgets.QAction(self) - self.actionAdd.setObjectName("actionAdd") - - self.actionDelete = QtWidgets.QAction(self) - self.actionDelete.setObjectName("actionDelete") - - self.action_todo = QtWidgets.QAction(self) - self.action_todo.setObjectName("action_todo") - - self.actionSettings = QtWidgets.QAction(self) - self.actionSettings.setObjectName("actionSettings") - - self.actionAdd_2 = QtWidgets.QAction(self) - self.actionAdd_2.setObjectName("actionAdd_2") - - self.actionRemove = QtWidgets.QAction(self) - self.actionRemove.setObjectName("actionRemove") - - self.menuFile.addAction(self.actionSettings) - self.menuPlugins.addAction(self.action_todo) - - self.menuItem.addAction(self.actionAdd_2) - self.menuItem.addAction(self.actionRemove) - - self.menubar.addAction(self.menuFile.menuAction()) - self.menubar.addAction(self.menuPlugins.menuAction()) - self.menubar.addAction(self.menuItem.menuAction()) - - self.retranslateUi() - QtCore.QMetaObject.connectSlotsByName(self) - - def retranslateUi(self): - _translate = QtCore.QCoreApplication.translate - # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.Add.setText(_translate("MainWindow", "Add")) - self.Remove.setText(_translate("MainWindow", "Remove")) - self.Edit.setText(_translate("MainWindow", "Edit")) - self.treeWidget.headerItem()\ - .setText(0, _translate("MainWindow", "Items:")) - __sortingEnabled = self.treeWidget.isSortingEnabled() - self.treeWidget.setSortingEnabled(False) - self.treeWidget.topLevelItem(0)\ - .setText(0, _translate("MainWindow", "Test copy")) - self.treeWidget.setSortingEnabled(__sortingEnabled) - self.menuFile.setTitle(_translate("MainWindow", "File")) - self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) - self.menuItem.setTitle(_translate("MainWindow", "Items")) - self.actionAdd.setText(_translate("MainWindow", "Add")) - self.actionDelete.setText(_translate("MainWindow", "Delete")) - self.action_todo.setText(_translate("MainWindow", "Install #todo")) - self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) - self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) - self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) - - - def addObject(self): - - -if __name__ == '__main__': - app = QApplication(sys.argv) - # label = QLabel('Hello World!') - # label.show() - - #clipboard_mgr = ClipboardManager.ClipboardManager() - main_window = MainWindow() - - sys.exit(app.exec_()) diff --git a/work_in_progress_by_BWAC/project/tests/__init__.py b/work_in_progress_by_BWAC/project/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/work_in_progress_by_BWAC/project/tests/test_example.py b/work_in_progress_by_BWAC/project/tests/test_example.py deleted file mode 100644 index 4890919e..00000000 --- a/work_in_progress_by_BWAC/project/tests/test_example.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -.. module:: utils - :synopsis: File containing constants and static functions. - -.. moduleauthor:: Bryan Kok -""" - -import pytest - - -@pytest.fixture -def error_fixture(): - assert 0 - - -def test_ok(): - print("ok") - - -def test_fail(): - assert 0 - - -def test_error(error_fixture): - pass - - -def test_skip(): - pytest.skip("skipping this test") - - -def test_xfail(): - pytest.xfail("xfailing this test") - - -@pytest.mark.xfail(reason="always xfail") -def test_xpass(): - pass diff --git a/work_in_progress_by_BWAC/project/utils.py b/work_in_progress_by_BWAC/project/utils.py deleted file mode 100644 index 754fe938..00000000 --- a/work_in_progress_by_BWAC/project/utils.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -.. module:: utils - :synopsis: File containing constants and static functions. - -.. moduleauthor:: Bryan Kok -""" - - -def add(x, y): - """Adds two numbers.""" - return 5 - - -CONSTANTS = { - 'NAME': 'Clipboard Mangler', - 'HISTORY_MAX_ITEMS': 10, -} From 4ea5acdb16291ddf1e4916b4ccfea8aaa0897576 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sun, 24 Feb 2019 00:27:26 +0800 Subject: [PATCH 12/60] Begin hooking the MainWindow up to the ClipboardManager, making classes for the clipboard objects and ensuring that the center widget is responsive --- .flake8 | 1 + docs/source/ClipboardManager.rst | 8 + docs/source/Widgets.rst | 12 + project/ClipboardManager/ClipboardManager.py | 27 ++- project/ClipboardManager/ClipboardObject.py | 22 ++ project/Stack/Stack.py | 2 + project/Widgets/MainListWidget.py | 14 ++ project/__main__.py | 242 ++++++++++++------- 8 files changed, 230 insertions(+), 98 deletions(-) create mode 100644 project/ClipboardManager/ClipboardObject.py create mode 100644 project/Widgets/MainListWidget.py diff --git a/.flake8 b/.flake8 index f2b41384..b1663a2f 100644 --- a/.flake8 +++ b/.flake8 @@ -1,3 +1,4 @@ +[flake8] max-line-length=100 application_import_names=projectt ignore=P102,B311,W503,E226,S311,W504,F821 diff --git a/docs/source/ClipboardManager.rst b/docs/source/ClipboardManager.rst index 583f8969..275e5db6 100644 --- a/docs/source/ClipboardManager.rst +++ b/docs/source/ClipboardManager.rst @@ -12,6 +12,14 @@ ClipboardManager.ClipboardManager module :undoc-members: :show-inheritance: +ClipboardManager.ClipboardObject module +--------------------------------------- + +.. automodule:: ClipboardManager.ClipboardObject + :members: + :undoc-members: + :show-inheritance: + ClipboardManager.HistoryManager module -------------------------------------- diff --git a/docs/source/Widgets.rst b/docs/source/Widgets.rst index 7d387afa..da02a540 100644 --- a/docs/source/Widgets.rst +++ b/docs/source/Widgets.rst @@ -1,6 +1,18 @@ Widgets package =============== +Submodules +---------- + +Widgets.MainListWidget module +----------------------------- + +.. automodule:: Widgets.MainListWidget + :members: + :undoc-members: + :show-inheritance: + + Module contents --------------- diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 7a756deb..283ef658 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -1,15 +1,30 @@ """Class encapsulating clipboard events""" from PyQt5.Qt import QApplication, QClipboard # noqa: F401 -from project.Stack import Stack - -def _clipboard_changed(): - print("Current Text", QApplication.clipboard().text()) - print("Current Image Info", QApplication.clipboard().pixmap()) +from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.Stack import Stack class ClipboardManager: def __init__(self): - QApplication.clipboard().dataChanged.connect(_clipboard_changed) + self._clipboard_state_callback = None + QApplication.clipboard().dataChanged.connect(self._clipboard_changed) self._clipboard_stack = Stack() + + def _clipboard_changed(self): + current_text = QApplication.clipboard().text() + print("Current Text", QApplication.clipboard().text()) + print("Current Image Info", QApplication.clipboard().pixmap()) + + if current_text and not (isinstance(self._clipboard_stack.peek(), TextClipboardObject) + and self._clipboard_stack.peek().text == current_text): + self._clipboard_stack.push_item(TextClipboardObject(current_text)) + + if self._clipboard_state_callback is not None: + self._clipboard_state_callback(self._clipboard_stack) + + # TODO: use Qt signals properly + # https://stackoverflow.com/questions/36434706/pyqt-proper-use-of-emit-and-pyqtsignal + def bind_clipboard_state_callback(self, function): + self._clipboard_state_callback = function diff --git a/project/ClipboardManager/ClipboardObject.py b/project/ClipboardManager/ClipboardObject.py new file mode 100644 index 00000000..86cc1ac4 --- /dev/null +++ b/project/ClipboardManager/ClipboardObject.py @@ -0,0 +1,22 @@ +from abc import ABCMeta +import datetime + + +class ClipboardObject(metaclass=ABCMeta): + + def __init__(self): + self._date = datetime.datetime.now() + + def date(self): + """Returns when this object was copied to clipboard""" + return self._date + + +class TextClipboardObject(ClipboardObject): + + def __init__(self, text): + super().__init__() + self.text = text + + def set_text(self, text: str): + self.text = text diff --git a/project/Stack/Stack.py b/project/Stack/Stack.py index fd898b8c..307961f9 100644 --- a/project/Stack/Stack.py +++ b/project/Stack/Stack.py @@ -52,6 +52,8 @@ def push_item(self, item): self._stack.append(item) def peek(self): + if not self._stack: + return None return self._stack[-1] def pop(self): diff --git a/project/Widgets/MainListWidget.py b/project/Widgets/MainListWidget.py new file mode 100644 index 00000000..3c8ac3d6 --- /dev/null +++ b/project/Widgets/MainListWidget.py @@ -0,0 +1,14 @@ +""" +.. module:: MainListView + :synopsis: The scrollable area in the main user interface, \ + with helper functions to add or remove objects + +.. moduleauthor:: TBD +""" +from PyQt5.QtWidgets import QListWidget + + +class MainListWidget(QListWidget): + def __init__(self): + super().__init__() + self.addItem("Sample Item") diff --git a/project/__main__.py b/project/__main__.py index c70f7a5d..e2f1a758 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,8 +1,12 @@ -from PyQt5.QtWidgets import QMainWindow, QApplication +from PyQt5.QtWidgets import QMainWindow, QApplication, \ + QHBoxLayout, QVBoxLayout, QWidget import sys from project import ClipboardManager +from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.Stack import Stack +from project.Widgets.MainListWidget import MainListWidget from .utils import CONSTANTS from PyQt5 import QtCore, QtWidgets @@ -11,122 +15,176 @@ # print("hello %s" % sys.argv[1]) # print(add(2, 2)) +class ActionBar(QWidget): + def __init__(self): + super().__init__() + _horizontal_layout = QHBoxLayout(self) + + self._add_btn = QtWidgets.QPushButton("Add") + # self._add_btn.setGeometry(QtCore.QRect(0, 3, 51, 20)) + # self._add_btn.clicked.connect(self._add_object) + self._add_btn.setObjectName(MainWindow.ADD_BUTTON_NAME) + + # self._add_btn.setStyleSheet("QPushButton {background-color: yellow, margin: 0}") + + self._remove_btn = QtWidgets.QPushButton("Remove") + # self._remove_btn.setGeometry(QtCore.QRect(50, 3, 51, 20)) + # self._remove_btn.clicked.connect() + self._remove_btn.setObjectName(MainWindow.REMOVE_BUTTON_NAME) + + self._edit_btn = QtWidgets.QPushButton("Edit") + # self._edit_btn.setGeometry(QtCore.QRect(100, 3, 51, 20)) + self._edit_btn.setObjectName(MainWindow.EDIT_BUTTON_NAME) + + _horizontal_layout.addWidget(self._add_btn) + _horizontal_layout.addWidget(self._remove_btn) + _horizontal_layout.addWidget(self._edit_btn) + _horizontal_layout.addStretch(1) + + class MainWindow(QMainWindow): + CENTRAL_WIDGET_NAME = 'central_widget' + ADD_BUTTON_NAME = 'add_btn' + REMOVE_BUTTON_NAME = 'remove_btn' + EDIT_BUTTON_NAME = 'edit_btn' + num_of_objects = 0 items = [] - def __init__(self): + + def __init__(self, clipboard_manager: ClipboardManager): super().__init__() - self.title = CONSTANTS['NAME'] - # self.left = 10 - # self.top = 10 - # self.width = 640 - # self.height = 480 + + self._central_widget_layout = QVBoxLayout() + self._central_widget = QtWidgets.QWidget(self) + self._clipboard_manager = clipboard_mgr + + self._clipboard_manager.bind_clipboard_state_callback(self._render_clipboard_stack) self._init_ui() def _init_ui(self): - self.setWindowTitle(self.title) + self.setWindowTitle(CONSTANTS['NAME']) # self.setGeometry(self.left, self.top, self.width, self.height) self.setupUi() self.show() + def _render_clipboard_stack(self, clipboard_stack: Stack): + self._main_list_widget.clear() + for clipboard_object in clipboard_stack.items(): + if isinstance(clipboard_object, TextClipboardObject): + self._main_list_widget.addItem(clipboard_object.text + " " + + clipboard_object + .date().strftime("%Y-%m-%d %H:%M:%S")) + def setupUi(self): # MainWindow.setObjectName("MainWindow") - self.setFixedSize(640, 480) - self.centralwidget = QtWidgets.QWidget(self) - self.centralwidget.setObjectName("centralwidget") - self.Add = QtWidgets.QPushButton(self.centralwidget) - self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) - self.Add.clicked.connect(self.addObject) - self.Add.setObjectName("Add") - - self.Remove = QtWidgets.QPushButton(self.centralwidget) - self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) - self.Remove.clicked.connect(self.removeObject) - self.Remove.setObjectName("Remove") - - self.Edit = QtWidgets.QPushButton(self.centralwidget) - self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) - self.Edit.setObjectName("Edit") - - self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget) - self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) - self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.treeWidget.setObjectName("treeWidget") - - self.setCentralWidget(self.centralwidget) - self.menubar = QtWidgets.QMenuBar(self) - self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) - self.menubar.setObjectName("menubar") + # self.setFixedSize(640, 480) + self._central_widget.setObjectName(MainWindow.CENTRAL_WIDGET_NAME) + + self._action_bar = ActionBar() + self._central_widget_layout.addWidget(self._action_bar) + + self._main_list_widget = MainListWidget() + self._central_widget_layout.addWidget(self._main_list_widget) + # self._central_widget_layout.addStretch(1) + + # self.Add = QtWidgets.QPushButton(self._central_widget) + # self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + # self.Add.clicked.connect(self.addObject) + # self.Add.setObjectName("Add") + + # self.Remove = QtWidgets.QPushButton(self._central_widget) + # self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) + # self.Remove.clicked.connect(self.removeObject) + # self.Remove.setObjectName("Remove") + # + # self.Edit = QtWidgets.QPushButton(self._central_widget) + # self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) + # self.Edit.setObjectName("Edit") + + # self.treeWidget = QtWidgets.QTreeWidget(self._central_widget) + # self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) + # self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) + # self.treeWidget.setObjectName("treeWidget") + + self.menubar = self.menuBar() + # self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) + # self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") - self.menuPlugins = QtWidgets.QMenu(self.menubar) - self.menuPlugins.setObjectName("menuPlugins") - self.menuItem = QtWidgets.QMenu(self.menubar) - self.menuItem.setObjectName("menuItem") - self.setMenuBar(self.menubar) - self.statusbar = QtWidgets.QStatusBar(self) - self.statusbar.setObjectName("statusbar") - self.setStatusBar(self.statusbar) - self.actionAdd = QtWidgets.QAction(self) - self.actionAdd.setObjectName("actionAdd") - self.actionDelete = QtWidgets.QAction(self) - self.actionDelete.setObjectName("actionDelete") - self.action_todo = QtWidgets.QAction(self) - self.action_todo.setObjectName("action_todo") + # self.menuPlugins = QtWidgets.QMenu(self.menubar) + # self.menuPlugins.setObjectName("menuPlugins") + # self.menuItem = QtWidgets.QMenu(self.menubar) + # self.menuItem.setObjectName("menuItem") + # self.setMenuBar(self.menubar) + # self.statusbar = QtWidgets.QStatusBar(self) + # self.statusbar.setObjectName("statusbar") + # self.setStatusBar(self.statusbar) + # self.actionAdd = QtWidgets.QAction(self) + # self.actionAdd.setObjectName("actionAdd") + # self.actionDelete = QtWidgets.QAction(self) + # self.actionDelete.setObjectName("actionDelete") + # self.action_todo = QtWidgets.QAction(self) + # self.action_todo.setObjectName("action_todo") self.actionSettings = QtWidgets.QAction(self) self.actionSettings.setObjectName("actionSettings") - self.actionAdd_2 = QtWidgets.QAction(self) - self.actionAdd_2.setObjectName("actionAdd_2") - self.actionRemove = QtWidgets.QAction(self) - self.actionRemove.setObjectName("actionRemove") + # self.actionAdd_2 = QtWidgets.QAction(self) + # self.actionAdd_2.setObjectName("actionAdd_2") + # self.actionRemove = QtWidgets.QAction(self) + # self.actionRemove.setObjectName("actionRemove") self.menuFile.addAction(self.actionSettings) - self.menuPlugins.addAction(self.action_todo) - self.menuItem.addAction(self.actionAdd_2) - self.menuItem.addAction(self.actionRemove) + # self.menuPlugins.addAction(self.action_todo) + # self.menuItem.addAction(self.actionAdd_2) + # self.menuItem.addAction(self.actionRemove) self.menubar.addAction(self.menuFile.menuAction()) - self.menubar.addAction(self.menuPlugins.menuAction()) - self.menubar.addAction(self.menuItem.menuAction()) + # self.menubar.addAction(self.menuPlugins.menuAction()) + # self.menubar.addAction(self.menuItem.menuAction()) + + self._central_widget.setLayout(self._central_widget_layout) + self.setCentralWidget(self._central_widget) self.retranslateUi() - QtCore.QMetaObject.connectSlotsByName(self) + + # https://stackoverflow.com/questions/2462401/problem-in-understanding-connectslotsbyname-in-pyqt + # Better to use new-style decorator @QtCore.pyqtSlot() + # QtCore.QMetaObject.connectSlotsByName(self) def retranslateUi(self): _translate = QtCore.QCoreApplication.translate # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.Add.setText(_translate("MainWindow", "Add")) - self.Remove.setText(_translate("MainWindow", "Remove")) - self.Edit.setText(_translate("MainWindow", "Edit")) - self.treeWidget.headerItem()\ - .setText(0, _translate("MainWindow", "Items:")) - __sortingEnabled = self.treeWidget.isSortingEnabled() - self.treeWidget.setSortingEnabled(False) + # self._add_btn.setText(_translate("MainWindow", "Add")) + # self._remove_btn.setText(_translate("MainWindow", "Remove")) + # self._edit_btn.setText(_translate("MainWindow", "Edit")) + # self.treeWidget.headerItem() \ + # .setText(0, _translate("MainWindow", "Items:")) + # __sortingEnabled = self.treeWidget.isSortingEnabled() + # self.treeWidget.setSortingEnabled(False) self.menuFile.setTitle(_translate("MainWindow", "File")) - self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) - self.menuItem.setTitle(_translate("MainWindow", "Items")) - self.actionAdd.setText(_translate("MainWindow", "Add")) - self.actionDelete.setText(_translate("MainWindow", "Delete")) - self.action_todo.setText(_translate("MainWindow", "Install #todo")) - self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) - self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) - self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) - - def addObject(self): - exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - - self.num_of_objects + 1 - - def removeObject(self): - - #TODO make it remove instead of add - - if self.items == []: - return - - exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - - self.num_of_objects + 1 + # self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) + # self.menuItem.setTitle(_translate("MainWindow", "Items")) + # self.actionAdd.setText(_translate("MainWindow", "Add")) + # self.actionDelete.setText(_translate("MainWindow", "Delete")) + # self.action_todo.setText(_translate("MainWindow", "Install #todo")) + # self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) + # self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) + # self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + + # def _add_object(self): + # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') + # + # self.num_of_objects + 1 + # + # def removeObject(self): + # # TODO make it remove instead of add + # + # if self.items == []: + # return + # + # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') + # + # self.num_of_objects + 1 + if __name__ == '__main__': app = QApplication(sys.argv) @@ -134,6 +192,6 @@ def removeObject(self): # label.show() clipboard_mgr = ClipboardManager.ClipboardManager() - main_window = MainWindow() + main_window = MainWindow(clipboard_mgr) sys.exit(app.exec_()) From 240a082a3b9bfabba57cf095f1879b9f68c634a3 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Sat, 23 Feb 2019 13:16:59 -0800 Subject: [PATCH 13/60] Create PredictiveText.py --- project/Plugins/PredictiveText.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 project/Plugins/PredictiveText.py diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py new file mode 100644 index 00000000..45b74ca2 --- /dev/null +++ b/project/Plugins/PredictiveText.py @@ -0,0 +1,13 @@ +#not done yet, feel free to change it :p + +class PredictiveText(): + + def _update_text(text): + text = text.lower() + text = text.split() + new_text = '' + if 'hello' in text: + text[text.index('hello')] = 'help me' + + new_text.join(text) + return new_text \ No newline at end of file From fc4fa3c3a88aed84c5148c325e221c1657e54a42 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Sat, 23 Feb 2019 13:18:33 -0800 Subject: [PATCH 14/60] Update __main__.py --- project/__main__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/project/__main__.py b/project/__main__.py index e2f1a758..96670216 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -87,10 +87,10 @@ def setupUi(self): self._central_widget_layout.addWidget(self._main_list_widget) # self._central_widget_layout.addStretch(1) - # self.Add = QtWidgets.QPushButton(self._central_widget) - # self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) - # self.Add.clicked.connect(self.addObject) - # self.Add.setObjectName("Add") + self.Add = QtWidgets.QPushButton(self._central_widget) + self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + self.Add.clicked.connect(self._add_Object) + self.Add.setObjectName("Add") # self.Remove = QtWidgets.QPushButton(self._central_widget) # self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) @@ -168,10 +168,10 @@ def retranslateUi(self): # self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) # self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) - # def _add_object(self): - # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - # + def _add_Object(self): + exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') + # self.num_of_objects + 1 # # def removeObject(self): From 47c4f782e6d9b95d75134d7211a0e2c06433a686 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Sat, 23 Feb 2019 13:21:11 -0800 Subject: [PATCH 15/60] Update PredictiveText.py --- project/Plugins/PredictiveText.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index 45b74ca2..e29df6f3 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -3,11 +3,9 @@ class PredictiveText(): def _update_text(text): - text = text.lower() text = text.split() - new_text = '' if 'hello' in text: - text[text.index('hello')] = 'help me' - - new_text.join(text) - return new_text \ No newline at end of file + text[text.index('hello')] = 'help me' #chage this to what ever you want + return text + +print(PredictiveText._update_text(text = 'hello')) \ No newline at end of file From 354e80932d115768bb7c67119b79e050380bdc4e Mon Sep 17 00:00:00 2001 From: BWACpro Date: Sat, 23 Feb 2019 13:25:39 -0800 Subject: [PATCH 16/60] Linted :P --- project/Plugins/PredictiveText.py | 7 +++---- project/__main__.py | 16 +++++++--------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index e29df6f3..9c8b6d8e 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,11 +1,10 @@ -#not done yet, feel free to change it :p +# Not done yet, feel free to change it :p + class PredictiveText(): def _update_text(text): text = text.split() if 'hello' in text: - text[text.index('hello')] = 'help me' #chage this to what ever you want + text[text.index('hello')] = 'help me' # Change this to what ever you want return text - -print(PredictiveText._update_text(text = 'hello')) \ No newline at end of file diff --git a/project/__main__.py b/project/__main__.py index 96670216..dc344b0c 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -87,10 +87,10 @@ def setupUi(self): self._central_widget_layout.addWidget(self._main_list_widget) # self._central_widget_layout.addStretch(1) - self.Add = QtWidgets.QPushButton(self._central_widget) - self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) - self.Add.clicked.connect(self._add_Object) - self.Add.setObjectName("Add") + # self.Add = QtWidgets.QPushButton(self._central_widget) + # self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + # self.Add.clicked.connect(self.addObject) + # self.Add.setObjectName("Add") # self.Remove = QtWidgets.QPushButton(self._central_widget) # self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) @@ -168,12 +168,10 @@ def retranslateUi(self): # self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) # self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) - def _add_Object(self): - exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - + # def _add_object(self): + # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') # self.num_of_objects + 1 - # # def removeObject(self): # # TODO make it remove instead of add # From f1333dd2a124bafb7f3425acfd2415923024f61b Mon Sep 17 00:00:00 2001 From: BWACpro Date: Sat, 23 Feb 2019 22:45:15 -0800 Subject: [PATCH 17/60] add files :p --- Pipfile | 4 + Pipfile.lock | 119 +++++++++++++++++++++++++++++- project/Plugins/ImageOptimizer.py | 27 +++++++ project/Plugins/PredictiveText.py | 14 +++- 4 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 project/Plugins/ImageOptimizer.py diff --git a/Pipfile b/Pipfile index 9c0abe9f..96d9949e 100644 --- a/Pipfile +++ b/Pipfile @@ -11,6 +11,10 @@ sphinx = "*" [packages] pyqt5 = "*" flake8 = "*" +numpy = "*" +matplotlib = "*" +appdirs = "*" +random = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 5bdb2bfb..ca32dd77 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "17ce94e1fc71663d21aa757654ae465c3575be6c1b6275bb1f808794655b7e96" + "sha256": "21e017c60ddc597ea1bb99b1bafcd2da2029c1c689ab7b96d7642b8c45c8b9da" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,21 @@ ] }, "default": { + "appdirs": { + "hashes": [ + "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", + "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" + ], + "index": "pypi", + "version": "==1.4.3" + }, + "cycler": { + "hashes": [ + "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d", + "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8" + ], + "version": "==0.10.0" + }, "entrypoints": { "hashes": [ "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", @@ -31,6 +46,58 @@ "index": "pypi", "version": "==3.7.6" }, + "kiwisolver": { + "hashes": [ + "sha256:0ee4ed8b3ae8f5f712b0aa9ebd2858b5b232f1b9a96b0943dceb34df2a223bc3", + "sha256:0f7f532f3c94e99545a29f4c3f05637f4d2713e7fd91b4dd8abfc18340b86cd5", + "sha256:1a078f5dd7e99317098f0e0d490257fd0349d79363e8c923d5bb76428f318421", + "sha256:1aa0b55a0eb1bd3fa82e704f44fb8f16e26702af1a073cc5030eea399e617b56", + "sha256:2874060b91e131ceeff00574b7c2140749c9355817a4ed498e82a4ffa308ecbc", + "sha256:379d97783ba8d2934d52221c833407f20ca287b36d949b4bba6c75274bcf6363", + "sha256:3b791ddf2aefc56382aadc26ea5b352e86a2921e4e85c31c1f770f527eb06ce4", + "sha256:4329008a167fac233e398e8a600d1b91539dc33c5a3eadee84c0d4b04d4494fa", + "sha256:45813e0873bbb679334a161b28cb9606d9665e70561fd6caa8863e279b5e464b", + "sha256:53a5b27e6b5717bdc0125338a822605084054c80f382051fb945d2c0e6899a20", + "sha256:574f24b9805cb1c72d02b9f7749aa0cc0b81aa82571be5201aa1453190390ae5", + "sha256:66f82819ff47fa67a11540da96966fb9245504b7f496034f534b81cacf333861", + "sha256:79e5fe3ccd5144ae80777e12973027bd2f4f5e3ae8eb286cabe787bed9780138", + "sha256:83410258eb886f3456714eea4d4304db3a1fc8624623fc3f38a487ab36c0f653", + "sha256:8b6a7b596ce1d2a6d93c3562f1178ebd3b7bb445b3b0dd33b09f9255e312a965", + "sha256:9576cb63897fbfa69df60f994082c3f4b8e6adb49cccb60efb2a80a208e6f996", + "sha256:95a25d9f3449046ecbe9065be8f8380c03c56081bc5d41fe0fb964aaa30b2195", + "sha256:a424f048bebc4476620e77f3e4d1f282920cef9bc376ba16d0b8fe97eec87cde", + "sha256:aaec1cfd94f4f3e9a25e144d5b0ed1eb8a9596ec36d7318a504d813412563a85", + "sha256:acb673eecbae089ea3be3dcf75bfe45fc8d4dcdc951e27d8691887963cf421c7", + "sha256:b15bc8d2c2848a4a7c04f76c9b3dc3561e95d4dabc6b4f24bfabe5fd81a0b14f", + "sha256:b1c240d565e977d80c0083404c01e4d59c5772c977fae2c483f100567f50847b", + "sha256:c595693de998461bcd49b8d20568c8870b3209b8ea323b2a7b0ea86d85864694", + "sha256:ce3be5d520b4d2c3e5eeb4cd2ef62b9b9ab8ac6b6fedbaa0e39cdb6f50644278", + "sha256:e0f910f84b35c36a3513b96d816e6442ae138862257ae18a0019d2fc67b041dc", + "sha256:ea36e19ac0a483eea239320aef0bd40702404ff8c7e42179a2d9d36c5afcb55c", + "sha256:efabbcd4f406b532206b8801058c8bab9e79645b9880329253ae3322b7b02cd5", + "sha256:f923406e6b32c86309261b8195e24e18b6a8801df0cfc7814ac44017bfcb3939" + ], + "version": "==1.0.1" + }, + "matplotlib": { + "hashes": [ + "sha256:16aa61846efddf91df623bbb4598e63be1068a6b6a2e6361cc802b41c7a286eb", + "sha256:1975b71a33ac986bb39b6d5cfbc15c7b1f218f1134efb4eb3881839d6ae69984", + "sha256:2b222744bd54781e6cc0b717fa35a54e5f176ba2ced337f27c5b435b334ef854", + "sha256:317643c0e88fad55414347216362b2e229c130edd5655fea5f8159a803098468", + "sha256:4269ce3d1b897d46fc3cc2273a0cc2a730345bb47e4456af662e6fca85c89dd7", + "sha256:65214fd668975077cdf8d408ccf2b2d6bdf73b4e6895a79f8e99ce4f0b43fcdb", + "sha256:74bc213ab8a92d86a0b304d9359d1e1d14168d4c6121b83862c9d8a88b89a738", + "sha256:88949be0db54755995dfb0210d0099a8712a3c696c860441971354c3debfc4af", + "sha256:8e1223d868be89423ec95ada5f37aa408ee64fe76ccb8e4d5f533699ba4c0e4a", + "sha256:9fa00f2d7a552a95fa6016e498fdeb6d74df537853dda79a9055c53dfc8b6e1a", + "sha256:c27fd46cab905097ba4bc28d5ba5289930f313fb1970c9d41092c9975b80e9b4", + "sha256:c94b792af431f6adb6859eb218137acd9a35f4f7442cea57e4a59c54751c36af", + "sha256:f4c12a01eb2dc16693887a874ba948b18c92f425c4d329639ece6d3bb8e631bb" + ], + "index": "pypi", + "version": "==3.0.2" + }, "mccabe": { "hashes": [ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", @@ -38,6 +105,35 @@ ], "version": "==0.6.1" }, + "numpy": { + "hashes": [ + "sha256:0cdbbaa30ae69281b18dd995d3079c4e552ad6d5426977f66b9a2a95f11f552a", + "sha256:2b0cca1049bd39d1879fa4d598624cafe82d35529c72de1b3d528d68031cdd95", + "sha256:31d3fe5b673e99d33d70cfee2ea8fe8dccd60f265c3ed990873a88647e3dd288", + "sha256:34dd4922aab246c39bf5df03ca653d6265e65971deca6784c956bf356bca6197", + "sha256:384e2dfa03da7c8d54f8f934f61b6a5e4e1ebb56a65b287567629d6c14578003", + "sha256:392e2ea22b41a22c0289a88053204b616181288162ba78e6823e1760309d5277", + "sha256:4341a39fc085f31a583be505eabf00e17c619b469fef78dc7e8241385bfddaa4", + "sha256:45080f065dcaa573ebecbfe13cdd86e8c0a68c4e999aa06bd365374ea7137706", + "sha256:485cb1eb4c9962f4cd042fed9424482ec1d83fee5dc2ef3f2552ac47852cb259", + "sha256:575cefd28d3e0da85b0864506ae26b06483ee4a906e308be5a7ad11083f9d757", + "sha256:62784b35df7de7ca4d0d81c5b6af5983f48c5cdef32fc3635b445674e56e3266", + "sha256:69c152f7c11bf3b4fc11bc4cc62eb0334371c0db6844ebace43b7c815b602805", + "sha256:6ccfdcefd287f252cf1ea7a3f1656070da330c4a5658e43ad223269165cdf977", + "sha256:7298fbd73c0b3eff1d53dc9b9bdb7add8797bb55eeee38c8ccd7906755ba28af", + "sha256:79463d918d1bf3aeb9186e3df17ddb0baca443f41371df422f99ee94f4f2bbfe", + "sha256:8bbee788d82c0ac656536de70e817af09b7694f5326b0ef08e5c1014fcb96bb3", + "sha256:a863957192855c4c57f60a75a1ac06ce5362ad18506d362dd807e194b4baf3ce", + "sha256:ae602ba425fb2b074e16d125cdce4f0194903da935b2e7fe284ebecca6d92e76", + "sha256:b13faa258b20fa66d29011f99fdf498641ca74a0a6d9266bc27d83c70fea4a6a", + "sha256:c2c39d69266621dd7464e2bb740d6eb5abc64ddc339cc97aa669f3bb4d75c103", + "sha256:e9c88f173d31909d881a60f08a8494e63f1aff2a4052476b24d4f50e82c47e24", + "sha256:f1a29267ac29fff0913de0f11f3a9edfcd3f39595f467026c29376fad243ebe3", + "sha256:f69dde0c5a137d887676a8129373e44366055cf19d1b434e853310c7a1e68f93" + ], + "index": "pypi", + "version": "==1.16.1" + }, "pycodestyle": { "hashes": [ "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", @@ -52,6 +148,13 @@ ], "version": "==2.1.0" }, + "pyparsing": { + "hashes": [ + "sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a", + "sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3" + ], + "version": "==2.3.1" + }, "pyqt5": { "hashes": [ "sha256:1402f1613698ca64e3cec0ee27a60b5454e782c16fbd1bdee4a270a058947939", @@ -78,6 +181,20 @@ "sha256:bb81cfc4d35ca59f1c419b6abeb6ca6a726a63b712cf979f2b5ab24b81c36f49" ], "version": "==4.19.14" + }, + "python-dateutil": { + "hashes": [ + "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", + "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" + ], + "version": "==2.8.0" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" } }, "develop": { diff --git a/project/Plugins/ImageOptimizer.py b/project/Plugins/ImageOptimizer.py new file mode 100644 index 00000000..69d7c565 --- /dev/null +++ b/project/Plugins/ImageOptimizer.py @@ -0,0 +1,27 @@ +# import the Python Image processing Library + +import numpy as np +import matplotlib.pylab as plt +from random import randint +import os + +class ImageOptimizer(): + + + #this is to check if the directory is a file + def _check_file(dir): + if os.path.isfile(dir) == True: + return True + else: + return False + + def _return_image(file_dir): + if ImageOptimizer._check_file(dir): + im = plt.imread(file_dir) + + return im.shape + + elif not ImageOptimizer._check_file(image_dir): + raise 'The file is not a directory, must be a file!' + +ImageOptimizer._return_image("C:/Users/Noahd/Desktop/images/bitmap.png") \ No newline at end of file diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index 9c8b6d8e..a7dcbc81 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,10 +1,18 @@ # Not done yet, feel free to change it :p +from random import randint class PredictiveText(): - def _update_text(text): + def _random_spelling_mistakes(text): text = text.split() - if 'hello' in text: - text[text.index('hello')] = 'help me' # Change this to what ever you want + print(text) + for word in text: + length = len(word) + if length == 1: + return + spot = randint(0, length - 1) + return text + +PredictiveText._random_spelling_mistakes('yelp hello I me') \ No newline at end of file From 74d1d9cc41eafe9fc9c23a657fc9fc5723951623 Mon Sep 17 00:00:00 2001 From: BWACpro Date: Sat, 23 Feb 2019 22:45:44 -0800 Subject: [PATCH 18/60] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 63ce0a01..2f8f9d81 100644 --- a/.gitignore +++ b/.gitignore @@ -107,4 +107,5 @@ venv.bak/ .idea/ # compiled sphinx HTML documentation -docs/build \ No newline at end of file +docs/build +.vscode/settings.json From e51a9d04b10cf46180c1cc35de620004fbda12ee Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sun, 24 Feb 2019 19:31:15 +1100 Subject: [PATCH 19/60] random_spelling_mistakes done :P random_spelling_mistakes done :P --- project/Plugins/PredictiveText.py | 45 ++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index a7dcbc81..b9102dc2 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,18 +1,37 @@ -# Not done yet, feel free to change it :p -from random import randint +from random import randint, choice +import string -class PredictiveText(): +def random_spelling_mistakes(text): + ''' + Usage: Will add random letters to words (only words above 2 letters) + then return the new sentence. - def _random_spelling_mistakes(text): - text = text.split() - print(text) - for word in text: - length = len(word) - if length == 1: - return - spot = randint(0, length - 1) + Example: - return text + print(random_spelling_mistakes('Hello, yes hi')) -PredictiveText._random_spelling_mistakes('yelp hello I me') \ No newline at end of file + Heqllo, yeVs hi + ''' + + # TODO: make it the same case as word changing, looks better + text = text.split() + new_words = '' + print(text) + for word in text: + if len(word) == 1 or len(word) == 2: + final = ''.join(word) + new_words = new_words + ' ' + final + else: + spot = randint(0, len(word) - 1) + if spot == 0: + '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get + removed''' + spot = randint(0, len(word) - 1) + if spot == 0: + pass + final = ''.join(word) + final = final[0:spot] + choice(string.ascii_letters) + final[spot:] + new_words = new_words + ' ' + final + return new_words + # TODO: there is a '.\PredictiveText.py:28:97: W291 trailing whitespace' and i cant resolve From 792171c71b8f0a517c5adfa96994572c7514b8ca Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sun, 24 Feb 2019 19:31:29 +1100 Subject: [PATCH 20/60] updates --- Pipfile | 4 - Pipfile.lock | 179 ++++++------------------------ project/Plugins/ImageOptimizer.py | 27 ----- 3 files changed, 31 insertions(+), 179 deletions(-) delete mode 100644 project/Plugins/ImageOptimizer.py diff --git a/Pipfile b/Pipfile index 96d9949e..9c0abe9f 100644 --- a/Pipfile +++ b/Pipfile @@ -11,10 +11,6 @@ sphinx = "*" [packages] pyqt5 = "*" flake8 = "*" -numpy = "*" -matplotlib = "*" -appdirs = "*" -random = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index ca32dd77..68d9999a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "21e017c60ddc597ea1bb99b1bafcd2da2029c1c689ab7b96d7642b8c45c8b9da" + "sha256": "17ce94e1fc71663d21aa757654ae465c3575be6c1b6275bb1f808794655b7e96" }, "pipfile-spec": 6, "requires": { @@ -16,21 +16,6 @@ ] }, "default": { - "appdirs": { - "hashes": [ - "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", - "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e" - ], - "index": "pypi", - "version": "==1.4.3" - }, - "cycler": { - "hashes": [ - "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d", - "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8" - ], - "version": "==0.10.0" - }, "entrypoints": { "hashes": [ "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", @@ -46,58 +31,6 @@ "index": "pypi", "version": "==3.7.6" }, - "kiwisolver": { - "hashes": [ - "sha256:0ee4ed8b3ae8f5f712b0aa9ebd2858b5b232f1b9a96b0943dceb34df2a223bc3", - "sha256:0f7f532f3c94e99545a29f4c3f05637f4d2713e7fd91b4dd8abfc18340b86cd5", - "sha256:1a078f5dd7e99317098f0e0d490257fd0349d79363e8c923d5bb76428f318421", - "sha256:1aa0b55a0eb1bd3fa82e704f44fb8f16e26702af1a073cc5030eea399e617b56", - "sha256:2874060b91e131ceeff00574b7c2140749c9355817a4ed498e82a4ffa308ecbc", - "sha256:379d97783ba8d2934d52221c833407f20ca287b36d949b4bba6c75274bcf6363", - "sha256:3b791ddf2aefc56382aadc26ea5b352e86a2921e4e85c31c1f770f527eb06ce4", - "sha256:4329008a167fac233e398e8a600d1b91539dc33c5a3eadee84c0d4b04d4494fa", - "sha256:45813e0873bbb679334a161b28cb9606d9665e70561fd6caa8863e279b5e464b", - "sha256:53a5b27e6b5717bdc0125338a822605084054c80f382051fb945d2c0e6899a20", - "sha256:574f24b9805cb1c72d02b9f7749aa0cc0b81aa82571be5201aa1453190390ae5", - "sha256:66f82819ff47fa67a11540da96966fb9245504b7f496034f534b81cacf333861", - "sha256:79e5fe3ccd5144ae80777e12973027bd2f4f5e3ae8eb286cabe787bed9780138", - "sha256:83410258eb886f3456714eea4d4304db3a1fc8624623fc3f38a487ab36c0f653", - "sha256:8b6a7b596ce1d2a6d93c3562f1178ebd3b7bb445b3b0dd33b09f9255e312a965", - "sha256:9576cb63897fbfa69df60f994082c3f4b8e6adb49cccb60efb2a80a208e6f996", - "sha256:95a25d9f3449046ecbe9065be8f8380c03c56081bc5d41fe0fb964aaa30b2195", - "sha256:a424f048bebc4476620e77f3e4d1f282920cef9bc376ba16d0b8fe97eec87cde", - "sha256:aaec1cfd94f4f3e9a25e144d5b0ed1eb8a9596ec36d7318a504d813412563a85", - "sha256:acb673eecbae089ea3be3dcf75bfe45fc8d4dcdc951e27d8691887963cf421c7", - "sha256:b15bc8d2c2848a4a7c04f76c9b3dc3561e95d4dabc6b4f24bfabe5fd81a0b14f", - "sha256:b1c240d565e977d80c0083404c01e4d59c5772c977fae2c483f100567f50847b", - "sha256:c595693de998461bcd49b8d20568c8870b3209b8ea323b2a7b0ea86d85864694", - "sha256:ce3be5d520b4d2c3e5eeb4cd2ef62b9b9ab8ac6b6fedbaa0e39cdb6f50644278", - "sha256:e0f910f84b35c36a3513b96d816e6442ae138862257ae18a0019d2fc67b041dc", - "sha256:ea36e19ac0a483eea239320aef0bd40702404ff8c7e42179a2d9d36c5afcb55c", - "sha256:efabbcd4f406b532206b8801058c8bab9e79645b9880329253ae3322b7b02cd5", - "sha256:f923406e6b32c86309261b8195e24e18b6a8801df0cfc7814ac44017bfcb3939" - ], - "version": "==1.0.1" - }, - "matplotlib": { - "hashes": [ - "sha256:16aa61846efddf91df623bbb4598e63be1068a6b6a2e6361cc802b41c7a286eb", - "sha256:1975b71a33ac986bb39b6d5cfbc15c7b1f218f1134efb4eb3881839d6ae69984", - "sha256:2b222744bd54781e6cc0b717fa35a54e5f176ba2ced337f27c5b435b334ef854", - "sha256:317643c0e88fad55414347216362b2e229c130edd5655fea5f8159a803098468", - "sha256:4269ce3d1b897d46fc3cc2273a0cc2a730345bb47e4456af662e6fca85c89dd7", - "sha256:65214fd668975077cdf8d408ccf2b2d6bdf73b4e6895a79f8e99ce4f0b43fcdb", - "sha256:74bc213ab8a92d86a0b304d9359d1e1d14168d4c6121b83862c9d8a88b89a738", - "sha256:88949be0db54755995dfb0210d0099a8712a3c696c860441971354c3debfc4af", - "sha256:8e1223d868be89423ec95ada5f37aa408ee64fe76ccb8e4d5f533699ba4c0e4a", - "sha256:9fa00f2d7a552a95fa6016e498fdeb6d74df537853dda79a9055c53dfc8b6e1a", - "sha256:c27fd46cab905097ba4bc28d5ba5289930f313fb1970c9d41092c9975b80e9b4", - "sha256:c94b792af431f6adb6859eb218137acd9a35f4f7442cea57e4a59c54751c36af", - "sha256:f4c12a01eb2dc16693887a874ba948b18c92f425c4d329639ece6d3bb8e631bb" - ], - "index": "pypi", - "version": "==3.0.2" - }, "mccabe": { "hashes": [ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", @@ -105,35 +38,6 @@ ], "version": "==0.6.1" }, - "numpy": { - "hashes": [ - "sha256:0cdbbaa30ae69281b18dd995d3079c4e552ad6d5426977f66b9a2a95f11f552a", - "sha256:2b0cca1049bd39d1879fa4d598624cafe82d35529c72de1b3d528d68031cdd95", - "sha256:31d3fe5b673e99d33d70cfee2ea8fe8dccd60f265c3ed990873a88647e3dd288", - "sha256:34dd4922aab246c39bf5df03ca653d6265e65971deca6784c956bf356bca6197", - "sha256:384e2dfa03da7c8d54f8f934f61b6a5e4e1ebb56a65b287567629d6c14578003", - "sha256:392e2ea22b41a22c0289a88053204b616181288162ba78e6823e1760309d5277", - "sha256:4341a39fc085f31a583be505eabf00e17c619b469fef78dc7e8241385bfddaa4", - "sha256:45080f065dcaa573ebecbfe13cdd86e8c0a68c4e999aa06bd365374ea7137706", - "sha256:485cb1eb4c9962f4cd042fed9424482ec1d83fee5dc2ef3f2552ac47852cb259", - "sha256:575cefd28d3e0da85b0864506ae26b06483ee4a906e308be5a7ad11083f9d757", - "sha256:62784b35df7de7ca4d0d81c5b6af5983f48c5cdef32fc3635b445674e56e3266", - "sha256:69c152f7c11bf3b4fc11bc4cc62eb0334371c0db6844ebace43b7c815b602805", - "sha256:6ccfdcefd287f252cf1ea7a3f1656070da330c4a5658e43ad223269165cdf977", - "sha256:7298fbd73c0b3eff1d53dc9b9bdb7add8797bb55eeee38c8ccd7906755ba28af", - "sha256:79463d918d1bf3aeb9186e3df17ddb0baca443f41371df422f99ee94f4f2bbfe", - "sha256:8bbee788d82c0ac656536de70e817af09b7694f5326b0ef08e5c1014fcb96bb3", - "sha256:a863957192855c4c57f60a75a1ac06ce5362ad18506d362dd807e194b4baf3ce", - "sha256:ae602ba425fb2b074e16d125cdce4f0194903da935b2e7fe284ebecca6d92e76", - "sha256:b13faa258b20fa66d29011f99fdf498641ca74a0a6d9266bc27d83c70fea4a6a", - "sha256:c2c39d69266621dd7464e2bb740d6eb5abc64ddc339cc97aa669f3bb4d75c103", - "sha256:e9c88f173d31909d881a60f08a8494e63f1aff2a4052476b24d4f50e82c47e24", - "sha256:f1a29267ac29fff0913de0f11f3a9edfcd3f39595f467026c29376fad243ebe3", - "sha256:f69dde0c5a137d887676a8129373e44366055cf19d1b434e853310c7a1e68f93" - ], - "index": "pypi", - "version": "==1.16.1" - }, "pycodestyle": { "hashes": [ "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", @@ -148,13 +52,6 @@ ], "version": "==2.1.0" }, - "pyparsing": { - "hashes": [ - "sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a", - "sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3" - ], - "version": "==2.3.1" - }, "pyqt5": { "hashes": [ "sha256:1402f1613698ca64e3cec0ee27a60b5454e782c16fbd1bdee4a270a058947939", @@ -181,20 +78,6 @@ "sha256:bb81cfc4d35ca59f1c419b6abeb6ca6a726a63b712cf979f2b5ab24b81c36f49" ], "version": "==4.19.14" - }, - "python-dateutil": { - "hashes": [ - "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", - "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" - ], - "version": "==2.8.0" - }, - "six": { - "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" - ], - "version": "==1.12.0" } }, "develop": { @@ -294,36 +177,36 @@ }, "markupsafe": { "hashes": [ - "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", - "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", - "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", - "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", - "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", - "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", - "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", - "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", - "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", - "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", - "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", - "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", - "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", - "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", - "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", - "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", - "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", - "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", - "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", - "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", - "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", - "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", - "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", - "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", - "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", - "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", - "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", - "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" - ], - "version": "==1.1.0" + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" + ], + "version": "==1.1.1" }, "mccabe": { "hashes": [ diff --git a/project/Plugins/ImageOptimizer.py b/project/Plugins/ImageOptimizer.py deleted file mode 100644 index 69d7c565..00000000 --- a/project/Plugins/ImageOptimizer.py +++ /dev/null @@ -1,27 +0,0 @@ -# import the Python Image processing Library - -import numpy as np -import matplotlib.pylab as plt -from random import randint -import os - -class ImageOptimizer(): - - - #this is to check if the directory is a file - def _check_file(dir): - if os.path.isfile(dir) == True: - return True - else: - return False - - def _return_image(file_dir): - if ImageOptimizer._check_file(dir): - im = plt.imread(file_dir) - - return im.shape - - elif not ImageOptimizer._check_file(image_dir): - raise 'The file is not a directory, must be a file!' - -ImageOptimizer._return_image("C:/Users/Noahd/Desktop/images/bitmap.png") \ No newline at end of file From 74a68b97a0bf6d06f01d6b0ff7e913c474594327 Mon Sep 17 00:00:00 2001 From: kaleidagraph <26967284+kaleidagraph@users.noreply.github.com> Date: Sun, 24 Feb 2019 09:42:35 +0000 Subject: [PATCH 21/60] fixed typo in linter settings --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index b1663a2f..ce02b1f3 100644 --- a/.flake8 +++ b/.flake8 @@ -1,6 +1,6 @@ [flake8] max-line-length=100 -application_import_names=projectt +application_import_names=project ignore=P102,B311,W503,E226,S311,W504,F821 exclude=__pycache__, venv, .venv, tests import-order-style=pycharm From 8d7dd0ccde456809b263046397efcfe990be3b2c Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Mon, 25 Feb 2019 00:50:10 +0800 Subject: [PATCH 22/60] Display copied text as a custom widget with date and index information --- project/Plugins/PredictiveText.py | 8 +++--- project/Widgets/MainListWidget.py | 41 ++++++++++++++++++++++++++++++- project/__main__.py | 15 ++++++----- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index b9102dc2..86eb8f5c 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -3,7 +3,7 @@ def random_spelling_mistakes(text): - ''' + """ Usage: Will add random letters to words (only words above 2 letters) then return the new sentence. @@ -12,7 +12,7 @@ def random_spelling_mistakes(text): print(random_spelling_mistakes('Hello, yes hi')) Heqllo, yeVs hi - ''' + """ # TODO: make it the same case as word changing, looks better text = text.split() @@ -25,8 +25,8 @@ def random_spelling_mistakes(text): else: spot = randint(0, len(word) - 1) if spot == 0: - '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get - removed''' + '''Give it two chances to not be 0, I think its better + if its mostly the middle letters that get removed''' spot = randint(0, len(word) - 1) if spot == 0: pass diff --git a/project/Widgets/MainListWidget.py b/project/Widgets/MainListWidget.py index 3c8ac3d6..5457c3fd 100644 --- a/project/Widgets/MainListWidget.py +++ b/project/Widgets/MainListWidget.py @@ -5,10 +5,49 @@ .. moduleauthor:: TBD """ -from PyQt5.QtWidgets import QListWidget +from PyQt5.QtWidgets import QListWidget, QWidget, QHBoxLayout, QLabel, QVBoxLayout, QSizePolicy + +from project.ClipboardManager.ClipboardObject import TextClipboardObject class MainListWidget(QListWidget): def __init__(self): super().__init__() self.addItem("Sample Item") + + +# https://www.pythoncentral.io/pyside-pyqt-tutorial-the-qlistwidget/ +# Or it can be created with the list as a parent, then automatically added to the list +# Or... https://stackoverflow.com/questions/25187444/pyqt-qlistwidget-custom-items +class TextListWidgetItem(QWidget): + """A row in the scrollview of the actual widget.""" + + def __init__(self, index: int, obj: TextClipboardObject, parent=None): + super(TextListWidgetItem, self).__init__(parent) + + self._main_hbox_layout = QHBoxLayout() + + self._right_section = QWidget() + self._right_vbox_layout = QVBoxLayout() + + self._text_area = QLabel() + # self._text_area.setReadOnly(True) + self._text_area.setText(obj.text) + + self._date_label = QLabel() + self._date_label.setText(obj.date().strftime("%Y-%m-%d %H:%M:%S")) + + # Date should be at the bottom. + self._right_vbox_layout.addWidget(self._text_area) + self._right_vbox_layout.addWidget(self._date_label) + + self._right_section.setLayout(self._right_vbox_layout) + self._right_section.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + + self._index_label = QLabel() + self._index_label.setText(str(index)) + + self._main_hbox_layout.addWidget(self._index_label) + self._main_hbox_layout.addWidget(self._right_section) + + self.setLayout(self._main_hbox_layout) diff --git a/project/__main__.py b/project/__main__.py index dc344b0c..3e340fe7 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,12 +1,12 @@ from PyQt5.QtWidgets import QMainWindow, QApplication, \ - QHBoxLayout, QVBoxLayout, QWidget + QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem import sys from project import ClipboardManager from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack -from project.Widgets.MainListWidget import MainListWidget +from project.Widgets.MainListWidget import MainListWidget, TextListWidgetItem from .utils import CONSTANTS from PyQt5 import QtCore, QtWidgets @@ -69,11 +69,14 @@ def _init_ui(self): def _render_clipboard_stack(self, clipboard_stack: Stack): self._main_list_widget.clear() - for clipboard_object in clipboard_stack.items(): + for (idx, clipboard_object) in enumerate(clipboard_stack.items()): if isinstance(clipboard_object, TextClipboardObject): - self._main_list_widget.addItem(clipboard_object.text + " " - + clipboard_object - .date().strftime("%Y-%m-%d %H:%M:%S")) + _item = QListWidgetItem(self._main_list_widget) + _custom_item = TextListWidgetItem(idx, clipboard_object) + _item.setSizeHint(_custom_item.sizeHint()) + + self._main_list_widget.addItem(_item) + self._main_list_widget.setItemWidget(_item, _custom_item) def setupUi(self): # MainWindow.setObjectName("MainWindow") From 86ca0538997a0cc69e0c6100b55074f009b1ca8a Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Mon, 25 Feb 2019 17:29:54 +1100 Subject: [PATCH 23/60] Inserted spelling mestakes :p --- Pipfile.lock | 6 +++--- project/ClipboardManager/ClipboardManager.py | 7 ++++++- project/Plugins/PredictiveText.py | 11 ++++++----- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 68d9999a..3e332166 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -232,10 +232,10 @@ }, "pluggy": { "hashes": [ - "sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616", - "sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a" + "sha256:19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f", + "sha256:84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746" ], - "version": "==0.8.1" + "version": "==0.9.0" }, "py": { "hashes": [ diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 283ef658..03655e47 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -3,6 +3,7 @@ from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack +from project.Plugins import PredictiveText class ClipboardManager: @@ -13,7 +14,11 @@ def __init__(self): self._clipboard_stack = Stack() def _clipboard_changed(self): - current_text = QApplication.clipboard().text() + + # testing by BWACpro + + # current_text = QApplication.clipboard().text() + current_text = PredictiveText.random_spelling_mistakes(QApplication.clipboard().text()) print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index 86eb8f5c..553e554d 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -12,12 +12,11 @@ def random_spelling_mistakes(text): print(random_spelling_mistakes('Hello, yes hi')) Heqllo, yeVs hi - """ - # TODO: make it the same case as word changing, looks better + I is very fast. A string of 7712 characters only took 0.006994724273681641 seconds to process. + """ text = text.split() new_words = '' - print(text) for word in text: if len(word) == 1 or len(word) == 2: final = ''.join(word) @@ -31,7 +30,9 @@ def random_spelling_mistakes(text): if spot == 0: pass final = ''.join(word) - final = final[0:spot] + choice(string.ascii_letters) + final[spot:] + if spot > 0: + final = final[0:spot] + choice(string.ascii_letters.lower()) + final[spot:] + elif spot == 0: + final = final[0:spot] + choice(string.ascii_letters.upper()) + final[spot:] new_words = new_words + ' ' + final return new_words - # TODO: there is a '.\PredictiveText.py:28:97: W291 trailing whitespace' and i cant resolve From 3ad89ae13162c8210e008271fcfb79b2ae953845 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Tue, 26 Feb 2019 07:44:44 +1100 Subject: [PATCH 24/60] General clean up and twitch quotes coming :p --- project/Plugins/PredictiveText.py | 13 +++++- project/__main__.py | 67 ++----------------------------- 2 files changed, 15 insertions(+), 65 deletions(-) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index 553e554d..fbb61f1f 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,6 +1,8 @@ from random import randint, choice import string +quotes = ['O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo EEEEO-A-AAA-AAAA'] + def random_spelling_mistakes(text): """ @@ -11,7 +13,7 @@ def random_spelling_mistakes(text): print(random_spelling_mistakes('Hello, yes hi')) - Heqllo, yeVs hi + Heqllo, yess hi I is very fast. A string of 7712 characters only took 0.006994724273681641 seconds to process. """ @@ -36,3 +38,12 @@ def random_spelling_mistakes(text): final = final[0:spot] + choice(string.ascii_letters.upper()) + final[spot:] new_words = new_words + ' ' + final return new_words + + +def twitch_quote(text): + b = randint(0, 27) + text = quotes[b] + + return text + +print(twitch_quote('Hello')) diff --git a/project/__main__.py b/project/__main__.py index 3e340fe7..35df8dee 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -12,8 +12,7 @@ from PyQt5 import QtCore, QtWidgets -# print("hello %s" % sys.argv[1]) -# print(add(2, 2)) +'''I (BWACpro) removed a lot a of comments, if i was important, uh go find a earlier commit''' class ActionBar(QWidget): def __init__(self): @@ -21,19 +20,13 @@ def __init__(self): _horizontal_layout = QHBoxLayout(self) self._add_btn = QtWidgets.QPushButton("Add") - # self._add_btn.setGeometry(QtCore.QRect(0, 3, 51, 20)) - # self._add_btn.clicked.connect(self._add_object) self._add_btn.setObjectName(MainWindow.ADD_BUTTON_NAME) - # self._add_btn.setStyleSheet("QPushButton {background-color: yellow, margin: 0}") self._remove_btn = QtWidgets.QPushButton("Remove") - # self._remove_btn.setGeometry(QtCore.QRect(50, 3, 51, 20)) - # self._remove_btn.clicked.connect() self._remove_btn.setObjectName(MainWindow.REMOVE_BUTTON_NAME) self._edit_btn = QtWidgets.QPushButton("Edit") - # self._edit_btn.setGeometry(QtCore.QRect(100, 3, 51, 20)) self._edit_btn.setObjectName(MainWindow.EDIT_BUTTON_NAME) _horizontal_layout.addWidget(self._add_btn) @@ -63,7 +56,6 @@ def __init__(self, clipboard_manager: ClipboardManager): def _init_ui(self): self.setWindowTitle(CONSTANTS['NAME']) - # self.setGeometry(self.left, self.top, self.width, self.height) self.setupUi() self.show() @@ -79,8 +71,6 @@ def _render_clipboard_stack(self, clipboard_stack: Stack): self._main_list_widget.setItemWidget(_item, _custom_item) def setupUi(self): - # MainWindow.setObjectName("MainWindow") - # self.setFixedSize(640, 480) self._central_widget.setObjectName(MainWindow.CENTRAL_WIDGET_NAME) self._action_bar = ActionBar() @@ -88,46 +78,11 @@ def setupUi(self): self._main_list_widget = MainListWidget() self._central_widget_layout.addWidget(self._main_list_widget) - # self._central_widget_layout.addStretch(1) - - # self.Add = QtWidgets.QPushButton(self._central_widget) - # self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) - # self.Add.clicked.connect(self.addObject) - # self.Add.setObjectName("Add") - - # self.Remove = QtWidgets.QPushButton(self._central_widget) - # self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) - # self.Remove.clicked.connect(self.removeObject) - # self.Remove.setObjectName("Remove") - # - # self.Edit = QtWidgets.QPushButton(self._central_widget) - # self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) - # self.Edit.setObjectName("Edit") - - # self.treeWidget = QtWidgets.QTreeWidget(self._central_widget) - # self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) - # self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) - # self.treeWidget.setObjectName("treeWidget") self.menubar = self.menuBar() - # self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) - # self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") - # self.menuPlugins = QtWidgets.QMenu(self.menubar) - # self.menuPlugins.setObjectName("menuPlugins") - # self.menuItem = QtWidgets.QMenu(self.menubar) - # self.menuItem.setObjectName("menuItem") - # self.setMenuBar(self.menubar) - # self.statusbar = QtWidgets.QStatusBar(self) - # self.statusbar.setObjectName("statusbar") - # self.setStatusBar(self.statusbar) - # self.actionAdd = QtWidgets.QAction(self) - # self.actionAdd.setObjectName("actionAdd") - # self.actionDelete = QtWidgets.QAction(self) - # self.actionDelete.setObjectName("actionDelete") - # self.action_todo = QtWidgets.QAction(self) - # self.action_todo.setObjectName("action_todo") + self.actionSettings = QtWidgets.QAction(self) self.actionSettings.setObjectName("actionSettings") # self.actionAdd_2 = QtWidgets.QAction(self) @@ -139,8 +94,7 @@ def setupUi(self): # self.menuItem.addAction(self.actionAdd_2) # self.menuItem.addAction(self.actionRemove) self.menubar.addAction(self.menuFile.menuAction()) - # self.menubar.addAction(self.menuPlugins.menuAction()) - # self.menubar.addAction(self.menuItem.menuAction()) + self._central_widget.setLayout(self._central_widget_layout) self.setCentralWidget(self._central_widget) @@ -171,21 +125,6 @@ def retranslateUi(self): # self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) # self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) - # def _add_object(self): - # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - # self.num_of_objects + 1 - # def removeObject(self): - # # TODO make it remove instead of add - # - # if self.items == []: - # return - # - # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - # - # self.num_of_objects + 1 - if __name__ == '__main__': app = QApplication(sys.argv) From 71cc28295e6431cd54ab665058212a81b2376ddf Mon Sep 17 00:00:00 2001 From: kaleidagraph <26967284+kaleidagraph@users.noreply.github.com> Date: Tue, 26 Feb 2019 14:07:12 +0000 Subject: [PATCH 25/60] Tidied up the main file. Still a lot commented out and the menu bar does not have members?? --- project/__main__.py | 53 +++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/project/__main__.py b/project/__main__.py index 35df8dee..b3fa6346 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,5 +1,5 @@ -from PyQt5.QtWidgets import QMainWindow, QApplication, \ - QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem +from PyQt5.QtWidgets import QMainWindow, QApplication, QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem +from PyQt5 import QtCore, QtWidgets import sys @@ -9,19 +9,17 @@ from project.Widgets.MainListWidget import MainListWidget, TextListWidgetItem from .utils import CONSTANTS -from PyQt5 import QtCore, QtWidgets - - +# Put this in the commit message not the code @BWACpro '''I (BWACpro) removed a lot a of comments, if i was important, uh go find a earlier commit''' class ActionBar(QWidget): + """ A bar which contains the controls for adding to this list of clipboard items""" def __init__(self): super().__init__() _horizontal_layout = QHBoxLayout(self) self._add_btn = QtWidgets.QPushButton("Add") - self._add_btn.setObjectName(MainWindow.ADD_BUTTON_NAME) - + self._add_btn.setObjectName(MainWindow.ADD_BUTTON_NAME) # can we not do this in the constructor? self._remove_btn = QtWidgets.QPushButton("Remove") self._remove_btn.setObjectName(MainWindow.REMOVE_BUTTON_NAME) @@ -36,15 +34,19 @@ def __init__(self): class MainWindow(QMainWindow): + """ MainWindow """ + # strange constants: CENTRAL_WIDGET_NAME = 'central_widget' ADD_BUTTON_NAME = 'add_btn' REMOVE_BUTTON_NAME = 'remove_btn' EDIT_BUTTON_NAME = 'edit_btn' + # please label what these are / relate to: num_of_objects = 0 items = [] def __init__(self, clipboard_manager: ClipboardManager): + """ Initialises new MainWindow class """ super().__init__() self._central_widget_layout = QVBoxLayout() @@ -55,22 +57,11 @@ def __init__(self, clipboard_manager: ClipboardManager): self._init_ui() def _init_ui(self): - self.setWindowTitle(CONSTANTS['NAME']) - self.setupUi() - self.show() + """ Creates UI """ - def _render_clipboard_stack(self, clipboard_stack: Stack): - self._main_list_widget.clear() - for (idx, clipboard_object) in enumerate(clipboard_stack.items()): - if isinstance(clipboard_object, TextClipboardObject): - _item = QListWidgetItem(self._main_list_widget) - _custom_item = TextListWidgetItem(idx, clipboard_object) - _item.setSizeHint(_custom_item.sizeHint()) - - self._main_list_widget.addItem(_item) - self._main_list_widget.setItemWidget(_item, _custom_item) + self.setWindowTitle(CONSTANTS['NAME']) # can we not pass this as a argument in the super of the constructor? - def setupUi(self): + # No idea what all these widgets are. Please clarify and comment around BWAC? self._central_widget.setObjectName(MainWindow.CENTRAL_WIDGET_NAME) self._action_bar = ActionBar() @@ -79,6 +70,7 @@ def setupUi(self): self._main_list_widget = MainListWidget() self._central_widget_layout.addWidget(self._main_list_widget) + # menu bar has no members? self.menubar = self.menuBar() self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") @@ -95,7 +87,6 @@ def setupUi(self): # self.menuItem.addAction(self.actionRemove) self.menubar.addAction(self.menuFile.menuAction()) - self._central_widget.setLayout(self._central_widget_layout) self.setCentralWidget(self._central_widget) @@ -105,7 +96,12 @@ def setupUi(self): # Better to use new-style decorator @QtCore.pyqtSlot() # QtCore.QMetaObject.connectSlotsByName(self) + self.show() + + # temp? def retranslateUi(self): + """ @transfusion What does this do?""" + _translate = QtCore.QCoreApplication.translate # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) # self._add_btn.setText(_translate("MainWindow", "Add")) @@ -125,11 +121,20 @@ def retranslateUi(self): # self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) # self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + def _render_clipboard_stack(self, clipboard_stack: Stack): + """ Renders the clipboard stack. no idea??""" + self._main_list_widget.clear() + for (idx, clipboard_object) in enumerate(clipboard_stack.items()): + if isinstance(clipboard_object, TextClipboardObject): + _item = QListWidgetItem(self._main_list_widget) + _custom_item = TextListWidgetItem(idx, clipboard_object) + _item.setSizeHint(_custom_item.sizeHint()) + + self._main_list_widget.addItem(_item) + self._main_list_widget.setItemWidget(_item, _custom_item) if __name__ == '__main__': app = QApplication(sys.argv) - # label = QLabel('Hello World!') - # label.show() clipboard_mgr = ClipboardManager.ClipboardManager() main_window = MainWindow(clipboard_mgr) From 1b286ee831a0395a6ca2cfb977b2f5b2b293110f Mon Sep 17 00:00:00 2001 From: kaleidagraph <26967284+kaleidagraph@users.noreply.github.com> Date: Tue, 26 Feb 2019 14:20:56 +0000 Subject: [PATCH 26/60] more tidying up, please read some of the comments made --- project/ClipboardManager/ClipboardManager.py | 3 +-- project/Plugins/PredictiveText.py | 3 --- project/Stack/Stack.py | 18 ++++++++++++------ project/Widgets/__init__.py | 0 4 files changed, 13 insertions(+), 11 deletions(-) delete mode 100644 project/Widgets/__init__.py diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 03655e47..76d0b9f6 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -22,8 +22,7 @@ def _clipboard_changed(self): print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) - if current_text and not (isinstance(self._clipboard_stack.peek(), TextClipboardObject) - and self._clipboard_stack.peek().text == current_text): + if current_text and not (isinstance(self._clipboard_stack.peek(), TextClipboardObject) and self._clipboard_stack.peek().text == current_text): self._clipboard_stack.push_item(TextClipboardObject(current_text)) if self._clipboard_state_callback is not None: diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index fbb61f1f..86e4d9f4 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -43,7 +43,4 @@ def random_spelling_mistakes(text): def twitch_quote(text): b = randint(0, 27) text = quotes[b] - return text - -print(twitch_quote('Hello')) diff --git a/project/Stack/Stack.py b/project/Stack/Stack.py index 307961f9..43487bfd 100644 --- a/project/Stack/Stack.py +++ b/project/Stack/Stack.py @@ -8,15 +8,16 @@ class Stack: + """ A collection of strings/other objects """ + # if it is a collection please consider adding magic methods for this (e.g. "__len__", "__iter__",...) + class SHIFT_DIRECTION(enum.Enum): UP: 1 DOWN: 2 - def __init__(self, existing_stack=None, cur_stack_pointer=None): - if existing_stack: - self._stack = existing_stack - else: - self._stack = [] + def __init__(self, existing_stack=[], cur_stack_pointer=None): + # Stack is backwards??? + self._stack = existing_stack if cur_stack_pointer: self._stack_pointer = cur_stack_pointer @@ -24,16 +25,20 @@ def __init__(self, existing_stack=None, cur_stack_pointer=None): # By default the stack pointer is at the top of the stack self._stack_pointer = len(self._stack) - 1 + # this should be __iter__ def items(self): return self._stack + # this should be __setitem__ def set_current_item(self, idx): + # What does idx relate to if not 0 <= idx < len(self._stack): raise Exception("Index is out of bounds") self._stack_pointer = idx def shift_current_item(self, idx, shift_direction: SHIFT_DIRECTION): + # again what does idx relate to _temp = self._stack[self._stack_pointer] if shift_direction == Stack.SHIFT_DIRECTION.UP: self._stack[idx] = self._stack[idx + 1] @@ -51,10 +56,11 @@ def swap_items(self, idx, target_idx): def push_item(self, item): self._stack.append(item) + # this should be __getitem__ def peek(self): if not self._stack: return None - return self._stack[-1] + return self._stack[-1] # if we reverse stack at start we won't have to do this def pop(self): return self._stack.pop() diff --git a/project/Widgets/__init__.py b/project/Widgets/__init__.py deleted file mode 100644 index e69de29b..00000000 From e70654604f47d526b9c34fe28eff5f1af21aba57 Mon Sep 17 00:00:00 2001 From: kaleidagraph <26967284+kaleidagraph@users.noreply.github.com> Date: Tue, 26 Feb 2019 16:33:35 +0000 Subject: [PATCH 27/60] Systray works but fails on close due to callback issue --- .gitignore | 3 +++ project/SystrayManager/Systray.py | 28 ++++++++++++++++++++++++++++ project/__main__.py | 11 +++++++++++ 3 files changed, 42 insertions(+) create mode 100644 project/SystrayManager/Systray.py diff --git a/.gitignore b/.gitignore index 2f8f9d81..47482d5d 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,6 @@ venv.bak/ # compiled sphinx HTML documentation docs/build .vscode/settings.json + +# test icon +project/tempicon.ico diff --git a/project/SystrayManager/Systray.py b/project/SystrayManager/Systray.py new file mode 100644 index 00000000..ece99d7c --- /dev/null +++ b/project/SystrayManager/Systray.py @@ -0,0 +1,28 @@ +from infi.systray import SysTrayIcon + +class systray: + """ Class which contains logic for a system tray interactive icon""" + + # temp icon & name + icon = "project\\tempicon.ico" + name = "Example tray icon" + + def __init__(self, closecallback): + # in future will have an function as a argument to work with rest of app + + # temp options for right click + menu_options = (("Say Hello", None, self.say_hello),) + self.systray = SysTrayIcon(self.icon, self.name, menu_options, on_quit=closecallback) + + def say_hello(self, systray): + print("Hello, World!") + + def start(self): + """ Starts systray icon""" + self.systray.start() + + def close(self): + """ Closes systray icon""" + self.systray.shutdown() + # this function also runs the callback:( + \ No newline at end of file diff --git a/project/__main__.py b/project/__main__.py index b3fa6346..94612a23 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -7,6 +7,7 @@ from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack from project.Widgets.MainListWidget import MainListWidget, TextListWidgetItem +from project.SystrayManager import Systray from .utils import CONSTANTS # Put this in the commit message not the code @BWACpro @@ -132,6 +133,11 @@ def _render_clipboard_stack(self, clipboard_stack: Stack): self._main_list_widget.addItem(_item) self._main_list_widget.setItemWidget(_item, _custom_item) + + def closeEvent(self, event): + """ Fires on window close""" + pass + if __name__ == '__main__': app = QApplication(sys.argv) @@ -139,4 +145,9 @@ def _render_clipboard_stack(self, clipboard_stack: Stack): clipboard_mgr = ClipboardManager.ClipboardManager() main_window = MainWindow(clipboard_mgr) + # Creates and starts systray icon + # systray = Systray.systray(app.quit) + # systray.start() + # app.aboutToQuit.connect(systray.close) + sys.exit(app.exec_()) From bc1c25eb183481e8e827017c526f9144998e0feb Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Wed, 27 Feb 2019 09:44:40 +0800 Subject: [PATCH 28/60] Fix linting, refactor to use qt slots and code remove item --- project/ClipboardManager/ClipboardManager.py | 59 +++++++--- project/Plugins/PredictiveText.py | 5 +- project/Stack/Stack.py | 14 ++- project/Widgets/MainListWidget.py | 2 +- project/__main__.py | 118 ++++++++++++++++++- 5 files changed, 171 insertions(+), 27 deletions(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 03655e47..1b58cea3 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -1,35 +1,62 @@ """Class encapsulating clipboard events""" from PyQt5.Qt import QApplication, QClipboard # noqa: F401 +from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack -from project.Plugins import PredictiveText +# import logging -class ClipboardManager: + +# https://stackoverflow.com/questions/36522809/ +# pyqt5-connection-doesnt-work-item-cannot-be-converted-to-pyqt5-qtcore-qobject +class ClipboardManager(QObject): + clipboard_changed_signal = pyqtSignal(Stack) def __init__(self): + super().__init__() self._clipboard_state_callback = None QApplication.clipboard().dataChanged.connect(self._clipboard_changed) - self._clipboard_stack = Stack() + self.clipboard_stack = Stack() + @pyqtSlot() def _clipboard_changed(self): - - # testing by BWACpro - - # current_text = QApplication.clipboard().text() - current_text = PredictiveText.random_spelling_mistakes(QApplication.clipboard().text()) + current_text = QApplication.clipboard().text() print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) - if current_text and not (isinstance(self._clipboard_stack.peek(), TextClipboardObject) - and self._clipboard_stack.peek().text == current_text): - self._clipboard_stack.push_item(TextClipboardObject(current_text)) + if current_text and not (isinstance(self.clipboard_stack.peek(), TextClipboardObject) + and self.clipboard_stack.peek().text == current_text): + self.clipboard_stack.push_item(TextClipboardObject(current_text)) + self.clipboard_changed_signal.emit(self.clipboard_stack) - if self._clipboard_state_callback is not None: - self._clipboard_state_callback(self._clipboard_stack) + # if self._clipboard_state_callback is not None: + # self._clipboard_state_callback(self._clipboard_stack) - # TODO: use Qt signals properly + # DONE: use Qt signals properly # https://stackoverflow.com/questions/36434706/pyqt-proper-use-of-emit-and-pyqtsignal - def bind_clipboard_state_callback(self, function): - self._clipboard_state_callback = function + # def bind_clipboard_state_callback(self, function): + # self._clipboard_state_callback = function + + def set_selected_object(self, idx): + if not 0 <= idx < self.clipboard_stack.items_count(): + raise Exception("Index is out of bounds") + + """Highlights a particular row in the main window""" + self.clipboard_stack.set_current_item(idx) + + def remove_clipboard_item(self): + """Public function to remove a clipboard item""" + self._remove_clipboard_item(self.clipboard_stack.current_item()) + self.clipboard_changed_signal.emit(self.clipboard_stack) + + def _remove_clipboard_item(self, idx): + """Helper function to remove a item from the stack""" + if not self.clipboard_stack.items_count(): + return + + if not 0 <= idx < self.clipboard_stack.items_count(): + raise Exception("Index is out of bounds") + + self.clipboard_stack.pop(idx) + self.clipboard_changed_signal.emit(self.clipboard_stack) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index fbb61f1f..df5e414c 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,7 +1,8 @@ from random import randint, choice import string -quotes = ['O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo EEEEO-A-AAA-AAAA'] +quotes = ['O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee ' + + 'AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo EEEEO-A-AAA-AAAA'] def random_spelling_mistakes(text): @@ -46,4 +47,4 @@ def twitch_quote(text): return text -print(twitch_quote('Hello')) +# print(twitch_quote('Hello')) diff --git a/project/Stack/Stack.py b/project/Stack/Stack.py index 307961f9..9cf18bf6 100644 --- a/project/Stack/Stack.py +++ b/project/Stack/Stack.py @@ -27,12 +27,18 @@ def __init__(self, existing_stack=None, cur_stack_pointer=None): def items(self): return self._stack + def items_count(self): + return len(self._stack) + def set_current_item(self, idx): if not 0 <= idx < len(self._stack): raise Exception("Index is out of bounds") self._stack_pointer = idx + def current_item(self): + return self._stack_pointer + def shift_current_item(self, idx, shift_direction: SHIFT_DIRECTION): _temp = self._stack[self._stack_pointer] if shift_direction == Stack.SHIFT_DIRECTION.UP: @@ -50,14 +56,18 @@ def swap_items(self, idx, target_idx): def push_item(self, item): self._stack.append(item) + if self.items_count() == 1: + self.set_current_item(0) def peek(self): if not self._stack: return None return self._stack[-1] - def pop(self): - return self._stack.pop() + def pop(self, index=-1): + self._stack_pointer = max(0, self._stack_pointer-1) + + return self._stack.pop(index) def clear(self): self._stack = [] diff --git a/project/Widgets/MainListWidget.py b/project/Widgets/MainListWidget.py index 5457c3fd..6c96097f 100644 --- a/project/Widgets/MainListWidget.py +++ b/project/Widgets/MainListWidget.py @@ -13,7 +13,7 @@ class MainListWidget(QListWidget): def __init__(self): super().__init__() - self.addItem("Sample Item") + # self.addItem("Sample Item") # https://www.pythoncentral.io/pyside-pyqt-tutorial-the-qlistwidget/ diff --git a/project/__main__.py b/project/__main__.py index 35df8dee..ceb281fb 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,3 +1,4 @@ +from PyQt5.QtCore import pyqtSlot, pyqtSignal from PyQt5.QtWidgets import QMainWindow, QApplication, \ QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem @@ -12,7 +13,8 @@ from PyQt5 import QtCore, QtWidgets -'''I (BWACpro) removed a lot a of comments, if i was important, uh go find a earlier commit''' +# print("hello %s" % sys.argv[1]) +# print(add(2, 2)) class ActionBar(QWidget): def __init__(self): @@ -20,26 +22,48 @@ def __init__(self): _horizontal_layout = QHBoxLayout(self) self._add_btn = QtWidgets.QPushButton("Add") + # self._add_btn.setGeometry(QtCore.QRect(0, 3, 51, 20)) + # self._add_btn.clicked.connect(self._add_object) self._add_btn.setObjectName(MainWindow.ADD_BUTTON_NAME) + # self._add_btn.setStyleSheet("QPushButton {background-color: yellow, margin: 0}") self._remove_btn = QtWidgets.QPushButton("Remove") + # self._remove_btn.setGeometry(QtCore.QRect(50, 3, 51, 20)) + # self._remove_btn.clicked.connect() self._remove_btn.setObjectName(MainWindow.REMOVE_BUTTON_NAME) self._edit_btn = QtWidgets.QPushButton("Edit") + # self._edit_btn.setGeometry(QtCore.QRect(100, 3, 51, 20)) self._edit_btn.setObjectName(MainWindow.EDIT_BUTTON_NAME) + self._move_up_btn = QtWidgets.QPushButton("Move Up") + self._move_up_btn.setObjectName(MainWindow.MOVE_UP_BUTTON_NAME) + + self._move_down_btn = QtWidgets.QPushButton("Move Down") + self._move_down_btn.setObjectName(MainWindow.MOVE_DOWN_BUTTON_NAME) + _horizontal_layout.addWidget(self._add_btn) _horizontal_layout.addWidget(self._remove_btn) _horizontal_layout.addWidget(self._edit_btn) + _horizontal_layout.addWidget(self._move_up_btn) + _horizontal_layout.addWidget(self._move_down_btn) + _horizontal_layout.addStretch(1) class MainWindow(QMainWindow): + remove_btn_signal = pyqtSignal() + add_btn_signal = pyqtSignal() + + item_selected = pyqtSignal(int) + CENTRAL_WIDGET_NAME = 'central_widget' ADD_BUTTON_NAME = 'add_btn' REMOVE_BUTTON_NAME = 'remove_btn' EDIT_BUTTON_NAME = 'edit_btn' + MOVE_UP_BUTTON_NAME = 'move_up_btn' + MOVE_DOWN_BUTTON_NAME = 'move_down_btn' num_of_objects = 0 items = [] @@ -51,38 +75,104 @@ def __init__(self, clipboard_manager: ClipboardManager): self._central_widget = QtWidgets.QWidget(self) self._clipboard_manager = clipboard_mgr - self._clipboard_manager.bind_clipboard_state_callback(self._render_clipboard_stack) + # self._clipboard_manager.bind_clipboard_state_callback(self._render_clipboard_stack) + self._clipboard_manager.clipboard_changed_signal.connect(self._render_clipboard_stack) + self.remove_btn_signal.connect(self._clipboard_manager.remove_clipboard_item) + + self.item_selected.connect(self._clipboard_manager.set_selected_object) + # self._main_list_widget.itemClicked.connect(self._set_selected_object) + self._init_ui() + @pyqtSlot(int) + def _set_current_row(self, idx): + # if no item is selected, idx will be -1 + if idx > -1: + self.item_selected.emit(self._clipboard_manager + .clipboard_stack.items_count() - max(0, idx) - 1) + + # @pyqtSlot(QListWidgetItem) + # def _set_selected_object(self, list_item: QListWidgetItem): + # self.item_selected.emit(self._main_list_widget.currentRow()) + def _init_ui(self): self.setWindowTitle(CONSTANTS['NAME']) + # self.setGeometry(self.left, self.top, self.width, self.height) self.setupUi() self.show() + @pyqtSlot(Stack) def _render_clipboard_stack(self, clipboard_stack: Stack): self._main_list_widget.clear() - for (idx, clipboard_object) in enumerate(clipboard_stack.items()): + # newest items should be at the top + for (idx, clipboard_object) in enumerate(reversed(clipboard_stack.items())): if isinstance(clipboard_object, TextClipboardObject): _item = QListWidgetItem(self._main_list_widget) - _custom_item = TextListWidgetItem(idx, clipboard_object) + _custom_item = TextListWidgetItem(clipboard_stack.items_count() + - idx - 1, clipboard_object) _item.setSizeHint(_custom_item.sizeHint()) self._main_list_widget.addItem(_item) self._main_list_widget.setItemWidget(_item, _custom_item) + self._main_list_widget.setCurrentRow(self._clipboard_manager.clipboard_stack.items_count() + - self._clipboard_manager.clipboard_stack + .current_item() - 1) + def setupUi(self): + # MainWindow.setObjectName("MainWindow") + # self.setFixedSize(640, 480) self._central_widget.setObjectName(MainWindow.CENTRAL_WIDGET_NAME) self._action_bar = ActionBar() + self._action_bar._remove_btn.clicked.connect(self.remove_btn_signal) + self._central_widget_layout.addWidget(self._action_bar) self._main_list_widget = MainListWidget() + self._main_list_widget.currentRowChanged.connect(self._set_current_row) + self._central_widget_layout.addWidget(self._main_list_widget) + # self._central_widget_layout.addStretch(1) + + # self.Add = QtWidgets.QPushButton(self._central_widget) + # self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) + # self.Add.clicked.connect(self.addObject) + # self.Add.setObjectName("Add") + + # self.Remove = QtWidgets.QPushButton(self._central_widget) + # self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) + # self.Remove.clicked.connect(self.removeObject) + # self.Remove.setObjectName("Remove") + # + # self.Edit = QtWidgets.QPushButton(self._central_widget) + # self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) + # self.Edit.setObjectName("Edit") + + # self.treeWidget = QtWidgets.QTreeWidget(self._central_widget) + # self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) + # self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) + # self.treeWidget.setObjectName("treeWidget") self.menubar = self.menuBar() + # self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) + # self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") - + # self.menuPlugins = QtWidgets.QMenu(self.menubar) + # self.menuPlugins.setObjectName("menuPlugins") + # self.menuItem = QtWidgets.QMenu(self.menubar) + # self.menuItem.setObjectName("menuItem") + # self.setMenuBar(self.menubar) + # self.statusbar = QtWidgets.QStatusBar(self) + # self.statusbar.setObjectName("statusbar") + # self.setStatusBar(self.statusbar) + # self.actionAdd = QtWidgets.QAction(self) + # self.actionAdd.setObjectName("actionAdd") + # self.actionDelete = QtWidgets.QAction(self) + # self.actionDelete.setObjectName("actionDelete") + # self.action_todo = QtWidgets.QAction(self) + # self.action_todo.setObjectName("action_todo") self.actionSettings = QtWidgets.QAction(self) self.actionSettings.setObjectName("actionSettings") # self.actionAdd_2 = QtWidgets.QAction(self) @@ -94,7 +184,8 @@ def setupUi(self): # self.menuItem.addAction(self.actionAdd_2) # self.menuItem.addAction(self.actionRemove) self.menubar.addAction(self.menuFile.menuAction()) - + # self.menubar.addAction(self.menuPlugins.menuAction()) + # self.menubar.addAction(self.menuItem.menuAction()) self._central_widget.setLayout(self._central_widget_layout) self.setCentralWidget(self._central_widget) @@ -125,6 +216,21 @@ def retranslateUi(self): # self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) # self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) + # def _add_object(self): + # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') + # self.num_of_objects + 1 + # def removeObject(self): + # # TODO make it remove instead of add + # + # if self.items == []: + # return + # + # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') + # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') + # + # self.num_of_objects + 1 + if __name__ == '__main__': app = QApplication(sys.argv) From a7cbbabce0fedd7ebe34fa2839e117b9edc44677 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Wed, 27 Feb 2019 17:38:26 +1100 Subject: [PATCH 29/60] Updates and the appy() func :p --- Pipfile.lock | 18 ++--- project/ClipboardManager/ClipboardManager.py | 7 +- project/Plugins/PredictiveText.py | 37 --------- project/Plugins/Text.py | 85 ++++++++++++++++++++ 4 files changed, 99 insertions(+), 48 deletions(-) delete mode 100644 project/Plugins/PredictiveText.py create mode 100644 project/Plugins/Text.py diff --git a/Pipfile.lock b/Pipfile.lock index 68d9999a..eeb2e93b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -25,11 +25,11 @@ }, "flake8": { "hashes": [ - "sha256:6d8c66a65635d46d54de59b027a1dda40abbe2275b3164b634835ac9c13fd048", - "sha256:6eab21c6e34df2c05416faa40d0c59963008fff29b6f0ccfe8fa28152ab3e383" + "sha256:859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661", + "sha256:a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8" ], "index": "pypi", - "version": "==3.7.6" + "version": "==3.7.7" }, "mccabe": { "hashes": [ @@ -148,11 +148,11 @@ }, "flake8": { "hashes": [ - "sha256:6d8c66a65635d46d54de59b027a1dda40abbe2275b3164b634835ac9c13fd048", - "sha256:6eab21c6e34df2c05416faa40d0c59963008fff29b6f0ccfe8fa28152ab3e383" + "sha256:859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661", + "sha256:a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8" ], "index": "pypi", - "version": "==3.7.6" + "version": "==3.7.7" }, "idna": { "hashes": [ @@ -232,10 +232,10 @@ }, "pluggy": { "hashes": [ - "sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616", - "sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a" + "sha256:19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f", + "sha256:84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746" ], - "version": "==0.8.1" + "version": "==0.9.0" }, "py": { "hashes": [ diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 283ef658..a1fbcbb7 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -3,17 +3,20 @@ from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack +from project.Plugins import Text class ClipboardManager: - def __init__(self): self._clipboard_state_callback = None QApplication.clipboard().dataChanged.connect(self._clipboard_changed) self._clipboard_stack = Stack() def _clipboard_changed(self): - current_text = QApplication.clipboard().text() + #testing by bwacpro + current_text = Text.apply(QApplication.clipboard().text()) + + #current_text = QApplication.clipboard().text() print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py deleted file mode 100644 index b9102dc2..00000000 --- a/project/Plugins/PredictiveText.py +++ /dev/null @@ -1,37 +0,0 @@ -from random import randint, choice -import string - - -def random_spelling_mistakes(text): - ''' - Usage: Will add random letters to words (only words above 2 letters) - then return the new sentence. - - Example: - - print(random_spelling_mistakes('Hello, yes hi')) - - Heqllo, yeVs hi - ''' - - # TODO: make it the same case as word changing, looks better - text = text.split() - new_words = '' - print(text) - for word in text: - if len(word) == 1 or len(word) == 2: - final = ''.join(word) - new_words = new_words + ' ' + final - else: - spot = randint(0, len(word) - 1) - if spot == 0: - '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get - removed''' - spot = randint(0, len(word) - 1) - if spot == 0: - pass - final = ''.join(word) - final = final[0:spot] + choice(string.ascii_letters) + final[spot:] - new_words = new_words + ' ' + final - return new_words - # TODO: there is a '.\PredictiveText.py:28:97: W291 trailing whitespace' and i cant resolve diff --git a/project/Plugins/Text.py b/project/Plugins/Text.py new file mode 100644 index 00000000..11f31a97 --- /dev/null +++ b/project/Plugins/Text.py @@ -0,0 +1,85 @@ +from random import randint, choice +import string + +quotes = [ + 'O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo', + '╠═══╣Lets build a ladder╠═══╣', + '( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)', + '┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?', + "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You're coming with us. (▀̿Ĺ̯▀̿ ̿)", + 'Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes', + 'Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7,\ + 8, 10', +] + +class Vars: + + times_appled = 0 + + +'''Use this function, not any other one. It as a 50/50 chance of applying each''' + + +def apply(text): + """First time coping, its normal, then it starts to go down hill....""" + Vars.times_appled = + 1 + if Vars.times_appled > 0 and Vars.times_appled < 2: + if randint(0, 5) == 5: + text = random_spelling_mistakes(text) + return text + else: + return text + elif Vars.times_appled > 2 and Vars.times_appled < 4: + if randint(0, 5) == 5: + text = random_spelling_mistakes(text) + return text + else: + text = quotify(text) + return text + elif Vars.times_appled > 4 and Vars.times_appled < 15: + if randint(0, 1) == 3: + text = random_spelling_mistakes(text) + return text + else: + text = quotify(text) + return text + + elif Vars.times_appled > 15: + text = quotify(text) + return text + else: + return text + + +def random_spelling_mistakes(text): + text = text.split() + new_words = '' + for word in text: + if len(word) == 1 or len(word) == 2: + final = ''.join(word) + new_words = new_words + ' ' + final + else: + spot = randint(0, len(word) - 1) + if spot == 0: + '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get + removed''' + spot = randint(0, len(word) - 1) + if spot == 0: + pass + final = ''.join(word) + final = final[0:spot] + choice(string.ascii_letters) + final[spot:] + new_words = new_words + ' ' + final + return new_words + + +def quotify(text): + try: + text = quotes[randint(0, len(quotes))] + except IndexError: + try: + text = quotes[randint(0, len(quotes))] + except IndexError: + print("Error: (IndexError) in PredictiveText.py. Try'ed to quotify but failed") + return text + finally: + return text From 4c1fedffb312db6977c61924bb5de71bebd61574 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Wed, 27 Feb 2019 18:17:12 +1100 Subject: [PATCH 30/60] Fixed my mistakes, also the apply() thing is here --- project/ClipboardManager/ClipboardManager.py | 3 +- project/Plugins/PredictiveText.py | 83 ++++++++++++++------ 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 1b58cea3..c990b0d5 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -4,6 +4,7 @@ from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack +from project.Plugins import PredictiveText as PT # import logging @@ -21,7 +22,7 @@ def __init__(self): @pyqtSlot() def _clipboard_changed(self): - current_text = QApplication.clipboard().text() + current_text = PT.apply(QApplication.clipboard().text()) print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index 2021aed8..709dce3f 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,23 +1,57 @@ from random import randint, choice import string -quotes = ['O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee ' + - 'AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo EEEEO-A-AAA-AAAA'] +quotes = [ + 'O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo', + '╠═══╣Lets build a ladder╠═══╣', + '( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)', + '┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?', + "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You're coming with us. (▀̿Ĺ̯▀̿ ̿)", + 'Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes', + 'Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7, \ + 8, 10', +] +class Vars: -def random_spelling_mistakes(text): - """ - Usage: Will add random letters to words (only words above 2 letters) - then return the new sentence. + times_appled = 0 + + +'''Use this function, not any other one. It as a 50/50 chance of applying each''' - Example: - print(random_spelling_mistakes('Hello, yes hi')) +def apply(text): + """First time coping, its normal, then it starts to go down hill....""" + Vars.times_appled = + 1 + if Vars.times_appled > 0 and Vars.times_appled < 2: + if randint(0, 5) == 5: + text = random_spelling_mistakes(text) + return text + else: + return text + elif Vars.times_appled > 2 and Vars.times_appled < 4: + if randint(0, 5) == 5: + text = random_spelling_mistakes(text) + return text + else: + text = quotify(text) + return text + elif Vars.times_appled > 4 and Vars.times_appled < 15: + if randint(0, 1) == 3: + text = random_spelling_mistakes(text) + return text + else: + text = quotify(text) + return text + + elif Vars.times_appled > 15: + text = quotify(text) + return text + else: + return text - Heqllo, yess hi - I is very fast. A string of 7712 characters only took 0.006994724273681641 seconds to process. - """ +def random_spelling_mistakes(text): text = text.split() new_words = '' for word in text: @@ -27,24 +61,25 @@ def random_spelling_mistakes(text): else: spot = randint(0, len(word) - 1) if spot == 0: - '''Give it two chances to not be 0, I think its better - if its mostly the middle letters that get removed''' + '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get + removed''' spot = randint(0, len(word) - 1) if spot == 0: pass final = ''.join(word) - if spot > 0: - final = final[0:spot] + choice(string.ascii_letters.lower()) + final[spot:] - elif spot == 0: - final = final[0:spot] + choice(string.ascii_letters.upper()) + final[spot:] + final = final[0:spot] + choice(string.ascii_letters) + final[spot:] new_words = new_words + ' ' + final return new_words -def twitch_quote(text): - b = randint(0, 27) - text = quotes[b] - return text - - -# print(twitch_quote('Hello')) +def quotify(text): + try: + text = quotes[randint(0, len(quotes))] + except IndexError: + try: + text = quotes[randint(0, len(quotes))] + except IndexError: + print("Error: (IndexError) in PredictiveText.py. Try'ed to quotify but failed") + return text + finally: + return text From 16c49dec1523f867b925c8d642a364e572d1e72f Mon Sep 17 00:00:00 2001 From: kaleidagraph <26967284+kaleidagraph@users.noreply.github.com> Date: Wed, 27 Feb 2019 10:58:44 +0000 Subject: [PATCH 31/60] Built working system tray icon, no functionality yet --- .gitignore | 3 --- project/Plugins/Systray.py | 17 +++++++++++++++++ project/SystrayManager/Systray.py | 28 ---------------------------- project/__main__.py | 10 +++++----- project/tempicon.ico | Bin 0 -> 27758 bytes 5 files changed, 22 insertions(+), 36 deletions(-) create mode 100644 project/Plugins/Systray.py delete mode 100644 project/SystrayManager/Systray.py create mode 100644 project/tempicon.ico diff --git a/.gitignore b/.gitignore index 47482d5d..2f8f9d81 100644 --- a/.gitignore +++ b/.gitignore @@ -109,6 +109,3 @@ venv.bak/ # compiled sphinx HTML documentation docs/build .vscode/settings.json - -# test icon -project/tempicon.ico diff --git a/project/Plugins/Systray.py b/project/Plugins/Systray.py new file mode 100644 index 00000000..928b537f --- /dev/null +++ b/project/Plugins/Systray.py @@ -0,0 +1,17 @@ +import sys +from PyQt5 import QtWidgets, QtGui + + +class SystemTrayIcon(QtWidgets.QSystemTrayIcon): + """ Class which contains logic for a system tray interactive icon""" + + # temp icon & name + icon = "project\\tempicon.ico" + name = "Example tray icon" + + def __init__(self, parent=None): + QtWidgets.QSystemTrayIcon.__init__(self, QtGui.QIcon(self.icon), parent) + menu = QtWidgets.QMenu(parent) + exitAction = menu.addAction("Temp Option One") + self.setContextMenu(menu) + self.setToolTip(self.name) diff --git a/project/SystrayManager/Systray.py b/project/SystrayManager/Systray.py deleted file mode 100644 index 403eb972..00000000 --- a/project/SystrayManager/Systray.py +++ /dev/null @@ -1,28 +0,0 @@ -from infi.systray import SysTrayIcon - - -class systray: - """ Class which contains logic for a system tray interactive icon""" - - # temp icon & name - icon = "project\\tempicon.ico" - name = "Example tray icon" - - def __init__(self, closecallback): - # in future will have an function as a argument to work with rest of app - - # temp options for right click - menu_options = (("Say Hello", None, self.say_hello),) - self.systray = SysTrayIcon(self.icon, self.name, menu_options, on_quit=closecallback) - - def say_hello(self, systray): - print("Hello, World!") - - def start(self): - """ Starts systray icon""" - self.systray.start() - - def close(self): - """ Closes systray icon""" - self.systray.shutdown() - # this function also runs the callback:( diff --git a/project/__main__.py b/project/__main__.py index 2b89b237..edbab853 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -8,7 +8,7 @@ from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack from project.Widgets import MainListWidget, TextListWidgetItem -# from project.SystrayManager import Systray # noqa: F401 +from project.Plugins.Systray import SystemTrayIcon from .utils import CONSTANTS from PyQt5 import QtCore, QtWidgets @@ -252,9 +252,9 @@ def closeEvent(self, event): clipboard_mgr = ClipboardManager.ClipboardManager() main_window = MainWindow(clipboard_mgr) - # Creates and starts systray icon - # systray = Systray.systray(app.quit) - # systray.start() - # app.aboutToQuit.connect(systray.close) + #Creates and starts systray icon + w = QtWidgets.QDesktopWidget() + systray = SystemTrayIcon(w) + systray.show() sys.exit(app.exec_()) diff --git a/project/tempicon.ico b/project/tempicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7f4327b998e18e80e57b0017d32c10580c5e1ac8 GIT binary patch literal 27758 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 F`+t~XQda-~ literal 0 HcmV?d00001 From a12e0ed86a6f38de15bbf35aed7dadedb8cca831 Mon Sep 17 00:00:00 2001 From: kaleidagraph <26967284+kaleidagraph@users.noreply.github.com> Date: Wed, 27 Feb 2019 11:09:51 +0000 Subject: [PATCH 32/60] Moved quotes into app.json and implemented retrieval of them --- project/Plugins/PredictiveText.py | 13 +++---------- project/Plugins/Save.py | 9 +++++++++ project/app.json | 11 +++++++++++ project/utils.py | 1 + 4 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 project/Plugins/Save.py create mode 100644 project/app.json diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index 709dce3f..e748aa4a 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,16 +1,9 @@ from random import randint, choice import string +from project.Plugins.Save import getQuotes -quotes = [ - 'O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo', - '╠═══╣Lets build a ladder╠═══╣', - '( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)', - '┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?', - "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You're coming with us. (▀̿Ĺ̯▀̿ ̿)", - 'Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes', - 'Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7, \ - 8, 10', -] +# Quotes are now loadeded from 'app.json' instead of being hard coded +quotes = getQuotes() class Vars: diff --git a/project/Plugins/Save.py b/project/Plugins/Save.py new file mode 100644 index 00000000..e6cde27f --- /dev/null +++ b/project/Plugins/Save.py @@ -0,0 +1,9 @@ +""" Contains logic for loading and saving states """ +import json +from project.utils import CONSTANTS + +def getQuotes(): + # due to some more complex characters in 'app.json' the encoding must be set utf-8 + with open(CONSTANTS['APP_SETTINGS'], encoding='utf-8') as f: + data = json.load(f) + return data['quotes'] \ No newline at end of file diff --git a/project/app.json b/project/app.json new file mode 100644 index 00000000..15156266 --- /dev/null +++ b/project/app.json @@ -0,0 +1,11 @@ +{ + "quotes": [ + "O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo", + "╠═══╣Lets build a ladder╠═══╣", + "( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)", + "┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?", + "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You\"re coming with us. (▀̿Ĺ̯▀̿ ̿)", + "Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes", + "Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7, 8, 10" + ] +} \ No newline at end of file diff --git a/project/utils.py b/project/utils.py index bf9d8a93..a6b540a1 100644 --- a/project/utils.py +++ b/project/utils.py @@ -15,4 +15,5 @@ def add(x, y): 'NAME': 'Clipboard Mangler', 'NUMOFOBJECTS': 0, 'HISTORY_MAX_ITEMS': 10, + 'APP_SETTINGS': 'project/app.json' } From 7a2fcf7ba3a3da3f6595eac864af40ad08c710f8 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Thu, 28 Feb 2019 02:45:51 +0800 Subject: [PATCH 33/60] Fix linting and fix moving items up and down --- Pipfile | 1 - Pipfile.lock | 9 +----- project/ClipboardManager/ClipboardManager.py | 31 ++++++++++++++++++-- project/Plugins/PredictiveText.py | 6 ++-- project/Plugins/Save.py | 3 +- project/Plugins/Systray.py | 4 +-- project/Stack/Stack.py | 26 ++++++++++------ project/__main__.py | 13 ++++++-- 8 files changed, 64 insertions(+), 29 deletions(-) diff --git a/Pipfile b/Pipfile index 7caf386f..9c0abe9f 100644 --- a/Pipfile +++ b/Pipfile @@ -11,7 +11,6 @@ sphinx = "*" [packages] pyqt5 = "*" flake8 = "*" -infi-systray = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index d539aac4..d047b160 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d45de85edd80d37d1d3abe3bf2ad9f251f2e0e4fe73d7b9641e3013095e3e0e1" + "sha256": "17ce94e1fc71663d21aa757654ae465c3575be6c1b6275bb1f808794655b7e96" }, "pipfile-spec": 6, "requires": { @@ -31,13 +31,6 @@ "index": "pypi", "version": "==3.7.7" }, - "infi-systray": { - "hashes": [ - "sha256:baea99548d882d4a7a6d3db4942f9bf93b88e30ddb9abe96d0dded44f564cf50" - ], - "index": "pypi", - "version": "==0.1.11" - }, "mccabe": { "hashes": [ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index c990b0d5..4cc03edc 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -4,7 +4,9 @@ from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.Stack import Stack -from project.Plugins import PredictiveText as PT + + +# from project.Plugins import PredictiveText as PT # import logging @@ -13,16 +15,27 @@ # pyqt5-connection-doesnt-work-item-cannot-be-converted-to-pyqt5-qtcore-qobject class ClipboardManager(QObject): clipboard_changed_signal = pyqtSignal(Stack) + stack_changed_signal = pyqtSignal(Stack) def __init__(self): super().__init__() self._clipboard_state_callback = None QApplication.clipboard().dataChanged.connect(self._clipboard_changed) self.clipboard_stack = Stack() + self.stack_changed_signal.connect(self._stack_changed) + + @pyqtSlot(Stack) + def _stack_changed(self): + # copy the top of the stack into the clipboard if the stack is not empty. + if self.clipboard_stack.items_count() and \ + isinstance(self.clipboard_stack.peek(), TextClipboardObject): + QApplication.clipboard().setText(self.clipboard_stack.peek().text) @pyqtSlot() def _clipboard_changed(self): - current_text = PT.apply(QApplication.clipboard().text()) + """""" + current_text = QApplication.clipboard().text() + # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) @@ -46,11 +59,22 @@ def set_selected_object(self, idx): """Highlights a particular row in the main window""" self.clipboard_stack.set_current_item(idx) + @pyqtSlot() def remove_clipboard_item(self): """Public function to remove a clipboard item""" self._remove_clipboard_item(self.clipboard_stack.current_item()) self.clipboard_changed_signal.emit(self.clipboard_stack) + def move_selected_item_up(self): + """Moves the current item in the stack up by one""" + self.clipboard_stack.shift_current_item(Stack.SHIFT_DIRECTION.UP) + self.stack_changed_signal.emit(self.clipboard_stack) + + def move_selected_item_down(self): + """Moves the current item in the stack down by one""" + self.clipboard_stack.shift_current_item(Stack.SHIFT_DIRECTION.DOWN) + self.stack_changed_signal.emit(self.clipboard_stack) + def _remove_clipboard_item(self, idx): """Helper function to remove a item from the stack""" if not self.clipboard_stack.items_count(): @@ -60,4 +84,5 @@ def _remove_clipboard_item(self, idx): raise Exception("Index is out of bounds") self.clipboard_stack.pop(idx) - self.clipboard_changed_signal.emit(self.clipboard_stack) + self.stack_changed_signal.emit(self.clipboard_stack) + # self.clipboard_changed_signal.emit(self.clipboard_stack) diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index e748aa4a..d96740da 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -5,8 +5,8 @@ # Quotes are now loadeded from 'app.json' instead of being hard coded quotes = getQuotes() -class Vars: +class Vars: times_appled = 0 @@ -54,8 +54,8 @@ def random_spelling_mistakes(text): else: spot = randint(0, len(word) - 1) if spot == 0: - '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get - removed''' + '''Give it two chances to not be 0, I think its better + if its mostly the middle letters that get removed''' spot = randint(0, len(word) - 1) if spot == 0: pass diff --git a/project/Plugins/Save.py b/project/Plugins/Save.py index e6cde27f..3bb233d8 100644 --- a/project/Plugins/Save.py +++ b/project/Plugins/Save.py @@ -2,8 +2,9 @@ import json from project.utils import CONSTANTS + def getQuotes(): # due to some more complex characters in 'app.json' the encoding must be set utf-8 with open(CONSTANTS['APP_SETTINGS'], encoding='utf-8') as f: data = json.load(f) - return data['quotes'] \ No newline at end of file + return data['quotes'] diff --git a/project/Plugins/Systray.py b/project/Plugins/Systray.py index 928b537f..b3a1a0a7 100644 --- a/project/Plugins/Systray.py +++ b/project/Plugins/Systray.py @@ -1,4 +1,4 @@ -import sys +import sys # noqa: F401 from PyQt5 import QtWidgets, QtGui @@ -12,6 +12,6 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon): def __init__(self, parent=None): QtWidgets.QSystemTrayIcon.__init__(self, QtGui.QIcon(self.icon), parent) menu = QtWidgets.QMenu(parent) - exitAction = menu.addAction("Temp Option One") + exitAction = menu.addAction("Temp Option One") # noqa: F841 self.setContextMenu(menu) self.setToolTip(self.name) diff --git a/project/Stack/Stack.py b/project/Stack/Stack.py index 4464e907..9fc11dcc 100644 --- a/project/Stack/Stack.py +++ b/project/Stack/Stack.py @@ -14,8 +14,8 @@ class Stack: # methods for this (e.g. "__len__", "__iter__",...) class SHIFT_DIRECTION(enum.Enum): - UP: 1 - DOWN: 2 + UP = 1 + DOWN = 2 def __init__(self, existing_stack=[], cur_stack_pointer=None): # Stack is backwards??? @@ -24,7 +24,7 @@ def __init__(self, existing_stack=[], cur_stack_pointer=None): if cur_stack_pointer: self._stack_pointer = cur_stack_pointer else: - # By default the stack pointer is at the top of the stack + # By default the stack pointer is at the top of the stack (-1 ??) self._stack_pointer = len(self._stack) - 1 # this should be __iter__ @@ -45,16 +45,24 @@ def set_current_item(self, idx): def current_item(self): return self._stack_pointer - def shift_current_item(self, idx, shift_direction: SHIFT_DIRECTION): - # again what does idx relate to + def shift_current_item(self, shift_direction: SHIFT_DIRECTION): + """Shifts the current item pointed to by the stack pointer up or down""" + + if self._stack_pointer <= 0 and shift_direction == Stack.SHIFT_DIRECTION.DOWN or \ + self._stack_pointer == self.items_count() - 1 \ + and shift_direction == Stack.SHIFT_DIRECTION.UP: + return + _temp = self._stack[self._stack_pointer] if shift_direction == Stack.SHIFT_DIRECTION.UP: - self._stack[idx] = self._stack[idx + 1] - self._stack[idx + 1] = _temp + self._stack[self._stack_pointer] = self._stack[self._stack_pointer + 1] + self._stack[self._stack_pointer + 1] = _temp + self._stack_pointer += 1 elif shift_direction == Stack.SHIFT_DIRECTION.DOWN: - self._stack[idx] = self._stack[idx - 1] - self._stack[idx - 1] = _temp + self._stack[self._stack_pointer] = self._stack[self._stack_pointer - 1] + self._stack[self._stack_pointer - 1] = _temp + self._stack_pointer -= 1 def swap_items(self, idx, target_idx): _temp = self._stack[idx] diff --git a/project/__main__.py b/project/__main__.py index edbab853..2f223459 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -50,8 +50,11 @@ def __init__(self): class MainWindow(QMainWindow): - remove_btn_signal = pyqtSignal() add_btn_signal = pyqtSignal() + remove_btn_signal = pyqtSignal() + + move_up_btn_signal = pyqtSignal() + move_down_btn_signal = pyqtSignal() item_selected = pyqtSignal(int) @@ -78,7 +81,11 @@ def __init__(self, clipboard_manager: ClipboardManager): # self._clipboard_manager.bind_clipboard_state_callback(self._render_clipboard_stack) self._clipboard_manager.clipboard_changed_signal.connect(self._render_clipboard_stack) + self._clipboard_manager.stack_changed_signal.connect(self._render_clipboard_stack) + self.remove_btn_signal.connect(self._clipboard_manager.remove_clipboard_item) + self.move_up_btn_signal.connect(self._clipboard_manager.move_selected_item_up) + self.move_down_btn_signal.connect(self._clipboard_manager.move_selected_item_down) self.item_selected.connect(self._clipboard_manager.set_selected_object) # self._main_list_widget.itemClicked.connect(self._set_selected_object) @@ -130,6 +137,8 @@ def setupUi(self): self._action_bar = ActionBar() self._action_bar._remove_btn.clicked.connect(self.remove_btn_signal) + self._action_bar._move_up_btn.clicked.connect(self.move_up_btn_signal) + self._action_bar._move_down_btn.clicked.connect(self.move_down_btn_signal) self._central_widget_layout.addWidget(self._action_bar) @@ -252,7 +261,7 @@ def closeEvent(self, event): clipboard_mgr = ClipboardManager.ClipboardManager() main_window = MainWindow(clipboard_mgr) - #Creates and starts systray icon + # Creates and starts systray icon w = QtWidgets.QDesktopWidget() systray = SystemTrayIcon(w) systray.show() From f0e0d453deba2ba62b6b3cd6ff261df1e821ff84 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Thu, 28 Feb 2019 06:47:31 +1100 Subject: [PATCH 34/60] small update --- Pipfile | 1 + project/Plugins/PredictiveText.py | 27 +++++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Pipfile b/Pipfile index 7caf386f..061312e8 100644 --- a/Pipfile +++ b/Pipfile @@ -12,6 +12,7 @@ sphinx = "*" pyqt5 = "*" flake8 = "*" infi-systray = "*" +json = "*" [requires] python_version = "3.7" diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/PredictiveText.py index 709dce3f..ae146970 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/PredictiveText.py @@ -1,19 +1,22 @@ from random import randint, choice import string +import json -quotes = [ - 'O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo', - '╠═══╣Lets build a ladder╠═══╣', - '( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)', - '┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?', - "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You're coming with us. (▀̿Ĺ̯▀̿ ̿)", - 'Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes', - 'Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7, \ - 8, 10', -] +# quotes = [ +# 'O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo', +# '╠═══╣Lets build a ladder╠═══╣', +# '( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)', +# '┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?', +# "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You're coming with us. (▀̿Ĺ̯▀̿ ̿)", +# 'Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes', +# 'Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7, \ +# 8, 10', +# ] + +def __init__(): -class Vars: +class Vars: times_appled = 0 @@ -61,7 +64,7 @@ def random_spelling_mistakes(text): else: spot = randint(0, len(word) - 1) if spot == 0: - '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get + '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get removed''' spot = randint(0, len(word) - 1) if spot == 0: From 72395c91749a88a10eaf1b24ee00962d1a1dfaa6 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Thu, 28 Feb 2019 17:29:01 +1100 Subject: [PATCH 35/60] bigish update, just some file rearranging --- Pipfile | 7 +- Pipfile.lock | 79 ++++++++++++++++++- project/ClipboardManager/ClipboardManager.py | 2 +- .../{PredictiveText.py => Text/Text.py} | 38 ++------- project/Plugins/Text/parse.py | 11 +++ 5 files changed, 98 insertions(+), 39 deletions(-) rename project/Plugins/{PredictiveText.py => Text/Text.py} (56%) create mode 100644 project/Plugins/Text/parse.py diff --git a/Pipfile b/Pipfile index 64fa89e4..a6334b41 100644 --- a/Pipfile +++ b/Pipfile @@ -11,11 +11,8 @@ sphinx = "*" [packages] pyqt5 = "*" flake8 = "*" -<<<<<<< HEAD -infi-systray = "*" -json = "*" -======= ->>>>>>> 7a2fcf7ba3a3da3f6595eac864af40ad08c710f8 +lxml = "*" +requests = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index d047b160..0fa46bd3 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "17ce94e1fc71663d21aa757654ae465c3575be6c1b6275bb1f808794655b7e96" + "sha256": "1c9c582593da9e7fcef78281f91524482d8b7fe9e389e0265c27ed9e390c84da" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,20 @@ ] }, "default": { + "certifi": { + "hashes": [ + "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", + "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" + ], + "version": "==2018.11.29" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, "entrypoints": { "hashes": [ "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", @@ -31,6 +45,45 @@ "index": "pypi", "version": "==3.7.7" }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "lxml": { + "hashes": [ + "sha256:0537eee4902e8bf4f41bfee8133f7edf96533dd175930a12086d6a40d62376b2", + "sha256:0562ec748abd230ab87d73384e08fa784f9b9cee89e28696087d2d22c052cc27", + "sha256:09e91831e749fbf0f24608694e4573be0ef51430229450c39c83176cc2e2d353", + "sha256:1ae4c0722fc70c0d4fba43ae33c2885f705e96dce1db41f75ae14a2d2749b428", + "sha256:1c630c083d782cbaf1f7f37f6cac87bda9cff643cf2803a5f180f30d97955cef", + "sha256:2fe74e3836bd8c0fa7467ffae05545233c7f37de1eb765cacfda15ad20c6574a", + "sha256:37af783c2667ead34a811037bda56a0b142ac8438f7ed29ae93f82ddb812fbd6", + "sha256:3f2d9eafbb0b24a33f56acd16f39fc935756524dcb3172892721c54713964c70", + "sha256:47d8365a8ef14097aa4c65730689be51851b4ade677285a3b2daa03b37893e26", + "sha256:510e904079bc56ea784677348e151e1156040dbfb736f1d8ea4b9e6d0ab2d9f4", + "sha256:58d0851da422bba31c7f652a7e9335313cf94a641aa6d73b8f3c67602f75b593", + "sha256:7940d5c2185ffb989203dacbb28e6ae88b4f1bb25d04e17f94b0edd82232bcbd", + "sha256:7cf39bb3a905579836f7a8f3a45320d9eb22f16ab0c1e112efb940ced4d057a5", + "sha256:9563a23c1456c0ab550c087833bc13fcc61013a66c6420921d5b70550ea312bf", + "sha256:95b392952935947e0786a90b75cc33388549dcb19af716b525dae65b186138fc", + "sha256:983129f3fd3cef5c3cf067adcca56e30a169656c00fcc6c648629dbb850b27fa", + "sha256:a0b75b1f1854771844c647c464533def3e0a899dd094a85d1d4ed72ecaaee93d", + "sha256:b5db89cc0ef624f3a81214b7961a99f443b8c91e88188376b6b322fd10d5b118", + "sha256:c0a7751ba1a4bfbe7831920d98cee3ce748007eab8dfda74593d44079568219a", + "sha256:c0c5a7d4aafcc30c9b6d8613a362567e32e5f5b708dc41bc3a81dac56f8af8bb", + "sha256:d4d63d85eacc6cb37b459b16061e1f100d154bee89dc8d8f9a6128a5a538e92e", + "sha256:da5e7e941d6e71c9c9a717c93725cda0708c2474f532e3680ac5e39ec57d224d", + "sha256:dccad2b3c583f036f43f80ac99ee212c2fa9a45151358d55f13004d095e683b2", + "sha256:df46307d39f2aeaafa1d25309b8a8d11738b73e9861f72d4d0a092528f498baa", + "sha256:e70b5e1cb48828ddd2818f99b1662cb9226dc6f57d07fc75485405c77da17436", + "sha256:ea825562b8cd057cbc9810d496b8b5dec37a1e2fc7b27bc7c1e72ce94462a09a" + ], + "index": "pypi", + "version": "==4.3.1" + }, "mccabe": { "hashes": [ "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", @@ -78,6 +131,21 @@ "sha256:bb81cfc4d35ca59f1c419b6abeb6ca6a726a63b712cf979f2b5ab24b81c36f49" ], "version": "==4.19.14" + }, + "requests": { + "hashes": [ + "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", + "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" + ], + "index": "pypi", + "version": "==2.21.0" + }, + "urllib3": { + "hashes": [ + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + ], + "version": "==1.24.1" } }, "develop": { @@ -123,6 +191,14 @@ ], "version": "==3.0.4" }, + "colorama": { + "hashes": [ + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.1" + }, "docutils": { "hashes": [ "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", @@ -284,6 +360,7 @@ "sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b" ], + "index": "pypi", "version": "==2.21.0" }, "six": { diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 4cc03edc..88e9bf42 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -6,7 +6,7 @@ from project.Stack import Stack -# from project.Plugins import PredictiveText as PT +from project.Plugins.Text import Text # import logging diff --git a/project/Plugins/PredictiveText.py b/project/Plugins/Text/Text.py similarity index 56% rename from project/Plugins/PredictiveText.py rename to project/Plugins/Text/Text.py index fc759af9..092fdfb4 100644 --- a/project/Plugins/PredictiveText.py +++ b/project/Plugins/Text/Text.py @@ -1,26 +1,12 @@ from random import randint, choice import string -<<<<<<< HEAD import json -# quotes = [ -# 'O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo', -# '╠═══╣Lets build a ladder╠═══╣', -# '( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)', -# '┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?', -# "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You're coming with us. (▀̿Ĺ̯▀̿ ̿)", -# 'Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes', -# 'Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7, \ -# 8, 10', -# ] - def __init__(): -======= -from project.Plugins.Save import getQuotes + from project.Plugins.Save import getQuotes -# Quotes are now loadeded from 'app.json' instead of being hard coded -quotes = getQuotes() ->>>>>>> 7a2fcf7ba3a3da3f6595eac864af40ad08c710f8 + # Quotes are now loadeded from 'app.json' instead of being hard coded + quotes = getQuotes() class Vars: @@ -71,13 +57,8 @@ def random_spelling_mistakes(text): else: spot = randint(0, len(word) - 1) if spot == 0: -<<<<<<< HEAD - '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get - removed''' -======= '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get removed''' ->>>>>>> 7a2fcf7ba3a3da3f6595eac864af40ad08c710f8 spot = randint(0, len(word) - 1) if spot == 0: pass @@ -88,13 +69,6 @@ def random_spelling_mistakes(text): def quotify(text): - try: - text = quotes[randint(0, len(quotes))] - except IndexError: - try: - text = quotes[randint(0, len(quotes))] - except IndexError: - print("Error: (IndexError) in PredictiveText.py. Try'ed to quotify but failed") - return text - finally: - return text + from project.Plugins.Text import Parse + quote = Parse.parse() + return quote diff --git a/project/Plugins/Text/parse.py b/project/Plugins/Text/parse.py new file mode 100644 index 00000000..41e9c2fd --- /dev/null +++ b/project/Plugins/Text/parse.py @@ -0,0 +1,11 @@ +from lxml import html +import requests + +def parse(): + try: + page = requests.get('https://funnysentences.com/sentence-generator/') + tree = html.fromstring(page.content) + quote = tree.xpath('//*[@id="sentencegen"]/text()') + return ''.join(quote) + except requests.exceptions.ConnectionError: + return "lol you don't have internet" From d8f7e4976454c53e0f4144707243e1342efbd736 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Fri, 1 Mar 2019 01:01:11 +0800 Subject: [PATCH 36/60] Add image support --- project/ClipboardManager/ClipboardManager.py | 33 ++++++++++++++---- project/ClipboardManager/ClipboardObject.py | 27 +++++++++++++++ project/Stack/Stack.py | 7 +++- project/Widgets/MainListWidget.py | 35 +++++++++++++++++++- project/__main__.py | 13 ++++++-- 5 files changed, 104 insertions(+), 11 deletions(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 4cc03edc..dc7a7b1a 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -2,7 +2,7 @@ from PyQt5.Qt import QApplication, QClipboard # noqa: F401 from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot -from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject from project.Stack import Stack @@ -20,6 +20,9 @@ class ClipboardManager(QObject): def __init__(self): super().__init__() self._clipboard_state_callback = None + self._last_text = None + self._last_image = None + QApplication.clipboard().dataChanged.connect(self._clipboard_changed) self.clipboard_stack = Stack() self.stack_changed_signal.connect(self._stack_changed) @@ -27,23 +30,39 @@ def __init__(self): @pyqtSlot(Stack) def _stack_changed(self): # copy the top of the stack into the clipboard if the stack is not empty. - if self.clipboard_stack.items_count() and \ - isinstance(self.clipboard_stack.peek(), TextClipboardObject): - QApplication.clipboard().setText(self.clipboard_stack.peek().text) + if self.clipboard_stack.items_count(): + if isinstance(self.clipboard_stack.peek(), TextClipboardObject): + QApplication.clipboard().setText(self.clipboard_stack.peek().text) + if isinstance(self.clipboard_stack.peek(), ImageClipboardObject): + QApplication.clipboard().setPixmap(self.clipboard_stack.peek().pixmap) @pyqtSlot() def _clipboard_changed(self): """""" current_text = QApplication.clipboard().text() + current_image = QApplication.clipboard().pixmap() + + top_item = self.clipboard_stack.peek() + # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) - if current_text and not (isinstance(self.clipboard_stack.peek(), TextClipboardObject) - and self.clipboard_stack.peek().text == current_text): + if current_text and (self._last_text is None or current_text != self._last_text) and \ + not (isinstance(top_item, TextClipboardObject) and top_item.text == current_text): self.clipboard_stack.push_item(TextClipboardObject(current_text)) self.clipboard_changed_signal.emit(self.clipboard_stack) + if not current_image.toImage().isNull() \ + and (self._last_image is None + or current_image.toImage() != self._last_image.toImage()) \ + and not (isinstance(top_item, ImageClipboardObject) + and top_item.pixmap.toImage() == current_image.toImage()): + self.clipboard_stack.push_item(ImageClipboardObject(current_image)) + self.clipboard_changed_signal.emit(self.clipboard_stack) + + self._last_image = current_image + self._last_text = current_text # if self._clipboard_state_callback is not None: # self._clipboard_state_callback(self._clipboard_stack) @@ -62,7 +81,7 @@ def set_selected_object(self, idx): @pyqtSlot() def remove_clipboard_item(self): """Public function to remove a clipboard item""" - self._remove_clipboard_item(self.clipboard_stack.current_item()) + self._remove_clipboard_item(self.clipboard_stack.current_item_idx) self.clipboard_changed_signal.emit(self.clipboard_stack) def move_selected_item_up(self): diff --git a/project/ClipboardManager/ClipboardObject.py b/project/ClipboardManager/ClipboardObject.py index 86cc1ac4..a1c88e7a 100644 --- a/project/ClipboardManager/ClipboardObject.py +++ b/project/ClipboardManager/ClipboardObject.py @@ -1,6 +1,8 @@ from abc import ABCMeta import datetime +from PyQt5.QtGui import QPixmap + class ClipboardObject(metaclass=ABCMeta): @@ -14,9 +16,34 @@ def date(self): class TextClipboardObject(ClipboardObject): + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.text == other.text + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + def __init__(self, text): super().__init__() self.text = text def set_text(self, text: str): self.text = text + + +class ImageClipboardObject(ClipboardObject): + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.pixmap.toImage() == other.pixmap.toImage() + else: + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def __init__(self, pixmap: QPixmap): + super().__init__() + self.pixmap = pixmap diff --git a/project/Stack/Stack.py b/project/Stack/Stack.py index 9fc11dcc..c00cdee8 100644 --- a/project/Stack/Stack.py +++ b/project/Stack/Stack.py @@ -42,9 +42,14 @@ def set_current_item(self, idx): self._stack_pointer = idx - def current_item(self): + @property + def current_item_idx(self): return self._stack_pointer + @property + def current_item(self): + return self._stack[self._stack_pointer] if self._stack else None + def shift_current_item(self, shift_direction: SHIFT_DIRECTION): """Shifts the current item pointed to by the stack pointer up or down""" diff --git a/project/Widgets/MainListWidget.py b/project/Widgets/MainListWidget.py index 6c96097f..bf9a2421 100644 --- a/project/Widgets/MainListWidget.py +++ b/project/Widgets/MainListWidget.py @@ -7,7 +7,7 @@ """ from PyQt5.QtWidgets import QListWidget, QWidget, QHBoxLayout, QLabel, QVBoxLayout, QSizePolicy -from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject class MainListWidget(QListWidget): @@ -51,3 +51,36 @@ def __init__(self, index: int, obj: TextClipboardObject, parent=None): self._main_hbox_layout.addWidget(self._right_section) self.setLayout(self._main_hbox_layout) + + +class ImageListWidgetItem(QWidget): + def __init__(self, index: int, obj: ImageClipboardObject, parent=None): + super().__init__(parent) + + self._main_hbox_layout = QHBoxLayout() + + self._right_section = QWidget() + self._right_vbox_layout = QVBoxLayout() + + # https://stackoverflow.com/questions/2286864/how-can-i-add-a-picture-to-a-qwidget-in-pyqt4 + # works with pixmaps too + self._image_area = QLabel() + self._image_area.setPixmap(obj.pixmap) + + self._date_label = QLabel() + self._date_label.setText(obj.date().strftime("%Y-%m-%d %H:%M:%S")) + + # Date should be at the bottom. + self._right_vbox_layout.addWidget(self._image_area) + self._right_vbox_layout.addWidget(self._date_label) + + self._right_section.setLayout(self._right_vbox_layout) + self._right_section.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + + self._index_label = QLabel() + self._index_label.setText(str(index)) + + self._main_hbox_layout.addWidget(self._index_label) + self._main_hbox_layout.addWidget(self._right_section) + + self.setLayout(self._main_hbox_layout) diff --git a/project/__main__.py b/project/__main__.py index 2f223459..8a90cbb0 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -5,10 +5,11 @@ import sys from project import ClipboardManager -from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject from project.Stack import Stack from project.Widgets import MainListWidget, TextListWidgetItem from project.Plugins.Systray import SystemTrayIcon +from project.Widgets.MainListWidget import ImageListWidgetItem from .utils import CONSTANTS from PyQt5 import QtCore, QtWidgets @@ -123,9 +124,17 @@ def _render_clipboard_stack(self, clipboard_stack: Stack): self._main_list_widget.addItem(_item) self._main_list_widget.setItemWidget(_item, _custom_item) + elif isinstance(clipboard_object, ImageClipboardObject): + _item = QListWidgetItem(self._main_list_widget) + _custom_item = ImageListWidgetItem(clipboard_stack.items_count() - idx - 1, + clipboard_object) + _item.setSizeHint(_custom_item.sizeHint()) + self._main_list_widget.addItem(_item) + self._main_list_widget.setItemWidget(_item, _custom_item) + self._main_list_widget.setCurrentRow(self._clipboard_manager.clipboard_stack.items_count() - self._clipboard_manager.clipboard_stack - .current_item() - 1) + .current_item_idx - 1) def setupUi(self): # MainWindow.setObjectName("MainWindow") From 9a5ec8cb77ebed4a8ae42f7590e0ab1e3fd4df14 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Fri, 1 Mar 2019 07:11:55 +1100 Subject: [PATCH 37/60] New text method --- Pipfile | 1 + Pipfile.lock | 25 +++++++- project/ClipboardManager/ClipboardManager.py | 2 +- project/Plugins/Text/Text.py | 66 ++++++++------------ project/Plugins/Text/parse.py | 1 + 5 files changed, 53 insertions(+), 42 deletions(-) diff --git a/Pipfile b/Pipfile index a6334b41..6e400524 100644 --- a/Pipfile +++ b/Pipfile @@ -13,6 +13,7 @@ pyqt5 = "*" flake8 = "*" lxml = "*" requests = "*" +thesaurus = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 0fa46bd3..183a954c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1c9c582593da9e7fcef78281f91524482d8b7fe9e389e0265c27ed9e390c84da" + "sha256": "8a1138130ef769617102c5d0548e339fcd02b844bee110972030c816003e0938" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,14 @@ ] }, "default": { + "beautifulsoup4": { + "hashes": [ + "sha256:034740f6cb549b4e932ae1ab975581e6103ac8f942200a0e9759065984391858", + "sha256:945065979fb8529dd2f37dbb58f00b661bdbcbebf954f93b32fdf5263ef35348", + "sha256:ba6d5c59906a85ac23dadfe5c88deaf3e179ef565f4898671253e50a78680718" + ], + "version": "==4.7.1" + }, "certifi": { "hashes": [ "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", @@ -140,6 +148,21 @@ "index": "pypi", "version": "==2.21.0" }, + "soupsieve": { + "hashes": [ + "sha256:afa56bf14907bb09403e5d15fbed6275caa4174d36b975226e3b67a3bb6e2c4b", + "sha256:eaed742b48b1f3e2d45ba6f79401b2ed5dc33b2123dfe216adb90d4bfa0ade26" + ], + "version": "==1.8" + }, + "thesaurus": { + "hashes": [ + "sha256:baba81d355f5e0ef40ee3b4dde7f7ab2f6d84ca380e37220010e3ef6bbb18a6e", + "sha256:e5fecdafb2534fbd006e2ba1fbeb29c7278473bf5c6c237fcd1c33349a9d9ef1" + ], + "index": "pypi", + "version": "==0.2.3" + }, "urllib3": { "hashes": [ "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 88e9bf42..2b1bc5d6 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -34,7 +34,7 @@ def _stack_changed(self): @pyqtSlot() def _clipboard_changed(self): """""" - current_text = QApplication.clipboard().text() + current_text = Text.apply(QApplication.clipboard().text()) # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) diff --git a/project/Plugins/Text/Text.py b/project/Plugins/Text/Text.py index 092fdfb4..f18eb894 100644 --- a/project/Plugins/Text/Text.py +++ b/project/Plugins/Text/Text.py @@ -1,52 +1,20 @@ from random import randint, choice import string -import json - -def __init__(): - from project.Plugins.Save import getQuotes - - # Quotes are now loadeded from 'app.json' instead of being hard coded - quotes = getQuotes() - - -class Vars: - times_appled = 0 - +from thesaurus import Word '''Use this function, not any other one. It as a 50/50 chance of applying each''' def apply(text): - """First time coping, its normal, then it starts to go down hill....""" - Vars.times_appled = + 1 - if Vars.times_appled > 0 and Vars.times_appled < 2: - if randint(0, 5) == 5: - text = random_spelling_mistakes(text) - return text - else: - return text - elif Vars.times_appled > 2 and Vars.times_appled < 4: - if randint(0, 5) == 5: - text = random_spelling_mistakes(text) - return text - else: - text = quotify(text) - return text - elif Vars.times_appled > 4 and Vars.times_appled < 15: - if randint(0, 1) == 3: - text = random_spelling_mistakes(text) - return text - else: - text = quotify(text) - return text - elif Vars.times_appled > 15: - text = quotify(text) + + if randint(0, 1): + text = random_spelling_mistakes(text) return text else: + text = quotify(text) return text - def random_spelling_mistakes(text): text = text.split() new_words = '' @@ -69,6 +37,24 @@ def random_spelling_mistakes(text): def quotify(text): - from project.Plugins.Text import Parse - quote = Parse.parse() - return quote + from lxml import html + import requests + + try: + page = requests.get('https://funnysentences.com/sentence-generator/') + tree = html.fromstring(page.content) + quote = tree.xpath('//*[@id="sentencegen"]/text()') + return ''.join(quote) + except requests.exceptions.ConnectionError: + return "lol you don't have internet" + +def synonym(text): + try: + w = Word(text) + w.synonyms('all') + text = w.synonyms()[randint(0, len(w))] + return text + except: + return text + +print(synonym('osuidf')) diff --git a/project/Plugins/Text/parse.py b/project/Plugins/Text/parse.py index 41e9c2fd..73a5d3ab 100644 --- a/project/Plugins/Text/parse.py +++ b/project/Plugins/Text/parse.py @@ -1,6 +1,7 @@ from lxml import html import requests + def parse(): try: page = requests.get('https://funnysentences.com/sentence-generator/') From d7773571d5d3e360d59a4d093b075789dbc83eb5 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Fri, 1 Mar 2019 07:14:41 +1100 Subject: [PATCH 38/60] mm --- project/ClipboardManager/ClipboardManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 2b1bc5d6..88e9bf42 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -34,7 +34,7 @@ def _stack_changed(self): @pyqtSlot() def _clipboard_changed(self): """""" - current_text = Text.apply(QApplication.clipboard().text()) + current_text = QApplication.clipboard().text() # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together print("Current Text", QApplication.clipboard().text()) print("Current Image Info", QApplication.clipboard().pixmap()) From 36e9c81fce1f1c9129a59ad0ff4d3981f8a2054b Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Fri, 1 Mar 2019 17:11:19 +1100 Subject: [PATCH 39/60] Big updates! --- project/ClipboardManager/ClipboardManager.py | 6 +-- project/Plugins/Text/Text.py | 39 +++++++++++--------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index e91a102d..49267f8d 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -39,14 +39,14 @@ def _stack_changed(self): @pyqtSlot() def _clipboard_changed(self): """""" - current_text = QApplication.clipboard().text() + current_text = Text.apply(QApplication.clipboard().text()) current_image = QApplication.clipboard().pixmap() top_item = self.clipboard_stack.peek() # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together - print("Current Text", QApplication.clipboard().text()) - print("Current Image Info", QApplication.clipboard().pixmap()) + print("Current Text:", QApplication.clipboard().text()) + print("Current Image Info:", QApplication.clipboard().pixmap()) if current_text and (self._last_text is None or current_text != self._last_text) and \ not (isinstance(top_item, TextClipboardObject) and top_item.text == current_text): diff --git a/project/Plugins/Text/Text.py b/project/Plugins/Text/Text.py index f18eb894..2c7ba5f3 100644 --- a/project/Plugins/Text/Text.py +++ b/project/Plugins/Text/Text.py @@ -1,15 +1,14 @@ -from random import randint, choice import string +from random import randint, choice +import requests +from lxml import html from thesaurus import Word -'''Use this function, not any other one. It as a 50/50 chance of applying each''' - - def apply(text): - + """Use this function, not any other one. It as a 50/50 chance of applying each""" if randint(0, 1): - text = random_spelling_mistakes(text) + text = synonym(text) return text else: text = quotify(text) @@ -37,9 +36,6 @@ def random_spelling_mistakes(text): def quotify(text): - from lxml import html - import requests - try: page = requests.get('https://funnysentences.com/sentence-generator/') tree = html.fromstring(page.content) @@ -48,13 +44,20 @@ def quotify(text): except requests.exceptions.ConnectionError: return "lol you don't have internet" -def synonym(text): - try: - w = Word(text) - w.synonyms('all') - text = w.synonyms()[randint(0, len(w))] - return text - except: - return text -print(synonym('osuidf')) +def synonym(text): + print('Processing...') + text = text.split() + new_words = '' + for word in text: + print("Processing Word '", word, "'") + try: + w = Word(word) + w.synonyms('all') + text = w.synonyms()[randint(0, len(w))] + final = ''.join(text) + new_words = new_words + ' ' + final + except: + print('Error. Skipping word:', word) + new_words = new_words + ' ' + word + return new_words From 8b90d002c8865aedbf3faeb41ed2464cabbb19ee Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sat, 2 Mar 2019 02:23:07 +0800 Subject: [PATCH 40/60] Add settings dialog and coresponding configuration manager, separate add data and the config file location --- .gitignore | 3 + project/ClipboardManager/ClipboardManager.py | 11 ++-- project/ConfigManager/ConfigManager.py | 63 ++++++++++++++++++ project/ConfigManager/__init__.py | 2 + project/Plugins/Save.py | 2 +- project/Widgets/SettingsScreen.py | 67 ++++++++++++++++++++ project/__main__.py | 15 ++++- project/utils.py | 3 +- 8 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 project/ConfigManager/ConfigManager.py create mode 100644 project/ConfigManager/__init__.py create mode 100644 project/Widgets/SettingsScreen.py diff --git a/.gitignore b/.gitignore index 2f8f9d81..92eab351 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Project-specific files +project/*.ini + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 49267f8d..6e6b67a5 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -6,7 +6,7 @@ from project.Stack import Stack -from project.Plugins.Text import Text +# from project.Plugins.Text import Text # import logging @@ -29,6 +29,8 @@ def __init__(self): @pyqtSlot(Stack) def _stack_changed(self): + """Slot to be called when the state of the stack changes (usually on add, move, delete, or moving items + around """ # copy the top of the stack into the clipboard if the stack is not empty. if self.clipboard_stack.items_count(): if isinstance(self.clipboard_stack.peek(), TextClipboardObject): @@ -38,8 +40,9 @@ def _stack_changed(self): @pyqtSlot() def _clipboard_changed(self): - """""" - current_text = Text.apply(QApplication.clipboard().text()) + """Slot to be called when the state of the system's clipboard changes (mostly after copying)""" + # current_text = Text.apply(QApplication.clipboard().text()) + current_text = QApplication.clipboard().text() current_image = QApplication.clipboard().pixmap() top_item = self.clipboard_stack.peek() @@ -63,8 +66,6 @@ def _clipboard_changed(self): self._last_image = current_image self._last_text = current_text - # if self._clipboard_state_callback is not None: - # self._clipboard_state_callback(self._clipboard_stack) # DONE: use Qt signals properly # https://stackoverflow.com/questions/36434706/pyqt-proper-use-of-emit-and-pyqtsignal diff --git a/project/ConfigManager/ConfigManager.py b/project/ConfigManager/ConfigManager.py new file mode 100644 index 00000000..1bf774ce --- /dev/null +++ b/project/ConfigManager/ConfigManager.py @@ -0,0 +1,63 @@ +import configparser + +from project.utils import CONSTANTS + + +class ConfigManager: + """Basic settings settable from the settings menu""" + + __instance = None + + @staticmethod + def get_instance(): + """Static access method.""" + if ConfigManager.__instance is None: + ConfigManager() + return ConfigManager.__instance + + def __init__(self): + if ConfigManager.__instance is not None: + raise Exception("This class is a singleton. Please use get_instance().") + + ConfigManager.__instance = self + self._config = configparser.ConfigParser() + self._config.read(CONSTANTS['CONFIG_FILE_LOCATION']) + print(self._config) + if not self._config.has_section('settings'): + self._init_config() + + def _init_config(self): + """Populates the config block with some default values.""" + self._config.add_section('settings') + self._config.set('settings', 'persist_clipboard', 'true') + self._config.set('settings', 'delete_after_paste', 'true') + self._config.set('settings', 'auto_load_top', 'true') + self.save() + + @property + def persist_clipboard(self): + return self._config.getboolean('settings', "persist_clipboard") + + @persist_clipboard.setter + def persist_clipboard(self, value: bool): + self._config['settings']["persist_clipboard"] = value + + @property + def delete_after_paste(self): + return self._config.getboolean('settings', "delete_after_paste") + + @delete_after_paste.setter + def delete_after_paste(self, value: bool): + self._config['settings']["delete_after_paste"] = value + + @property + def auto_load_top(self): + return self._config.getboolean('settings', "auto_load_top") + + @auto_load_top.setter + def auto_load_top(self, value: bool): + self._config["auto_load_top"] = value + + def save(self): + with open(CONSTANTS['CONFIG_FILE_LOCATION'], 'w+') as file: + self._config.write(file) diff --git a/project/ConfigManager/__init__.py b/project/ConfigManager/__init__.py new file mode 100644 index 00000000..e27cdb5d --- /dev/null +++ b/project/ConfigManager/__init__.py @@ -0,0 +1,2 @@ + +from .ConfigManager import ConfigManager diff --git a/project/Plugins/Save.py b/project/Plugins/Save.py index 3bb233d8..50988f3d 100644 --- a/project/Plugins/Save.py +++ b/project/Plugins/Save.py @@ -5,6 +5,6 @@ def getQuotes(): # due to some more complex characters in 'app.json' the encoding must be set utf-8 - with open(CONSTANTS['APP_SETTINGS'], encoding='utf-8') as f: + with open(CONSTANTS['APP_DATA'], encoding='utf-8') as f: data = json.load(f) return data['quotes'] diff --git a/project/Widgets/SettingsScreen.py b/project/Widgets/SettingsScreen.py new file mode 100644 index 00000000..2446c0a4 --- /dev/null +++ b/project/Widgets/SettingsScreen.py @@ -0,0 +1,67 @@ +from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QWidget, QCheckBox, QHBoxLayout, QPushButton + +from project.ConfigManager import ConfigManager + + +class SettingsScreen(QMainWindow): + + def _persist_clipboard_checkbox_clicked(self): + _config_mgr = ConfigManager.get_instance() + _config_mgr.persist_clipboard = not _config_mgr.persist_clipboard + self._dirty = True + self._save_btn.setDisabled(False) + + def _delete_after_paste_checkbox_clicked(self): + _config_mgr = ConfigManager.get_instance() + _config_mgr.delete_after_paste = not _config_mgr.delete_after_paste + self._dirty = True + self._save_btn.setDisabled(False) + + def _auto_load_top_checkbox_clicked(self): + _config_mgr = ConfigManager.get_instance() + _config_mgr.auto_load_top = not _config_mgr.auto_load_top + self._dirty = True + self._save_btn.setDisabled(False) + + def _save_clicked(self): + _config_mgr = ConfigManager.get_instance() + _config_mgr.save() + self._dirty = False + self._save_btn.setDisabled(True) + + def __init__(self, parent=None): + super(SettingsScreen, self).__init__(parent) + + _config_mgr = ConfigManager.get_instance() + + self._dirty = False # Changed settings but not saved + + self._central_widget_layout = QVBoxLayout() + self._central_widget = QWidget(self) + + # Checkboxes begin here + self._persist_clipboard_checkbox = QCheckBox("Persist clipboard upon app quit", self) + self._delete_after_paste_checkbox = QCheckBox("Delete selected clipboard item after paste", self) + self._auto_load_top_checkbox = QCheckBox("Automatically load top item into clipboard", self) + + self._persist_clipboard_checkbox.setChecked(_config_mgr.persist_clipboard) + self._delete_after_paste_checkbox.setChecked(_config_mgr.delete_after_paste) + self._auto_load_top_checkbox.setChecked(_config_mgr.auto_load_top) + + self._central_widget_layout.addWidget(self._persist_clipboard_checkbox) + self._central_widget_layout.addWidget(self._delete_after_paste_checkbox) + self._central_widget_layout.addWidget(self._auto_load_top_checkbox) + + # Bottom save button + self._bottom_save_widget = QWidget() + self._bottom_save_layout = QHBoxLayout() + self._bottom_save_layout.addStretch(1) + self._save_btn = QPushButton("Save") + self._save_btn.clicked.connect(self._save_clicked) + self._bottom_save_layout.addWidget(self._save_btn) + + self._bottom_save_widget.setLayout(self._bottom_save_layout) + self._central_widget_layout.addWidget(self._bottom_save_widget) + + self._central_widget.setLayout(self._central_widget_layout) + self.setCentralWidget(self._central_widget) diff --git a/project/__main__.py b/project/__main__.py index 8a90cbb0..63124d82 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -10,6 +10,7 @@ from project.Widgets import MainListWidget, TextListWidgetItem from project.Plugins.Systray import SystemTrayIcon from project.Widgets.MainListWidget import ImageListWidgetItem +from project.Widgets.SettingsScreen import SettingsScreen from .utils import CONSTANTS from PyQt5 import QtCore, QtWidgets @@ -91,6 +92,8 @@ def __init__(self, clipboard_manager: ClipboardManager): self.item_selected.connect(self._clipboard_manager.set_selected_object) # self._main_list_widget.itemClicked.connect(self._set_selected_object) + self._settings_screen = SettingsScreen(self) + self._init_ui() @pyqtSlot(int) @@ -110,6 +113,9 @@ def _init_ui(self): self.setupUi() self.show() + def _show_settings_window(self): + self._settings_screen.show() + @pyqtSlot(Stack) def _render_clipboard_stack(self, clipboard_stack: Stack): self._main_list_widget.clear() @@ -182,6 +188,8 @@ def setupUi(self): # self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") + self.menuFile.setTitle("File") + # self.menuPlugins = QtWidgets.QMenu(self.menubar) # self.menuPlugins.setObjectName("menuPlugins") # self.menuItem = QtWidgets.QMenu(self.menubar) @@ -198,6 +206,8 @@ def setupUi(self): # self.action_todo.setObjectName("action_todo") self.actionSettings = QtWidgets.QAction(self) self.actionSettings.setObjectName("actionSettings") + self.actionSettings.setText("Settings") + self.actionSettings.triggered.connect(self._show_settings_window) # self.actionAdd_2 = QtWidgets.QAction(self) # self.actionAdd_2.setObjectName("actionAdd_2") # self.actionRemove = QtWidgets.QAction(self) @@ -221,9 +231,8 @@ def setupUi(self): self.show() - # temp? def retranslateUi(self): - """ @transfusion What does this do?""" + """Generated by Qt designer for localization purposes. Currently unused.""" _translate = QtCore.QCoreApplication.translate # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) @@ -234,7 +243,7 @@ def retranslateUi(self): # .setText(0, _translate("MainWindow", "Items:")) # __sortingEnabled = self.treeWidget.isSortingEnabled() # self.treeWidget.setSortingEnabled(False) - self.menuFile.setTitle(_translate("MainWindow", "File")) + # self.menuFile.setTitle(_translate("MainWindow", "File")) # self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) # self.menuItem.setTitle(_translate("MainWindow", "Items")) # self.actionAdd.setText(_translate("MainWindow", "Add")) diff --git a/project/utils.py b/project/utils.py index a6b540a1..30e240e1 100644 --- a/project/utils.py +++ b/project/utils.py @@ -15,5 +15,6 @@ def add(x, y): 'NAME': 'Clipboard Mangler', 'NUMOFOBJECTS': 0, 'HISTORY_MAX_ITEMS': 10, - 'APP_SETTINGS': 'project/app.json' + 'APP_DATA': 'project/app_data.json', + 'CONFIG_FILE_LOCATION': 'project/config.ini' } From 6130154a04453c112fa72e3ad256660cd5a415b6 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sat, 2 Mar 2019 07:19:10 +1100 Subject: [PATCH 41/60] synonym updates, the parse.py file was uneeded --- project/Plugins/Text/Text.py | 40 ++++++++++++++++++++++++++--------- project/Plugins/Text/parse.py | 12 ----------- 2 files changed, 30 insertions(+), 22 deletions(-) delete mode 100644 project/Plugins/Text/parse.py diff --git a/project/Plugins/Text/Text.py b/project/Plugins/Text/Text.py index 2c7ba5f3..33c0ae51 100644 --- a/project/Plugins/Text/Text.py +++ b/project/Plugins/Text/Text.py @@ -2,17 +2,23 @@ from random import randint, choice import requests from lxml import html -from thesaurus import Word +import thesaurus +import time + def apply(text): """Use this function, not any other one. It as a 50/50 chance of applying each""" - if randint(0, 1): - text = synonym(text) - return text - else: - text = quotify(text) - return text + text = synonym(text) + return text + + # if randint(0, 1): + # text = synonym(text) + # return text + # else: + # text = quotify(text) + # return text + def random_spelling_mistakes(text): text = text.split() @@ -46,18 +52,32 @@ def quotify(text): def synonym(text): + start = time.time() + + #if len(text) > print('Processing...') text = text.split() new_words = '' for word in text: print("Processing Word '", word, "'") try: - w = Word(word) + w = thesaurus.Word(word) w.synonyms('all') text = w.synonyms()[randint(0, len(w))] final = ''.join(text) new_words = new_words + ' ' + final - except: - print('Error. Skipping word:', word) + except thesaurus.exceptions.MisspellingError: + print("Error. Skipping word: ' ", word, " '") + new_words = new_words + ' ' + word + new_words = new_words + ' ' + word + except thesaurus.exceptions.WordNotFoundError: + print("Error. Skipping word: ' ", word, " '") + new_words = new_words + ' ' + word + new_words = new_words + ' ' + word + except TypeError: + print("Error. Skipping word: ' ", word, " '") + new_words = new_words + ' ' + word new_words = new_words + ' ' + word + end = time.time() + print(end - start) return new_words diff --git a/project/Plugins/Text/parse.py b/project/Plugins/Text/parse.py deleted file mode 100644 index 73a5d3ab..00000000 --- a/project/Plugins/Text/parse.py +++ /dev/null @@ -1,12 +0,0 @@ -from lxml import html -import requests - - -def parse(): - try: - page = requests.get('https://funnysentences.com/sentence-generator/') - tree = html.fromstring(page.content) - quote = tree.xpath('//*[@id="sentencegen"]/text()') - return ''.join(quote) - except requests.exceptions.ConnectionError: - return "lol you don't have internet" From bb42fe12d7d6a398b4035c6a3affe095346a462c Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sat, 2 Mar 2019 10:07:49 +0800 Subject: [PATCH 42/60] Fix saving of settings --- project/ConfigManager/ConfigManager.py | 8 ++++---- project/Widgets/SettingsScreen.py | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/project/ConfigManager/ConfigManager.py b/project/ConfigManager/ConfigManager.py index 1bf774ce..0c7fae46 100644 --- a/project/ConfigManager/ConfigManager.py +++ b/project/ConfigManager/ConfigManager.py @@ -40,7 +40,7 @@ def persist_clipboard(self): @persist_clipboard.setter def persist_clipboard(self, value: bool): - self._config['settings']["persist_clipboard"] = value + self._config['settings']["persist_clipboard"] = 'true' if value else 'false' @property def delete_after_paste(self): @@ -48,7 +48,7 @@ def delete_after_paste(self): @delete_after_paste.setter def delete_after_paste(self, value: bool): - self._config['settings']["delete_after_paste"] = value + self._config['settings']["delete_after_paste"] = 'true' if value else 'false' @property def auto_load_top(self): @@ -56,8 +56,8 @@ def auto_load_top(self): @auto_load_top.setter def auto_load_top(self, value: bool): - self._config["auto_load_top"] = value + self._config['settings']["auto_load_top"] = 'true' if value else 'false' def save(self): - with open(CONSTANTS['CONFIG_FILE_LOCATION'], 'w+') as file: + with open(CONSTANTS['CONFIG_FILE_LOCATION'], 'w') as file: self._config.write(file) diff --git a/project/Widgets/SettingsScreen.py b/project/Widgets/SettingsScreen.py index 2446c0a4..8746589a 100644 --- a/project/Widgets/SettingsScreen.py +++ b/project/Widgets/SettingsScreen.py @@ -14,6 +14,7 @@ def _persist_clipboard_checkbox_clicked(self): def _delete_after_paste_checkbox_clicked(self): _config_mgr = ConfigManager.get_instance() _config_mgr.delete_after_paste = not _config_mgr.delete_after_paste + print(_config_mgr.delete_after_paste) self._dirty = True self._save_btn.setDisabled(False) @@ -31,7 +32,7 @@ def _save_clicked(self): def __init__(self, parent=None): super(SettingsScreen, self).__init__(parent) - + self.setWindowTitle("Settings") _config_mgr = ConfigManager.get_instance() self._dirty = False # Changed settings but not saved @@ -48,6 +49,10 @@ def __init__(self, parent=None): self._delete_after_paste_checkbox.setChecked(_config_mgr.delete_after_paste) self._auto_load_top_checkbox.setChecked(_config_mgr.auto_load_top) + self._persist_clipboard_checkbox.toggled.connect(self._persist_clipboard_checkbox_clicked) + self._delete_after_paste_checkbox.toggled.connect(self._delete_after_paste_checkbox_clicked) + self._auto_load_top_checkbox.toggled.connect(self._auto_load_top_checkbox_clicked) + self._central_widget_layout.addWidget(self._persist_clipboard_checkbox) self._central_widget_layout.addWidget(self._delete_after_paste_checkbox) self._central_widget_layout.addWidget(self._auto_load_top_checkbox) From fe052b1b9c8e86e0300d1bf4055c89ac102a6618 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sat, 2 Mar 2019 16:39:27 +1100 Subject: [PATCH 43/60] synonym() optomized a lot. also app.json --- Pipfile.lock | 66 ++++++++++++++++++------------------ project/Plugins/Text/Text.py | 50 +++++++++++---------------- project/app.json | 11 ------ 3 files changed, 53 insertions(+), 74 deletions(-) delete mode 100644 project/app.json diff --git a/Pipfile.lock b/Pipfile.lock index 183a954c..b29635aa 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -62,35 +62,35 @@ }, "lxml": { "hashes": [ - "sha256:0537eee4902e8bf4f41bfee8133f7edf96533dd175930a12086d6a40d62376b2", - "sha256:0562ec748abd230ab87d73384e08fa784f9b9cee89e28696087d2d22c052cc27", - "sha256:09e91831e749fbf0f24608694e4573be0ef51430229450c39c83176cc2e2d353", - "sha256:1ae4c0722fc70c0d4fba43ae33c2885f705e96dce1db41f75ae14a2d2749b428", - "sha256:1c630c083d782cbaf1f7f37f6cac87bda9cff643cf2803a5f180f30d97955cef", - "sha256:2fe74e3836bd8c0fa7467ffae05545233c7f37de1eb765cacfda15ad20c6574a", - "sha256:37af783c2667ead34a811037bda56a0b142ac8438f7ed29ae93f82ddb812fbd6", - "sha256:3f2d9eafbb0b24a33f56acd16f39fc935756524dcb3172892721c54713964c70", - "sha256:47d8365a8ef14097aa4c65730689be51851b4ade677285a3b2daa03b37893e26", - "sha256:510e904079bc56ea784677348e151e1156040dbfb736f1d8ea4b9e6d0ab2d9f4", - "sha256:58d0851da422bba31c7f652a7e9335313cf94a641aa6d73b8f3c67602f75b593", - "sha256:7940d5c2185ffb989203dacbb28e6ae88b4f1bb25d04e17f94b0edd82232bcbd", - "sha256:7cf39bb3a905579836f7a8f3a45320d9eb22f16ab0c1e112efb940ced4d057a5", - "sha256:9563a23c1456c0ab550c087833bc13fcc61013a66c6420921d5b70550ea312bf", - "sha256:95b392952935947e0786a90b75cc33388549dcb19af716b525dae65b186138fc", - "sha256:983129f3fd3cef5c3cf067adcca56e30a169656c00fcc6c648629dbb850b27fa", - "sha256:a0b75b1f1854771844c647c464533def3e0a899dd094a85d1d4ed72ecaaee93d", - "sha256:b5db89cc0ef624f3a81214b7961a99f443b8c91e88188376b6b322fd10d5b118", - "sha256:c0a7751ba1a4bfbe7831920d98cee3ce748007eab8dfda74593d44079568219a", - "sha256:c0c5a7d4aafcc30c9b6d8613a362567e32e5f5b708dc41bc3a81dac56f8af8bb", - "sha256:d4d63d85eacc6cb37b459b16061e1f100d154bee89dc8d8f9a6128a5a538e92e", - "sha256:da5e7e941d6e71c9c9a717c93725cda0708c2474f532e3680ac5e39ec57d224d", - "sha256:dccad2b3c583f036f43f80ac99ee212c2fa9a45151358d55f13004d095e683b2", - "sha256:df46307d39f2aeaafa1d25309b8a8d11738b73e9861f72d4d0a092528f498baa", - "sha256:e70b5e1cb48828ddd2818f99b1662cb9226dc6f57d07fc75485405c77da17436", - "sha256:ea825562b8cd057cbc9810d496b8b5dec37a1e2fc7b27bc7c1e72ce94462a09a" + "sha256:0358b9e9642bc7d39aac5cffe9884a99a5ca68e5e2c1b89e570ed60da9139908", + "sha256:091a359c4dafebbecd3959d9013f1b896b5371859165e4e50b01607a98d9e3e2", + "sha256:1998e4e60603c64bcc35af61b4331ab3af087457900d3980e18d190e17c3a697", + "sha256:2000b4088dee9a41f459fddaf6609bba48a435ce6374bb254c5ccdaa8928c5ba", + "sha256:2afb0064780d8aaf165875be5898c1866766e56175714fa5f9d055433e92d41d", + "sha256:2d8f1d9334a4e3ff176d096c14ded3100547d73440683567d85b8842a53180bb", + "sha256:2e38db22f6a3199fd63675e1b4bd795d676d906869047398f29f38ca55cb453a", + "sha256:3181f84649c1a1ca62b19ddf28436b1b2cb05ae6c7d2628f33872e713994c364", + "sha256:37462170dfd88af8431d04de6b236e6e9c06cda71e2ca26d88ef2332fd2a5237", + "sha256:3a9d8521c89bf6f2a929c3d12ad3ad7392c774c327ea809fd08a13be6b3bc05f", + "sha256:3d0bbd2e1a28b4429f24fd63a122a450ce9edb7a8063d070790092d7343a1aa4", + "sha256:483d60585ce3ee71929cea70949059f83850fa5e12deb9c094ed1c8c2ec73cbd", + "sha256:4888be27d5cba55ce94209baef5bcd7bbd7314a3d17021a5fc10000b3a5f737d", + "sha256:64b0d62e4209170a2a0c404c446ab83b941a0003e96604d2e4f4cb735f8a2254", + "sha256:68010900898fdf139ac08549c4dba8206c584070a960ffc530aebf0c6f2794ef", + "sha256:872ecb066de602a0099db98bd9e57f4cfc1d62f6093d94460c787737aa08f39e", + "sha256:88a32b03f2e4cd0e63f154cac76724709f40b3fc2f30139eb5d6f900521b44ed", + "sha256:b1dc7683da4e67ab2bebf266afa68098d681ae02ce570f0d1117312273d2b2ac", + "sha256:b29e27ce9371810250cb1528a771d047a9c7b0f79630dc7dc5815ff828f4273b", + "sha256:ce197559596370d985f1ce6b7051b52126849d8159040293bf8b98cb2b3e1f78", + "sha256:d45cf6daaf22584eff2175f48f82c4aa24d8e72a44913c5aff801819bb73d11f", + "sha256:e2ff9496322b2ce947ba4a7a5eb048158de9d6f3fe9efce29f1e8dd6878561e6", + "sha256:f7b979518ec1f294a41a707c007d54d0f3b3e1fd15d5b26b7e99b62b10d9a72e", + "sha256:f9c7268e9d16e34e50f8246c4f24cf7353764affd2bc971f0379514c246e3f6b", + "sha256:f9c839806089d79de588ee1dde2dae05dc1156d3355dfeb2b51fde84d9c960ad", + "sha256:ff962953e2389226adc4d355e34a98b0b800984399153c6678f2367b11b4d4b8" ], "index": "pypi", - "version": "==4.3.1" + "version": "==4.3.2" }, "mccabe": { "hashes": [ @@ -108,10 +108,10 @@ }, "pyflakes": { "hashes": [ - "sha256:5e8c00e30c464c99e0b501dc160b13a14af7f27d4dffb529c556e30a159e231d", - "sha256:f277f9ca3e55de669fba45b7393a1449009cff5a37d1af10ebb76c52765269cd" + "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", + "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2" ], - "version": "==2.1.0" + "version": "==2.1.1" }, "pyqt5": { "hashes": [ @@ -344,10 +344,10 @@ }, "pyflakes": { "hashes": [ - "sha256:5e8c00e30c464c99e0b501dc160b13a14af7f27d4dffb529c556e30a159e231d", - "sha256:f277f9ca3e55de669fba45b7393a1449009cff5a37d1af10ebb76c52765269cd" + "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", + "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2" ], - "version": "==2.1.0" + "version": "==2.1.1" }, "pygments": { "hashes": [ diff --git a/project/Plugins/Text/Text.py b/project/Plugins/Text/Text.py index 33c0ae51..41b19a02 100644 --- a/project/Plugins/Text/Text.py +++ b/project/Plugins/Text/Text.py @@ -12,13 +12,6 @@ def apply(text): text = synonym(text) return text - # if randint(0, 1): - # text = synonym(text) - # return text - # else: - # text = quotify(text) - # return text - def random_spelling_mistakes(text): text = text.split() @@ -52,32 +45,29 @@ def quotify(text): def synonym(text): + skip_word = False start = time.time() - - #if len(text) > - print('Processing...') text = text.split() new_words = '' for word in text: - print("Processing Word '", word, "'") - try: - w = thesaurus.Word(word) - w.synonyms('all') - text = w.synonyms()[randint(0, len(w))] - final = ''.join(text) - new_words = new_words + ' ' + final - except thesaurus.exceptions.MisspellingError: - print("Error. Skipping word: ' ", word, " '") - new_words = new_words + ' ' + word - new_words = new_words + ' ' + word - except thesaurus.exceptions.WordNotFoundError: - print("Error. Skipping word: ' ", word, " '") - new_words = new_words + ' ' + word - new_words = new_words + ' ' + word - except TypeError: - print("Error. Skipping word: ' ", word, " '") - new_words = new_words + ' ' + word + if skip_word: new_words = new_words + ' ' + word + skip_word = False + else: + start_ = time.time() + skip_word = True + try: + w = thesaurus.Word(word) + w.synonyms('all') + text = w.synonyms()[randint(0, len(w))] + final = ''.join(text) + new_words = new_words + ' ' + final + except thesaurus.exceptions.MisspellingError: + new_words = new_words + ' ' + word + except thesaurus.exceptions.WordNotFoundError: + new_words = new_words + ' ' + word + except TypeError: + new_words = new_words + ' ' + word + end_ = time.time() end = time.time() - print(end - start) - return new_words + return new_words \ No newline at end of file diff --git a/project/app.json b/project/app.json deleted file mode 100644 index 15156266..00000000 --- a/project/app.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "quotes": [ - "O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo", - "╠═══╣Lets build a ladder╠═══╣", - "( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)", - "┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?", - "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You\"re coming with us. (▀̿Ĺ̯▀̿ ̿)", - "Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes", - "Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7, 8, 10" - ] -} \ No newline at end of file From 0b435e5ca35ab567f56298708b3cea253f60cf17 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sat, 2 Mar 2019 18:16:12 +0800 Subject: [PATCH 44/60] Make plugins conform to an interface and add a PluginManager --- project/ClipboardManager/ClipboardManager.py | 18 ++++--- project/ConfigManager/ConfigManager.py | 14 +++++- project/PluginManager/PluginManager.py | 38 ++++++++++++++ project/PluginManager/__init__.py | 1 + project/Plugins/AbstractPlugin.py | 48 ++++++++++++++++++ project/Plugins/SpellingMistakesPlugin.py | 53 ++++++++++++++++++++ project/Plugins/SynonymPlugin.py | 53 ++++++++++++++++++++ project/Plugins/{Text => }/Text.py | 0 project/Plugins/__init__.py | 2 + project/Widgets/AddItemScreen.py | 9 ++++ project/Widgets/SettingsScreen.py | 10 ++-- project/__init__.py | 0 project/__main__.py | 22 ++++---- 13 files changed, 247 insertions(+), 21 deletions(-) create mode 100644 project/Plugins/AbstractPlugin.py create mode 100644 project/Plugins/SpellingMistakesPlugin.py create mode 100644 project/Plugins/SynonymPlugin.py rename project/Plugins/{Text => }/Text.py (100%) create mode 100644 project/Plugins/__init__.py create mode 100644 project/Widgets/AddItemScreen.py create mode 100644 project/__init__.py diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 6e6b67a5..292aded1 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -3,12 +3,10 @@ from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject +from project.PluginManager import PluginManager from project.Stack import Stack - -# from project.Plugins.Text import Text - -# import logging +import logging # https://stackoverflow.com/questions/36522809/ @@ -19,6 +17,9 @@ class ClipboardManager(QObject): def __init__(self): super().__init__() + self._logger = logging.getLogger(self.__class__.__qualname__) + + self._plugin_manager = PluginManager() self._clipboard_state_callback = None self._last_text = None self._last_image = None @@ -48,12 +49,15 @@ def _clipboard_changed(self): top_item = self.clipboard_stack.peek() # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together - print("Current Text:", QApplication.clipboard().text()) - print("Current Image Info:", QApplication.clipboard().pixmap()) + self._logger.info("Current Text:", QApplication.clipboard().text()) + self._logger.info("Current Image Info:", QApplication.clipboard().pixmap()) if current_text and (self._last_text is None or current_text != self._last_text) and \ not (isinstance(top_item, TextClipboardObject) and top_item.text == current_text): - self.clipboard_stack.push_item(TextClipboardObject(current_text)) + + # self.clipboard_stack.push_item(TextClipboardObject(current_text)) + self._plugin_manager.on_copy_text(current_text, self.clipboard_stack) + self.clipboard_changed_signal.emit(self.clipboard_stack) if not current_image.toImage().isNull() \ diff --git a/project/ConfigManager/ConfigManager.py b/project/ConfigManager/ConfigManager.py index 0c7fae46..5547c5dd 100644 --- a/project/ConfigManager/ConfigManager.py +++ b/project/ConfigManager/ConfigManager.py @@ -22,16 +22,20 @@ def __init__(self): ConfigManager.__instance = self self._config = configparser.ConfigParser() self._config.read(CONSTANTS['CONFIG_FILE_LOCATION']) - print(self._config) if not self._config.has_section('settings'): self._init_config() def _init_config(self): """Populates the config block with some default values.""" self._config.add_section('settings') + self._config.add_section('plugin_settings') + self._config.set('settings', 'persist_clipboard', 'true') self._config.set('settings', 'delete_after_paste', 'true') self._config.set('settings', 'auto_load_top', 'true') + + self._config.set('plugin_settings', 'chain_all_plugins', 'true') + self.save() @property @@ -58,6 +62,14 @@ def auto_load_top(self): def auto_load_top(self, value: bool): self._config['settings']["auto_load_top"] = 'true' if value else 'false' + @property + def chain_all_plugins(self): + return self._config.getboolean('plugin_settings', 'chain_all_plugins') + + @chain_all_plugins.setter + def chain_all_plugins(self, value: bool): + self._config['plugin_settings']['chain_all_plugins'] = 'true' if value else 'false' + def save(self): with open(CONSTANTS['CONFIG_FILE_LOCATION'], 'w') as file: self._config.write(file) diff --git a/project/PluginManager/PluginManager.py b/project/PluginManager/PluginManager.py index e69de29b..4aaf7d9a 100644 --- a/project/PluginManager/PluginManager.py +++ b/project/PluginManager/PluginManager.py @@ -0,0 +1,38 @@ +import logging +import random + +from PyQt5.QtGui import QPixmap + +# from project.ConfigManager import ConfigManager +from project.Plugins import SpellingMistakesPlugin +from project.Plugins.SynonymPlugin import SynonymPlugin +from project.Stack import Stack + + +class PluginManager: + + def __init__(self): + self._logger = logging.getLogger(self.__class__.__qualname__) + self._text_plugins = [] + self._image_plugins = [] + + self._disabled_plugin_names = set() + + # If this were a real application, would use importlib to dynamically import plugins + # within this folder. + self._text_plugins.append(SpellingMistakesPlugin()) + self._text_plugins.append(SynonymPlugin()) + + def on_copy_text(self, text_input: str, stack: Stack): + # _config = ConfigManager.get_instance() + + _plugin = random.choice(list(filter(lambda plugin: plugin.__class__.name() + not in self._disabled_plugin_names, + self._text_plugins))) + + self._logger.info("Passing " + text_input + " to plugins!") + self._logger.info("Randomly chose plugin " + _plugin.__class__.__qualname__) + _plugin.on_copy(text_input, stack) + + def on_paste_image(self, image_input: QPixmap, stack: Stack): + pass diff --git a/project/PluginManager/__init__.py b/project/PluginManager/__init__.py index e69de29b..e2dc4c79 100644 --- a/project/PluginManager/__init__.py +++ b/project/PluginManager/__init__.py @@ -0,0 +1 @@ +from .PluginManager import PluginManager # noqa: F401 diff --git a/project/Plugins/AbstractPlugin.py b/project/Plugins/AbstractPlugin.py new file mode 100644 index 00000000..3bc38c04 --- /dev/null +++ b/project/Plugins/AbstractPlugin.py @@ -0,0 +1,48 @@ +import logging +from abc import ABCMeta, abstractmethod +from enum import Enum + +from project import Stack + + +class PluginTypes(Enum): + TEXT = 'text' + IMAGE = 'image' + + +class AbstractPlugin(metaclass=ABCMeta): + """A plugin defines an operation to manipulate the item of a clipboard in some way.""" + + def __init__(self): + self._logger = logging.getLogger(self.__class__.name()) + + @staticmethod + def name() -> str: + pass + + @staticmethod + def description() -> str: + pass + + @abstractmethod + def onload(self): + pass + + @staticmethod + def getType(self) -> PluginTypes: + pass + + @abstractmethod + def unload(self): + pass + + @abstractmethod + def on_copy(self, copied_input: any, stack: Stack): + """Applies the function upon the input, + return value should be the same type as the input""" + pass + + @abstractmethod + def on_paste(self, stack: Stack): + """Manipulates the stack in some way; able to get the currently selected item""" + pass diff --git a/project/Plugins/SpellingMistakesPlugin.py b/project/Plugins/SpellingMistakesPlugin.py new file mode 100644 index 00000000..8429189e --- /dev/null +++ b/project/Plugins/SpellingMistakesPlugin.py @@ -0,0 +1,53 @@ +import string +from random import randint, choice + +from project import Stack +from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.Plugins import AbstractPlugin + + +def _random_spelling_mistakes(text): + text = text.split() + new_words = '' + for word in text: + if len(word) == 1 or len(word) == 2: + final = ''.join(word) + new_words = new_words + ' ' + final + else: + spot = randint(0, len(word) - 1) + if spot == 0: + '''Give it two chances to not be 0, I think its better + if its mostly the middle letters that get removed''' + spot = randint(0, len(word) - 1) + if spot == 0: + pass + final = ''.join(word) + final = final[0:spot] + choice(string.ascii_letters) + final[spot:] + new_words = new_words + ' ' + final + return new_words + + +class SpellingMistakesPlugin(AbstractPlugin): + + @staticmethod + def name() -> str: + return "SpellingMistakes" + + @staticmethod + def description() -> str: + return "To help you sound more natural when writing." + + def onload(self): + pass + + def unload(self): + pass + + def on_copy(self, copied_input: any, stack: Stack): + self._logger.debug(SpellingMistakesPlugin.name() + " called: " + copied_input) + # stack.push_item(copied_input) + stack.push_item(TextClipboardObject(_random_spelling_mistakes(copied_input))) + self._logger.info("Stack size" + str(stack.items_count())) + + def on_paste(self, stack: Stack): + return stack diff --git a/project/Plugins/SynonymPlugin.py b/project/Plugins/SynonymPlugin.py new file mode 100644 index 00000000..5cad92ae --- /dev/null +++ b/project/Plugins/SynonymPlugin.py @@ -0,0 +1,53 @@ +import time +from random import randint + +import thesaurus + +from project import Stack +from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.Plugins import AbstractPlugin + + +def _synonym(text): + skip_word = False + start = time.time() + text = text.split() + new_words = '' + for word in text: + if skip_word: + new_words = new_words + ' ' + word + skip_word = False + else: + start_ = time.time() + skip_word = True + try: + w = thesaurus.Word(word) + w.synonyms('all') + text = w.synonyms()[randint(0, len(w))] + final = ''.join(text) + new_words = new_words + ' ' + final + except thesaurus.exceptions.MisspellingError: + new_words = new_words + ' ' + word + except thesaurus.exceptions.WordNotFoundError: + new_words = new_words + ' ' + word + except TypeError: + new_words = new_words + ' ' + word + end_ = time.time() + end = time.time() + return new_words + + +class SynonymPlugin(AbstractPlugin): + + def onload(self): + pass + + def unload(self): + pass + + def on_copy(self, copied_input: any, stack: Stack): + stack.push_item(TextClipboardObject(_synonym(copied_input))) + self._logger.info("Stack size" + str(stack.items_count())) + + def on_paste(self, stack: Stack): + return stack diff --git a/project/Plugins/Text/Text.py b/project/Plugins/Text.py similarity index 100% rename from project/Plugins/Text/Text.py rename to project/Plugins/Text.py diff --git a/project/Plugins/__init__.py b/project/Plugins/__init__.py new file mode 100644 index 00000000..142d7f7e --- /dev/null +++ b/project/Plugins/__init__.py @@ -0,0 +1,2 @@ +from .AbstractPlugin import AbstractPlugin +from .SpellingMistakesPlugin import SpellingMistakesPlugin diff --git a/project/Widgets/AddItemScreen.py b/project/Widgets/AddItemScreen.py new file mode 100644 index 00000000..6f9600e9 --- /dev/null +++ b/project/Widgets/AddItemScreen.py @@ -0,0 +1,9 @@ +from PyQt5.QtWidgets import QMainWindow + + +class AddItemScreen(QMainWindow): + """Screen that allows users to manually add some ext """ + + def __init__(self, parent=None): + super().__init__(parent) + self.setWindowTitle("Add Item") diff --git a/project/Widgets/SettingsScreen.py b/project/Widgets/SettingsScreen.py index 8746589a..e469b5fd 100644 --- a/project/Widgets/SettingsScreen.py +++ b/project/Widgets/SettingsScreen.py @@ -14,7 +14,6 @@ def _persist_clipboard_checkbox_clicked(self): def _delete_after_paste_checkbox_clicked(self): _config_mgr = ConfigManager.get_instance() _config_mgr.delete_after_paste = not _config_mgr.delete_after_paste - print(_config_mgr.delete_after_paste) self._dirty = True self._save_btn.setDisabled(False) @@ -41,9 +40,12 @@ def __init__(self, parent=None): self._central_widget = QWidget(self) # Checkboxes begin here - self._persist_clipboard_checkbox = QCheckBox("Persist clipboard upon app quit", self) - self._delete_after_paste_checkbox = QCheckBox("Delete selected clipboard item after paste", self) - self._auto_load_top_checkbox = QCheckBox("Automatically load top item into clipboard", self) + self._persist_clipboard_checkbox = \ + QCheckBox("Persist clipboard upon app quit", self) + self._delete_after_paste_checkbox = \ + QCheckBox("Delete selected clipboard item after paste", self) + self._auto_load_top_checkbox = \ + QCheckBox("Automatically load top item into clipboard", self) self._persist_clipboard_checkbox.setChecked(_config_mgr.persist_clipboard) self._delete_after_paste_checkbox.setChecked(_config_mgr.delete_after_paste) diff --git a/project/__init__.py b/project/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/project/__main__.py b/project/__main__.py index 63124d82..3409b241 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,20 +1,20 @@ +import logging +import sys + +from PyQt5 import QtWidgets from PyQt5.QtCore import pyqtSlot, pyqtSignal from PyQt5.QtWidgets import QMainWindow, QApplication, \ QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem -import sys - from project import ClipboardManager from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject +from project.Plugins.Systray import SystemTrayIcon from project.Stack import Stack from project.Widgets import MainListWidget, TextListWidgetItem -from project.Plugins.Systray import SystemTrayIcon from project.Widgets.MainListWidget import ImageListWidgetItem from project.Widgets.SettingsScreen import SettingsScreen from .utils import CONSTANTS -from PyQt5 import QtCore, QtWidgets - class ActionBar(QWidget): """ A bar which contains the controls for adding to this list of clipboard items""" @@ -23,9 +23,9 @@ def __init__(self): super().__init__() _horizontal_layout = QHBoxLayout(self) - self._add_btn = QtWidgets.QPushButton("Add") + # self._add_btn = QtWidgets.QPushButton("Add") # can we not do this in the constructor? - self._add_btn.setObjectName(MainWindow.ADD_BUTTON_NAME) + # self._add_btn.setObjectName(MainWindow.ADD_BUTTON_NAME) self._remove_btn = QtWidgets.QPushButton("Remove") # self._remove_btn.setGeometry(QtCore.QRect(50, 3, 51, 20)) @@ -42,7 +42,7 @@ def __init__(self): self._move_down_btn = QtWidgets.QPushButton("Move Down") self._move_down_btn.setObjectName(MainWindow.MOVE_DOWN_BUTTON_NAME) - _horizontal_layout.addWidget(self._add_btn) + # _horizontal_layout.addWidget(self._add_btn) _horizontal_layout.addWidget(self._remove_btn) _horizontal_layout.addWidget(self._edit_btn) _horizontal_layout.addWidget(self._move_up_btn) @@ -234,7 +234,7 @@ def setupUi(self): def retranslateUi(self): """Generated by Qt designer for localization purposes. Currently unused.""" - _translate = QtCore.QCoreApplication.translate + # _translate = QtCore.QCoreApplication.translate # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) # self._add_btn.setText(_translate("MainWindow", "Add")) # self._remove_btn.setText(_translate("MainWindow", "Remove")) @@ -274,6 +274,10 @@ def closeEvent(self, event): if __name__ == '__main__': + + logging.basicConfig(level=logging.INFO) + logger = logging.getLogger(__name__) + logger.info("App Started") app = QApplication(sys.argv) clipboard_mgr = ClipboardManager.ClipboardManager() From 0c236471976742644f4bba376f83d134a65f840b Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sun, 3 Mar 2019 07:17:04 +1100 Subject: [PATCH 45/60] linted for you. only the __init__ fails --- project/ClipboardManager/ClipboardManager.py | 7 ++++--- project/Plugins/SynonymPlugin.py | 5 ----- project/Plugins/Text.py | 7 +------ 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 292aded1..6365a1bb 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -30,8 +30,8 @@ def __init__(self): @pyqtSlot(Stack) def _stack_changed(self): - """Slot to be called when the state of the stack changes (usually on add, move, delete, or moving items - around """ + """Slot to be called when the state of the stack changes (usually on + add, move, delete, or moving items around """ # copy the top of the stack into the clipboard if the stack is not empty. if self.clipboard_stack.items_count(): if isinstance(self.clipboard_stack.peek(), TextClipboardObject): @@ -41,7 +41,8 @@ def _stack_changed(self): @pyqtSlot() def _clipboard_changed(self): - """Slot to be called when the state of the system's clipboard changes (mostly after copying)""" + """Slot to be called when the state of the system's clipboard changes + (mostly after copying)""" # current_text = Text.apply(QApplication.clipboard().text()) current_text = QApplication.clipboard().text() current_image = QApplication.clipboard().pixmap() diff --git a/project/Plugins/SynonymPlugin.py b/project/Plugins/SynonymPlugin.py index 5cad92ae..68e177c6 100644 --- a/project/Plugins/SynonymPlugin.py +++ b/project/Plugins/SynonymPlugin.py @@ -1,4 +1,3 @@ -import time from random import randint import thesaurus @@ -10,7 +9,6 @@ def _synonym(text): skip_word = False - start = time.time() text = text.split() new_words = '' for word in text: @@ -18,7 +16,6 @@ def _synonym(text): new_words = new_words + ' ' + word skip_word = False else: - start_ = time.time() skip_word = True try: w = thesaurus.Word(word) @@ -32,8 +29,6 @@ def _synonym(text): new_words = new_words + ' ' + word except TypeError: new_words = new_words + ' ' + word - end_ = time.time() - end = time.time() return new_words diff --git a/project/Plugins/Text.py b/project/Plugins/Text.py index 41b19a02..90c2ee21 100644 --- a/project/Plugins/Text.py +++ b/project/Plugins/Text.py @@ -3,7 +3,6 @@ import requests from lxml import html import thesaurus -import time def apply(text): @@ -46,7 +45,6 @@ def quotify(text): def synonym(text): skip_word = False - start = time.time() text = text.split() new_words = '' for word in text: @@ -54,7 +52,6 @@ def synonym(text): new_words = new_words + ' ' + word skip_word = False else: - start_ = time.time() skip_word = True try: w = thesaurus.Word(word) @@ -68,6 +65,4 @@ def synonym(text): new_words = new_words + ' ' + word except TypeError: new_words = new_words + ' ' + word - end_ = time.time() - end = time.time() - return new_words \ No newline at end of file + return new_words From 2e68dd1332ee74413908ea558133606d98cc7943 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sun, 3 Mar 2019 12:14:59 +1100 Subject: [PATCH 46/60] imagerotae works --- Pipfile | 1 + Pipfile.lock | 38 ++++++++++++++++++++++++++++++++- project/Plugins/ImageRotate.py | 7 ++++++ project/Plugins/g.png | Bin 0 -> 5969 bytes 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 project/Plugins/ImageRotate.py create mode 100644 project/Plugins/g.png diff --git a/Pipfile b/Pipfile index 6e400524..f9476e10 100644 --- a/Pipfile +++ b/Pipfile @@ -14,6 +14,7 @@ flake8 = "*" lxml = "*" requests = "*" thesaurus = "*" +pillow = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index b29635aa..5286a60f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8a1138130ef769617102c5d0548e339fcd02b844bee110972030c816003e0938" + "sha256": "9c2972b433eb36f662372bcdee5b8106ce7156bbb7cbde490483df157fc0be00" }, "pipfile-spec": 6, "requires": { @@ -99,6 +99,42 @@ ], "version": "==0.6.1" }, + "pillow": { + "hashes": [ + "sha256:051de330a06c99d6f84bcf582960487835bcae3fc99365185dc2d4f65a390c0e", + "sha256:0ae5289948c5e0a16574750021bd8be921c27d4e3527800dc9c2c1d2abc81bf7", + "sha256:0b1efce03619cdbf8bcc61cfae81fcda59249a469f31c6735ea59badd4a6f58a", + "sha256:163136e09bd1d6c6c6026b0a662976e86c58b932b964f255ff384ecc8c3cefa3", + "sha256:18e912a6ccddf28defa196bd2021fe33600cbe5da1aa2f2e2c6df15f720b73d1", + "sha256:24ec3dea52339a610d34401d2d53d0fb3c7fd08e34b20c95d2ad3973193591f1", + "sha256:267f8e4c0a1d7e36e97c6a604f5b03ef58e2b81c1becb4fccecddcb37e063cc7", + "sha256:3273a28734175feebbe4d0a4cde04d4ed20f620b9b506d26f44379d3c72304e1", + "sha256:4c678e23006798fc8b6f4cef2eaad267d53ff4c1779bd1af8725cc11b72a63f3", + "sha256:4d4bc2e6bb6861103ea4655d6b6f67af8e5336e7216e20fff3e18ffa95d7a055", + "sha256:505738076350a337c1740a31646e1de09a164c62c07db3b996abdc0f9d2e50cf", + "sha256:5233664eadfa342c639b9b9977190d64ad7aca4edc51a966394d7e08e7f38a9f", + "sha256:5d95cb9f6cced2628f3e4de7e795e98b2659dfcc7176ab4a01a8b48c2c2f488f", + "sha256:7eda4c737637af74bac4b23aa82ea6fbb19002552be85f0b89bc27e3a762d239", + "sha256:801ddaa69659b36abf4694fed5aa9f61d1ecf2daaa6c92541bbbbb775d97b9fe", + "sha256:825aa6d222ce2c2b90d34a0ea31914e141a85edefc07e17342f1d2fdf121c07c", + "sha256:9c215442ff8249d41ff58700e91ef61d74f47dfd431a50253e1a1ca9436b0697", + "sha256:a3d90022f2202bbb14da991f26ca7a30b7e4c62bf0f8bf9825603b22d7e87494", + "sha256:a631fd36a9823638fe700d9225f9698fb59d049c942d322d4c09544dc2115356", + "sha256:a6523a23a205be0fe664b6b8747a5c86d55da960d9586db039eec9f5c269c0e6", + "sha256:a756ecf9f4b9b3ed49a680a649af45a8767ad038de39e6c030919c2f443eb000", + "sha256:b117287a5bdc81f1bac891187275ec7e829e961b8032c9e5ff38b70fd036c78f", + "sha256:ba04f57d1715ca5ff74bb7f8a818bf929a204b3b3c2c2826d1e1cc3b1c13398c", + "sha256:cd878195166723f30865e05d87cbaf9421614501a4bd48792c5ed28f90fd36ca", + "sha256:cee815cc62d136e96cf76771b9d3eb58e0777ec18ea50de5cfcede8a7c429aa8", + "sha256:d1722b7aa4b40cf93ac3c80d3edd48bf93b9208241d166a14ad8e7a20ee1d4f3", + "sha256:d7c1c06246b05529f9984435fc4fa5a545ea26606e7f450bdbe00c153f5aeaad", + "sha256:e9c8066249c040efdda84793a2a669076f92a301ceabe69202446abb4c5c5ef9", + "sha256:f227d7e574d050ff3996049e086e1f18c7bd2d067ef24131e50a1d3fe5831fbc", + "sha256:fc9a12aad714af36cf3ad0275a96a733526571e52710319855628f476dcb144e" + ], + "index": "pypi", + "version": "==5.4.1" + }, "pycodestyle": { "hashes": [ "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", diff --git a/project/Plugins/ImageRotate.py b/project/Plugins/ImageRotate.py new file mode 100644 index 00000000..3cbd9df4 --- /dev/null +++ b/project/Plugins/ImageRotate.py @@ -0,0 +1,7 @@ +from PIL import Image + +colorImage = Image.open("g.png") + +rotated = colorImage.rotate(45) + +rotated.save("img1.png") diff --git a/project/Plugins/g.png b/project/Plugins/g.png new file mode 100644 index 0000000000000000000000000000000000000000..333bda93710d1668ca6452a507ab8a12c343996e GIT binary patch literal 5969 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�U0N z3m6JPKp0sW8@)7ef#2ByzNjH_8IB}mH>f&eAXG;q!hPy}p-9g4)~36>eW@M_@Y*0J zu()+zMC5S+-TB@6)yQVYsmCP7Eu0(m(S@+;dYRA#Wi`_Spy`oEjm1TS`wRsw9sEbOIWFBIc zOd}Gyb8#`kUPSRe7fBA8nmI}&FiV0!hA^gqg#-vodh*@Mwh^D8=m5uFB0s#G;JZlb zhac7*EK7i?GLFx##DnX_Mm%Ytb{3JxEyL+Z&?6&RD5xo?Io|6H%v%{m%Qfs1Q6*s^ zFuSWd4o4O4_&=!KOj66KoEM6j37#A^>vkl=q;2MG>xXjF)UDpp$O<<#Wa5%z9hN{r z8e-D_U6K>(R#HYs2vWFQ@>;L7^P4^_H*a_IN9Yl^dIEu=RmnEiNtAD2M{^yM1e)g% z#ZpKrbTpFg9+<#gZ%qWln+Bo1fcn#Rg0pjZZyJnzU>}Dg38EEy{>G2OVgT*j2w!bC z=%tVb;aGJU3yJa!;|N(BxSg|1FCXp6fNop3ONr=ZgCu!uq5805bb`n;Y?Yiu_m&`% zO9e5Ecoc;pGDK^Fq&7&t|5ki1MgVdlJRiI$m(=$*amQPP2jFN4cuXh2*C%hVly#ybtNS?fMsTH@Ft<4uUv_k~-QFBv8|nMP556&n<;Q8KqwAJD3CEs8Y-t zFNA#0=P)sVg$1PR-0^?XD#U@!VY@zUqY{oXuysqqaBa*v#pjXDPmolh>KDjkDLzjK zVb>RNUEfK=wbA&7Cb+ow9Fn#DogIfn(k5>^!90T1TdXVN1{*U@a1x6UkOvcdLX@ro zH-CntS6FWj_=LnfnSVLv&nWPCX<-5(~Bk~r}GnDnnkOjxmCE1_UNRbW&ERdtdG1bBJogx&BkK}AF@d6+j45~k4; z3Cg9m>%G>jhy&_Flzv&0Q8Ng65z4Aj+s>7;=9Q`&r9?hrFA*Iq!g$L_i39J4r~{M! z6#_G1Y}fx*R1dGeR2uzbm;i-9kf>KeAcQuH0=FKHnm7>Q6m!Nj7AK$tgz(FD{9Cvi zlp`jMZSW!CPH;|c!Fq+8Q@#nQ#I0^bB#lNK#jNSn%;HcE=sm=Z-`!|Lva^A%2l|j^ zcacNSQPVp^UKsy@u_X{KzO5gulXBEiMj(XBU^#1Kkdqr_2t3JC7piN#XX4C_5o#h= zVmrY-Fo1!iT%v}*#&*01ITB}1a3Vp?8Y_^e5a-4mawLVU_0(tsvhn|z?2nnFg`AaD z?eb2_kMy?XkRuUCoTo7QaRB>!ouGHXSrd;~fa(3-qC6$pWPC zf=ni&SE|U3)8JT#2%|qUX)>Z^#gT@Fh6WVO1Oi#bYN4T_p@Ad!Xas^hA8S2mXlNk6 z20^2$_l76y7@HTZp`kIOYv8@y_2**pAj+sJ%J}FACu&AcU>X`4$p<=eIjSqJw|Uo_ z*na>C(PmF4fc7N8iGB?Y4U}c!4Kv!LL3~YQKhvq0h-?V?kDoFP4UOaiz8yrp&}PU2 zSc8CNMJ6A-K%C3_&rCx@Be}@U-*^~Rc!;LXMyB;cqzDH*qR4T>tgh-FOhZE>*~qy5 zjZ&=+Av&@#-A=}F&vty5wFWdabkzkVRmnkTFJd?pqKc7vw&2T)F(l~dmgt)qz-MBu z0SyfeNYTUkdWakTQQPqs+pg~*azI4G9dCKK#yc#34r?uFXlQ@{;x?^9jszkz){4;3 z(8^P9XEwaA&)pjjXRQwn4IPOfm(fH5d5K`s-Ad5V z(7@OZIEkq}wgh)7bH3Bi(1_nKh&#b`Q9HCljS90XHuj;Rp#g_6?gUq(G~37|L!J-% z;95qQ@ITg|p`ih9Q`lk(BDsb;{^KJJX3ylkEl{7@u74XuXE0`F8X6iJZ=Ym`(reoF zkLFIL1OBMo^^W4M|9-9KXf Date: Sun, 3 Mar 2019 12:19:18 +1100 Subject: [PATCH 47/60] Update README.md --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e392a059..7f1a02d2 100644 --- a/README.md +++ b/README.md @@ -30,17 +30,16 @@ You should be using [Pipenv](https://pipenv.readthedocs.io/en/latest/). Take a l # Project Information ##### Team Name -Knowledgeable Kois -`# TODO` +Knowledgeable Kois ## Description -`# TODO` +A clipboard manager, Copy your text and images with ease! ## Setup & Installation -`# TODO` +Clone this repo, in a terminal run `pipenv install` then `pipenv run start` Unit tests are written using the [pytest](https://docs.pytest.org/en/latest/) framework. @@ -48,7 +47,7 @@ Unit tests are written using the [pytest](https://docs.pytest.org/en/latest/) fr ## How do I use this thing? -`# TODO` +Simply copy text/images (images will only work with right-click>copy) ## Documentation @@ -57,4 +56,4 @@ Documentation is generated using [Sphinx](http://www.sphinx-doc.org/en/master/). cd docs sphinx-apidoc -f -o source/ ../project/ make html -``` \ No newline at end of file +``` From 49d3f694b82689cdf8d0b014a97e56dc4e4a3e68 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sun, 3 Mar 2019 10:53:36 +0800 Subject: [PATCH 48/60] Prevent the plugins from firing upon moving an item up or down --- Pipfile | 1 + Pipfile.lock | 31 +++-- project/ClipboardManager/ClipboardManager.py | 55 +++++---- project/ConfigManager/ConfigManager.py | 18 +-- project/ConfigManager/__init__.py | 2 +- project/PluginManager/PluginManager.py | 5 +- project/Plugins/ImageRotatePlugin.py | 36 ++++++ project/Plugins/QuotePlugin.py | 45 ++++++++ project/Plugins/SynonymPlugin.py | 61 +++++----- project/Plugins/Text.py | 73 ------------ project/Plugins/__init__.py | 4 +- project/Widgets/SettingsScreen.py | 14 ++- project/__main__.py | 115 ++++--------------- 13 files changed, 212 insertions(+), 248 deletions(-) create mode 100644 project/Plugins/ImageRotatePlugin.py create mode 100644 project/Plugins/QuotePlugin.py delete mode 100644 project/Plugins/Text.py diff --git a/Pipfile b/Pipfile index 6e400524..0974c0fc 100644 --- a/Pipfile +++ b/Pipfile @@ -14,6 +14,7 @@ flake8 = "*" lxml = "*" requests = "*" thesaurus = "*" +nltk = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index b29635aa..a5b940ce 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8a1138130ef769617102c5d0548e339fcd02b844bee110972030c816003e0938" + "sha256": "7d7e482cb66e7c577a46e6b0327839e38cd2bdfae4404b3a70573a686a6dcd7a" }, "pipfile-spec": 6, "requires": { @@ -99,6 +99,13 @@ ], "version": "==0.6.1" }, + "nltk": { + "hashes": [ + "sha256:286f6797204ffdb52525a1d21ec0a221ec68b8e3fa4f2d25f412ac8e63c70e8d" + ], + "index": "pypi", + "version": "==3.4" + }, "pycodestyle": { "hashes": [ "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", @@ -148,6 +155,20 @@ "index": "pypi", "version": "==2.21.0" }, + "singledispatch": { + "hashes": [ + "sha256:5b06af87df13818d14f08a028e42f566640aef80805c3b50c5056b086e3c2b9c", + "sha256:833b46966687b3de7f438c761ac475213e53b306740f1abfaa86e1d1aae56aa8" + ], + "version": "==3.4.0.3" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, "soupsieve": { "hashes": [ "sha256:afa56bf14907bb09403e5d15fbed6275caa4174d36b975226e3b67a3bb6e2c4b", @@ -214,14 +235,6 @@ ], "version": "==3.0.4" }, - "colorama": { - "hashes": [ - "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", - "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" - ], - "markers": "sys_platform == 'win32'", - "version": "==0.4.1" - }, "docutils": { "hashes": [ "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 292aded1..79971b9e 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -1,13 +1,14 @@ """Class encapsulating clipboard events""" -from PyQt5.Qt import QApplication, QClipboard # noqa: F401 +import logging + +from PyQt5.Qt import QApplication # noqa: F401 from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject +from project.ConfigManager import ConfigManager from project.PluginManager import PluginManager from project.Stack import Stack -import logging - # https://stackoverflow.com/questions/36522809/ # pyqt5-connection-doesnt-work-item-cannot-be-converted-to-pyqt5-qtcore-qobject @@ -25,46 +26,54 @@ def __init__(self): self._last_image = None QApplication.clipboard().dataChanged.connect(self._clipboard_changed) + self.clipboard_stack = Stack() self.stack_changed_signal.connect(self._stack_changed) @pyqtSlot(Stack) def _stack_changed(self): - """Slot to be called when the state of the stack changes (usually on add, move, delete, or moving items - around """ + """Slot to be called when the state of the stack changes + (usually on add, move, delete, or moving items around """ + + _config = ConfigManager.get_instance() # copy the top of the stack into the clipboard if the stack is not empty. if self.clipboard_stack.items_count(): - if isinstance(self.clipboard_stack.peek(), TextClipboardObject): - QApplication.clipboard().setText(self.clipboard_stack.peek().text) - if isinstance(self.clipboard_stack.peek(), ImageClipboardObject): - QApplication.clipboard().setPixmap(self.clipboard_stack.peek().pixmap) + if _config.auto_load_top: + item_to_load = self.clipboard_stack.peek() + else: + item_to_load = self.clipboard_stack.current_item + + if isinstance(item_to_load, TextClipboardObject): + self._last_text = item_to_load.text + self._logger.info("Current Stack Item: " + item_to_load.text) + QApplication.clipboard().setText(item_to_load.text) + if isinstance(item_to_load, ImageClipboardObject): + self._last_image = item_to_load.pixmap + QApplication.clipboard().setPixmap(item_to_load.pixmap) @pyqtSlot() def _clipboard_changed(self): - """Slot to be called when the state of the system's clipboard changes (mostly after copying)""" + """Slot to be called when the state of the system's clipboard changes + (mostly after copying)""" # current_text = Text.apply(QApplication.clipboard().text()) current_text = QApplication.clipboard().text() current_image = QApplication.clipboard().pixmap() - top_item = self.clipboard_stack.peek() + # top_item = self.clipboard_stack.peek() # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together - self._logger.info("Current Text:", QApplication.clipboard().text()) - self._logger.info("Current Image Info:", QApplication.clipboard().pixmap()) - - if current_text and (self._last_text is None or current_text != self._last_text) and \ - not (isinstance(top_item, TextClipboardObject) and top_item.text == current_text): + self._logger.info("Current Text:" + str(QApplication.clipboard().text())) + # self._logger.info("Current Image Info:", str(QApplication.clipboard().pixmap())) + # print(str(current_text) != self._last_text) + if current_text and (self._last_text is None or current_text != self._last_text): # self.clipboard_stack.push_item(TextClipboardObject(current_text)) self._plugin_manager.on_copy_text(current_text, self.clipboard_stack) - self.clipboard_changed_signal.emit(self.clipboard_stack) if not current_image.toImage().isNull() \ and (self._last_image is None - or current_image.toImage() != self._last_image.toImage()) \ - and not (isinstance(top_item, ImageClipboardObject) - and top_item.pixmap.toImage() == current_image.toImage()): + or current_image.toImage() != self._last_image.toImage()): self.clipboard_stack.push_item(ImageClipboardObject(current_image)) self.clipboard_changed_signal.emit(self.clipboard_stack) @@ -73,15 +82,15 @@ def _clipboard_changed(self): # DONE: use Qt signals properly # https://stackoverflow.com/questions/36434706/pyqt-proper-use-of-emit-and-pyqtsignal - # def bind_clipboard_state_callback(self, function): - # self._clipboard_state_callback = function + @pyqtSlot(int) def set_selected_object(self, idx): + """Highlights a particular row in the main window""" if not 0 <= idx < self.clipboard_stack.items_count(): raise Exception("Index is out of bounds") - """Highlights a particular row in the main window""" self.clipboard_stack.set_current_item(idx) + self._stack_changed() @pyqtSlot() def remove_clipboard_item(self): diff --git a/project/ConfigManager/ConfigManager.py b/project/ConfigManager/ConfigManager.py index 5547c5dd..f3f1f489 100644 --- a/project/ConfigManager/ConfigManager.py +++ b/project/ConfigManager/ConfigManager.py @@ -31,10 +31,10 @@ def _init_config(self): self._config.add_section('plugin_settings') self._config.set('settings', 'persist_clipboard', 'true') - self._config.set('settings', 'delete_after_paste', 'true') + # self._config.set('settings', 'delete_after_paste', 'true') self._config.set('settings', 'auto_load_top', 'true') - self._config.set('plugin_settings', 'chain_all_plugins', 'true') + self._config.set('plugin_settings', 'chain_all_plugins', 'false') self.save() @@ -46,13 +46,13 @@ def persist_clipboard(self): def persist_clipboard(self, value: bool): self._config['settings']["persist_clipboard"] = 'true' if value else 'false' - @property - def delete_after_paste(self): - return self._config.getboolean('settings', "delete_after_paste") - - @delete_after_paste.setter - def delete_after_paste(self, value: bool): - self._config['settings']["delete_after_paste"] = 'true' if value else 'false' + # @property + # def delete_after_paste(self): + # return self._config.getboolean('settings', "delete_after_paste") + # + # @delete_after_paste.setter + # def delete_after_paste(self, value: bool): + # self._config['settings']["delete_after_paste"] = 'true' if value else 'false' @property def auto_load_top(self): diff --git a/project/ConfigManager/__init__.py b/project/ConfigManager/__init__.py index e27cdb5d..33083209 100644 --- a/project/ConfigManager/__init__.py +++ b/project/ConfigManager/__init__.py @@ -1,2 +1,2 @@ -from .ConfigManager import ConfigManager +from .ConfigManager import ConfigManager # noqa: F401 diff --git a/project/PluginManager/PluginManager.py b/project/PluginManager/PluginManager.py index 4aaf7d9a..1279ae0f 100644 --- a/project/PluginManager/PluginManager.py +++ b/project/PluginManager/PluginManager.py @@ -3,8 +3,8 @@ from PyQt5.QtGui import QPixmap -# from project.ConfigManager import ConfigManager from project.Plugins import SpellingMistakesPlugin +from project.Plugins.QuotePlugin import QuotePlugin from project.Plugins.SynonymPlugin import SynonymPlugin from project.Stack import Stack @@ -22,9 +22,10 @@ def __init__(self): # within this folder. self._text_plugins.append(SpellingMistakesPlugin()) self._text_plugins.append(SynonymPlugin()) + self._text_plugins.append(QuotePlugin()) def on_copy_text(self, text_input: str, stack: Stack): - # _config = ConfigManager.get_instance() + """Function that is called by the ClipboardManager upon text copy""" _plugin = random.choice(list(filter(lambda plugin: plugin.__class__.name() not in self._disabled_plugin_names, diff --git a/project/Plugins/ImageRotatePlugin.py b/project/Plugins/ImageRotatePlugin.py new file mode 100644 index 00000000..0a76f1d4 --- /dev/null +++ b/project/Plugins/ImageRotatePlugin.py @@ -0,0 +1,36 @@ +# from PyQt5.QtGui import QPixmap +# +# from project import Stack +# from project.ClipboardManager.ClipboardObject import TextClipboardObject +# from project.Plugins import AbstractPlugin +# +# +# def _rotate_pixmap(pixmap: QPixmap): +# +# +# class ImageRotatePlugin(AbstractPlugin): +# +# @staticmethod +# def name() -> str: +# return "SpellingMistakes" +# +# @staticmethod +# def description() -> str: +# return "To help you sound more natural when writing." +# +# def onload(self): +# pass +# +# def unload(self): +# pass +# +# def on_copy(self, copied_input: any, stack: Stack): +# self._logger.debug(ImageRotatePlugin.name() + " called: " + copied_input) +# # push the actual copied text first, then push the quote later +# stack.push_item(TextClipboardObject(copied_input)) +# _quote = self._get_quote() +# if _quote is not None: +# stack.push_item(TextClipboardObject(_quote)) +# +# def on_paste(self, stack: Stack): +# return stack diff --git a/project/Plugins/QuotePlugin.py b/project/Plugins/QuotePlugin.py new file mode 100644 index 00000000..e61a4cc3 --- /dev/null +++ b/project/Plugins/QuotePlugin.py @@ -0,0 +1,45 @@ +import requests +from lxml import html + +from project import Stack +from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.Plugins import AbstractPlugin + + +class QuotePlugin(AbstractPlugin): + + def _get_quote(self): + """Gets a quote from funnysentences.com API""" + try: + page = requests.get('https://funnysentences.com/sentence-generator/') + tree = html.fromstring(page.content) + quote = tree.xpath('//*[@id="sentencegen"]/text()') + return ''.join(quote) + except requests.exceptions.ConnectionError: + self._logger.info('Fetching quote from API failed') + return None + + @staticmethod + def name() -> str: + return "SpellingMistakes" + + @staticmethod + def description() -> str: + return "To help you sound more natural when writing." + + def onload(self): + pass + + def unload(self): + pass + + def on_copy(self, copied_input: any, stack: Stack): + self._logger.debug(QuotePlugin.name() + " called: " + copied_input) + # push the actual copied text first, then push the quote later + stack.push_item(TextClipboardObject(copied_input)) + _quote = self._get_quote() + if _quote is not None: + stack.push_item(TextClipboardObject(_quote)) + + def on_paste(self, stack: Stack): + return stack diff --git a/project/Plugins/SynonymPlugin.py b/project/Plugins/SynonymPlugin.py index 5cad92ae..0ae144fd 100644 --- a/project/Plugins/SynonymPlugin.py +++ b/project/Plugins/SynonymPlugin.py @@ -8,37 +8,38 @@ from project.Plugins import AbstractPlugin -def _synonym(text): - skip_word = False - start = time.time() - text = text.split() - new_words = '' - for word in text: - if skip_word: - new_words = new_words + ' ' + word - skip_word = False - else: - start_ = time.time() - skip_word = True - try: - w = thesaurus.Word(word) - w.synonyms('all') - text = w.synonyms()[randint(0, len(w))] - final = ''.join(text) - new_words = new_words + ' ' + final - except thesaurus.exceptions.MisspellingError: - new_words = new_words + ' ' + word - except thesaurus.exceptions.WordNotFoundError: - new_words = new_words + ' ' + word - except TypeError: - new_words = new_words + ' ' + word - end_ = time.time() - end = time.time() - return new_words - - class SynonymPlugin(AbstractPlugin): + def _synonym(self, text): + skip_word = False + start = time.time() + text = text.split() + new_words = '' + for word in text: + if skip_word: + new_words = new_words + ' ' + word + skip_word = False + else: + # start_ = time.time() + skip_word = True + try: + w = thesaurus.Word(word) + w.synonyms('all') + _synonyms = w.synonyms() + text = _synonyms[randint(0, len(_synonyms) - 1)] + final = ''.join(text) + new_words = new_words + ' ' + final + except thesaurus.exceptions.MisspellingError: + new_words = new_words + ' ' + word + except thesaurus.exceptions.WordNotFoundError: + new_words = new_words + ' ' + word + except TypeError: + new_words = new_words + ' ' + word + # end_ = time.time() + end = time.time() + self._logger.info('processing time: ' + str(end - start)) + return new_words + def onload(self): pass @@ -46,7 +47,7 @@ def unload(self): pass def on_copy(self, copied_input: any, stack: Stack): - stack.push_item(TextClipboardObject(_synonym(copied_input))) + stack.push_item(TextClipboardObject(self._synonym(copied_input))) self._logger.info("Stack size" + str(stack.items_count())) def on_paste(self, stack: Stack): diff --git a/project/Plugins/Text.py b/project/Plugins/Text.py deleted file mode 100644 index 41b19a02..00000000 --- a/project/Plugins/Text.py +++ /dev/null @@ -1,73 +0,0 @@ -import string -from random import randint, choice -import requests -from lxml import html -import thesaurus -import time - - -def apply(text): - """Use this function, not any other one. It as a 50/50 chance of applying each""" - - text = synonym(text) - return text - - -def random_spelling_mistakes(text): - text = text.split() - new_words = '' - for word in text: - if len(word) == 1 or len(word) == 2: - final = ''.join(word) - new_words = new_words + ' ' + final - else: - spot = randint(0, len(word) - 1) - if spot == 0: - '''Give it two chances to not be 0, I think its better - if its mostly the middle letters that get removed''' - spot = randint(0, len(word) - 1) - if spot == 0: - pass - final = ''.join(word) - final = final[0:spot] + choice(string.ascii_letters) + final[spot:] - new_words = new_words + ' ' + final - return new_words - - -def quotify(text): - try: - page = requests.get('https://funnysentences.com/sentence-generator/') - tree = html.fromstring(page.content) - quote = tree.xpath('//*[@id="sentencegen"]/text()') - return ''.join(quote) - except requests.exceptions.ConnectionError: - return "lol you don't have internet" - - -def synonym(text): - skip_word = False - start = time.time() - text = text.split() - new_words = '' - for word in text: - if skip_word: - new_words = new_words + ' ' + word - skip_word = False - else: - start_ = time.time() - skip_word = True - try: - w = thesaurus.Word(word) - w.synonyms('all') - text = w.synonyms()[randint(0, len(w))] - final = ''.join(text) - new_words = new_words + ' ' + final - except thesaurus.exceptions.MisspellingError: - new_words = new_words + ' ' + word - except thesaurus.exceptions.WordNotFoundError: - new_words = new_words + ' ' + word - except TypeError: - new_words = new_words + ' ' + word - end_ = time.time() - end = time.time() - return new_words \ No newline at end of file diff --git a/project/Plugins/__init__.py b/project/Plugins/__init__.py index 142d7f7e..b1c1bd8e 100644 --- a/project/Plugins/__init__.py +++ b/project/Plugins/__init__.py @@ -1,2 +1,2 @@ -from .AbstractPlugin import AbstractPlugin -from .SpellingMistakesPlugin import SpellingMistakesPlugin +from .AbstractPlugin import AbstractPlugin # noqa: F401 +from .SpellingMistakesPlugin import SpellingMistakesPlugin # noqa: F401 diff --git a/project/Widgets/SettingsScreen.py b/project/Widgets/SettingsScreen.py index e469b5fd..74d7f393 100644 --- a/project/Widgets/SettingsScreen.py +++ b/project/Widgets/SettingsScreen.py @@ -42,21 +42,23 @@ def __init__(self, parent=None): # Checkboxes begin here self._persist_clipboard_checkbox = \ QCheckBox("Persist clipboard upon app quit", self) - self._delete_after_paste_checkbox = \ - QCheckBox("Delete selected clipboard item after paste", self) + + # Can't capture key events outside app easily in a cross-platform way/security risk + # self._delete_after_paste_checkbox = \ + # QCheckBox("Delete selected clipboard item after paste", self) self._auto_load_top_checkbox = \ - QCheckBox("Automatically load top item into clipboard", self) + QCheckBox("Always load top item into clipboard", self) self._persist_clipboard_checkbox.setChecked(_config_mgr.persist_clipboard) - self._delete_after_paste_checkbox.setChecked(_config_mgr.delete_after_paste) + # self._delete_after_paste_checkbox.setChecked(_config_mgr.delete_after_paste) self._auto_load_top_checkbox.setChecked(_config_mgr.auto_load_top) self._persist_clipboard_checkbox.toggled.connect(self._persist_clipboard_checkbox_clicked) - self._delete_after_paste_checkbox.toggled.connect(self._delete_after_paste_checkbox_clicked) + # self._delete_after_paste_checkbox.toggled.connect(self._delete_after_paste_checkbox_clicked) self._auto_load_top_checkbox.toggled.connect(self._auto_load_top_checkbox_clicked) self._central_widget_layout.addWidget(self._persist_clipboard_checkbox) - self._central_widget_layout.addWidget(self._delete_after_paste_checkbox) + # self._central_widget_layout.addWidget(self._delete_after_paste_checkbox) self._central_widget_layout.addWidget(self._auto_load_top_checkbox) # Bottom save button diff --git a/project/__main__.py b/project/__main__.py index 3409b241..960d8c0f 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -3,6 +3,7 @@ from PyQt5 import QtWidgets from PyQt5.QtCore import pyqtSlot, pyqtSignal +from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QMainWindow, QApplication, \ QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem @@ -76,6 +77,7 @@ class MainWindow(QMainWindow): def __init__(self, clipboard_manager: ClipboardManager): """ Initialises new MainWindow class """ super().__init__() + self._logger = logging.getLogger(self.__class__.__qualname__) self._central_widget_layout = QVBoxLayout() self._central_widget = QtWidgets.QWidget(self) @@ -116,6 +118,9 @@ def _init_ui(self): def _show_settings_window(self): self._settings_screen.show() + def _show_plugins_window(self): + pass + @pyqtSlot(Stack) def _render_clipboard_stack(self, clipboard_stack: Stack): self._main_list_widget.clear() @@ -143,10 +148,6 @@ def _render_clipboard_stack(self, clipboard_stack: Stack): .current_item_idx - 1) def setupUi(self): - # MainWindow.setObjectName("MainWindow") - # self.setFixedSize(640, 480) - - # No idea what all these widgets are. Please clarify and comment around BWAC? self._central_widget.setObjectName(MainWindow.CENTRAL_WIDGET_NAME) @@ -161,112 +162,41 @@ def setupUi(self): self._main_list_widget.currentRowChanged.connect(self._set_current_row) self._central_widget_layout.addWidget(self._main_list_widget) - # self._central_widget_layout.addStretch(1) - - # self.Add = QtWidgets.QPushButton(self._central_widget) - # self.Add.setGeometry(QtCore.QRect(0, 3, 51, 20)) - # self.Add.clicked.connect(self.addObject) - # self.Add.setObjectName("Add") - - # self.Remove = QtWidgets.QPushButton(self._central_widget) - # self.Remove.setGeometry(QtCore.QRect(50, 3, 51, 20)) - # self.Remove.clicked.connect(self.removeObject) - # self.Remove.setObjectName("Remove") - # - # self.Edit = QtWidgets.QPushButton(self._central_widget) - # self.Edit.setGeometry(QtCore.QRect(100, 3, 51, 20)) - # self.Edit.setObjectName("Edit") - - # self.treeWidget = QtWidgets.QTreeWidget(self._central_widget) - # self.treeWidget.setGeometry(QtCore.QRect(0, 30, 631, 411)) - # self.treeWidget.setFrameShape(QtWidgets.QFrame.StyledPanel) - # self.treeWidget.setObjectName("treeWidget") - - # menu bar has no members? + self.menubar = self.menuBar() - # self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21)) - # self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") - self.menuFile.setTitle("File") - - # self.menuPlugins = QtWidgets.QMenu(self.menubar) - # self.menuPlugins.setObjectName("menuPlugins") - # self.menuItem = QtWidgets.QMenu(self.menubar) - # self.menuItem.setObjectName("menuItem") - # self.setMenuBar(self.menubar) - # self.statusbar = QtWidgets.QStatusBar(self) - # self.statusbar.setObjectName("statusbar") - # self.setStatusBar(self.statusbar) - # self.actionAdd = QtWidgets.QAction(self) - # self.actionAdd.setObjectName("actionAdd") - # self.actionDelete = QtWidgets.QAction(self) - # self.actionDelete.setObjectName("actionDelete") - # self.action_todo = QtWidgets.QAction(self) - # self.action_todo.setObjectName("action_todo") + self.menuFile.setTitle("Settings") + self.actionSettings = QtWidgets.QAction(self) self.actionSettings.setObjectName("actionSettings") - self.actionSettings.setText("Settings") + self.actionSettings.setText("General") self.actionSettings.triggered.connect(self._show_settings_window) - # self.actionAdd_2 = QtWidgets.QAction(self) - # self.actionAdd_2.setObjectName("actionAdd_2") - # self.actionRemove = QtWidgets.QAction(self) - # self.actionRemove.setObjectName("actionRemove") + self.menuFile.addAction(self.actionSettings) - # self.menuPlugins.addAction(self.action_todo) - # self.menuItem.addAction(self.actionAdd_2) - # self.menuItem.addAction(self.actionRemove) + + self.pluginSettings = QtWidgets.QAction(self) + self.pluginSettings.setObjectName("actionPlugins") + self.pluginSettings.setText('Plugins') + self.pluginSettings.triggered.connect(self._show_plugins_window) + + self.menuFile.addAction(self.pluginSettings) + self.menubar.addAction(self.menuFile.menuAction()) - # self.menubar.addAction(self.menuPlugins.menuAction()) - # self.menubar.addAction(self.menuItem.menuAction()) self._central_widget.setLayout(self._central_widget_layout) self.setCentralWidget(self._central_widget) - self.retranslateUi() - # https://stackoverflow.com/questions/2462401/problem-in-understanding-connectslotsbyname-in-pyqt # Better to use new-style decorator @QtCore.pyqtSlot() # QtCore.QMetaObject.connectSlotsByName(self) self.show() - def retranslateUi(self): - """Generated by Qt designer for localization purposes. Currently unused.""" - - # _translate = QtCore.QCoreApplication.translate - # MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - # self._add_btn.setText(_translate("MainWindow", "Add")) - # self._remove_btn.setText(_translate("MainWindow", "Remove")) - # self._edit_btn.setText(_translate("MainWindow", "Edit")) - # self.treeWidget.headerItem() \ - # .setText(0, _translate("MainWindow", "Items:")) - # __sortingEnabled = self.treeWidget.isSortingEnabled() - # self.treeWidget.setSortingEnabled(False) - # self.menuFile.setTitle(_translate("MainWindow", "File")) - # self.menuPlugins.setTitle(_translate("MainWindow", "Plugins")) - # self.menuItem.setTitle(_translate("MainWindow", "Items")) - # self.actionAdd.setText(_translate("MainWindow", "Add")) - # self.actionDelete.setText(_translate("MainWindow", "Delete")) - # self.action_todo.setText(_translate("MainWindow", "Install #todo")) - # self.actionSettings.setText(_translate("MainWindow", "Settings #todo")) - # self.actionAdd_2.setText(_translate("MainWindow", "Add #todo")) - # self.actionRemove.setText(_translate("MainWindow", "Remove #todo")) - - # def _add_object(self): - # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - # self.num_of_objects + 1 - # def removeObject(self): - # # TODO make it remove instead of add - # - # if self.items == []: - # return - # - # exec('item_' + str(self.num_of_objects) + ' = QtWidgets.QTreeWidgetItem(self.treeWidget)') - # exec('item_' + str(self.num_of_objects) + '.setText(0, "Untitled")') - # - # self.num_of_objects + 1 + def keyPressEvent(self, event): + self._logger.info("Key press detected") + if event.matches(QKeySequence.Paste): + self._logger.info("Detected paste") def closeEvent(self, event): """ Fires on window close""" @@ -274,7 +204,6 @@ def closeEvent(self, event): if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) logger.info("App Started") From 5018213fcbdda97a72c3fe75292b2d02ef9b8914 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sun, 3 Mar 2019 17:08:33 +1100 Subject: [PATCH 49/60] icon --- project/__main__.py | 3 +++ project/icon.ico | Bin 0 -> 27758 bytes 2 files changed, 3 insertions(+) create mode 100644 project/icon.ico diff --git a/project/__main__.py b/project/__main__.py index 960d8c0f..33ad6d8a 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -2,6 +2,7 @@ import sys from PyQt5 import QtWidgets +from PyQt5.QtGui import QIcon from PyQt5.QtCore import pyqtSlot, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QMainWindow, QApplication, \ @@ -209,6 +210,8 @@ def closeEvent(self, event): logger.info("App Started") app = QApplication(sys.argv) + app.setWindowIcon(QIcon("./project/icon.ico")) + clipboard_mgr = ClipboardManager.ClipboardManager() main_window = MainWindow(clipboard_mgr) diff --git a/project/icon.ico b/project/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7f4327b998e18e80e57b0017d32c10580c5e1ac8 GIT binary patch literal 27758 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 F`+t~XQda-~ literal 0 HcmV?d00001 From 056591b4febfa4a5a340e61cdb3553d455e17b8c Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sun, 3 Mar 2019 16:03:28 +0800 Subject: [PATCH 50/60] Rename some of the plugins and prevent the _stack_changed event from recursively calling itself --- project/ClipboardManager/ClipboardManager.py | 30 +++++++++++--------- project/PluginManager/PluginManager.py | 13 +++++++-- project/Plugins/ImageRotatePlugin.py | 19 +++++++++++-- project/Plugins/QuotePlugin.py | 4 +-- project/Plugins/SynonymPlugin.py | 8 ++++++ 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 97fde751..3f91431b 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -25,6 +25,8 @@ def __init__(self): self._last_text = None self._last_image = None + self._clipboard_mutex = False + QApplication.clipboard().dataChanged.connect(self._clipboard_changed) self.clipboard_stack = Stack() @@ -34,7 +36,7 @@ def __init__(self): def _stack_changed(self): """Slot to be called when the state of the stack changes (usually on add, move, delete, or moving items around """ - + self._clipboard_mutex = True _config = ConfigManager.get_instance() # copy the top of the stack into the clipboard if the stack is not empty. @@ -48,34 +50,35 @@ def _stack_changed(self): self._last_text = item_to_load.text self._logger.info("Current Stack Item: " + item_to_load.text) QApplication.clipboard().setText(item_to_load.text) - if isinstance(item_to_load, ImageClipboardObject): + elif isinstance(item_to_load, ImageClipboardObject): self._last_image = item_to_load.pixmap - QApplication.clipboard().setPixmap(item_to_load.pixmap) + self._logger.info("Stack Changed Item: " + str(self._last_image)) + QApplication.clipboard().setPixmap(self._last_image) @pyqtSlot() def _clipboard_changed(self): """Slot to be called when the state of the system's clipboard changes (mostly after copying)""" - # current_text = Text.apply(QApplication.clipboard().text()) + self._logger.info("Clipboard Changed called") + if self._clipboard_mutex: + self._clipboard_mutex = False + return + current_text = QApplication.clipboard().text() current_image = QApplication.clipboard().pixmap() - # top_item = self.clipboard_stack.peek() - # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together self._logger.info("Current Text:" + str(QApplication.clipboard().text())) - # self._logger.info("Current Image Info:", str(QApplication.clipboard().pixmap())) + self._logger.info("Current Image Info:", str(QApplication.clipboard().pixmap())) - # print(str(current_text) != self._last_text) if current_text and (self._last_text is None or current_text != self._last_text): - # self.clipboard_stack.push_item(TextClipboardObject(current_text)) self._plugin_manager.on_copy_text(current_text, self.clipboard_stack) self.clipboard_changed_signal.emit(self.clipboard_stack) - if not current_image.toImage().isNull() \ - and (self._last_image is None - or current_image.toImage() != self._last_image.toImage()): - self.clipboard_stack.push_item(ImageClipboardObject(current_image)) + # If the image is not blank + if not current_image.toImage().isNull() and (self._last_image is None + or current_image.toImage() != self._last_image.toImage()): + self._plugin_manager.on_copy_image(current_image, self.clipboard_stack) self.clipboard_changed_signal.emit(self.clipboard_stack) self._last_image = current_image @@ -87,6 +90,7 @@ def _clipboard_changed(self): @pyqtSlot(int) def set_selected_object(self, idx): """Highlights a particular row in the main window""" + self._logger.info("set_selected_object called " + str(idx)) if not 0 <= idx < self.clipboard_stack.items_count(): raise Exception("Index is out of bounds") diff --git a/project/PluginManager/PluginManager.py b/project/PluginManager/PluginManager.py index 1279ae0f..70f37bbe 100644 --- a/project/PluginManager/PluginManager.py +++ b/project/PluginManager/PluginManager.py @@ -4,6 +4,7 @@ from PyQt5.QtGui import QPixmap from project.Plugins import SpellingMistakesPlugin +from project.Plugins.ImageRotatePlugin import ImageRotatePlugin from project.Plugins.QuotePlugin import QuotePlugin from project.Plugins.SynonymPlugin import SynonymPlugin from project.Stack import Stack @@ -24,6 +25,8 @@ def __init__(self): self._text_plugins.append(SynonymPlugin()) self._text_plugins.append(QuotePlugin()) + self._image_plugins.append(ImageRotatePlugin()) + def on_copy_text(self, text_input: str, stack: Stack): """Function that is called by the ClipboardManager upon text copy""" @@ -35,5 +38,11 @@ def on_copy_text(self, text_input: str, stack: Stack): self._logger.info("Randomly chose plugin " + _plugin.__class__.__qualname__) _plugin.on_copy(text_input, stack) - def on_paste_image(self, image_input: QPixmap, stack: Stack): - pass + def on_copy_image(self, image_input: QPixmap, stack: Stack): + """Function that is called by the ClipboardManager upon image copy""" + _plugin = random.choice(list(filter(lambda plugin: plugin.__class__.name() + not in self._disabled_plugin_names, + self._image_plugins))) + + _plugin.on_copy(image_input, stack) + diff --git a/project/Plugins/ImageRotatePlugin.py b/project/Plugins/ImageRotatePlugin.py index 60bc2572..d596382d 100644 --- a/project/Plugins/ImageRotatePlugin.py +++ b/project/Plugins/ImageRotatePlugin.py @@ -1,11 +1,26 @@ # from PyQt5.QtGui import QPixmap +import random + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QPixmap, QTransform from project import Stack # from project.ClipboardManager.ClipboardObject import TextClipboardObject +from project.ClipboardManager.ClipboardObject import ImageClipboardObject from project.Plugins import AbstractPlugin -# def _rotate_pixmap(pixmap: QPixmap): +def _rotate_pixmap(pixmap: QPixmap): + """Helper function to rotate image in random multiples of 90 deg""" + + _transforms = [QTransform().rotate(0), + QTransform().rotate(90), + QTransform().rotate(180), + QTransform().rotate(270)] + + # pick a random transform + _transform = random.choice(_transforms) + return pixmap.transformed(_transform, Qt.SmoothTransformation) class ImageRotatePlugin(AbstractPlugin): @@ -25,7 +40,7 @@ def unload(self): pass def on_copy(self, copied_input: any, stack: Stack): - pass + stack.push_item(ImageClipboardObject(_rotate_pixmap(copied_input))) def on_paste(self, stack: Stack): return stack diff --git a/project/Plugins/QuotePlugin.py b/project/Plugins/QuotePlugin.py index e61a4cc3..577267e2 100644 --- a/project/Plugins/QuotePlugin.py +++ b/project/Plugins/QuotePlugin.py @@ -21,11 +21,11 @@ def _get_quote(self): @staticmethod def name() -> str: - return "SpellingMistakes" + return "Quotes" @staticmethod def description() -> str: - return "To help you sound more natural when writing." + return "Adds a random quote to help you sound smarter." def onload(self): pass diff --git a/project/Plugins/SynonymPlugin.py b/project/Plugins/SynonymPlugin.py index 0ae144fd..1618ce1e 100644 --- a/project/Plugins/SynonymPlugin.py +++ b/project/Plugins/SynonymPlugin.py @@ -40,6 +40,14 @@ def _synonym(self, text): self._logger.info('processing time: ' + str(end - start)) return new_words + @staticmethod + def name() -> str: + return "Synonyms" + + @staticmethod + def description() -> str: + return "Picks up the thesaurus for you so you don't have to." + def onload(self): pass From 72c25d0a04c2115ad1bd1a23c05f6116029af2ed Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sun, 3 Mar 2019 16:08:00 +0800 Subject: [PATCH 51/60] Fix linting and logging issue --- project/ClipboardManager/ClipboardManager.py | 7 ++++--- project/PluginManager/PluginManager.py | 13 ++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 3f91431b..ad6aae35 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -69,15 +69,16 @@ def _clipboard_changed(self): # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together self._logger.info("Current Text:" + str(QApplication.clipboard().text())) - self._logger.info("Current Image Info:", str(QApplication.clipboard().pixmap())) + self._logger.info("Current Image Info:" + str(QApplication.clipboard().pixmap())) if current_text and (self._last_text is None or current_text != self._last_text): self._plugin_manager.on_copy_text(current_text, self.clipboard_stack) self.clipboard_changed_signal.emit(self.clipboard_stack) # If the image is not blank - if not current_image.toImage().isNull() and (self._last_image is None - or current_image.toImage() != self._last_image.toImage()): + if not current_image.toImage().isNull() \ + and (self._last_image is None + or current_image.toImage() != self._last_image.toImage()): self._plugin_manager.on_copy_image(current_image, self.clipboard_stack) self.clipboard_changed_signal.emit(self.clipboard_stack) diff --git a/project/PluginManager/PluginManager.py b/project/PluginManager/PluginManager.py index 70f37bbe..4fe23b85 100644 --- a/project/PluginManager/PluginManager.py +++ b/project/PluginManager/PluginManager.py @@ -30,9 +30,9 @@ def __init__(self): def on_copy_text(self, text_input: str, stack: Stack): """Function that is called by the ClipboardManager upon text copy""" - _plugin = random.choice(list(filter(lambda plugin: plugin.__class__.name() - not in self._disabled_plugin_names, - self._text_plugins))) + _plugin = random.choice( + list(filter(lambda plugin: plugin.__class__.name() not in self._disabled_plugin_names, + self._text_plugins))) self._logger.info("Passing " + text_input + " to plugins!") self._logger.info("Randomly chose plugin " + _plugin.__class__.__qualname__) @@ -40,9 +40,8 @@ def on_copy_text(self, text_input: str, stack: Stack): def on_copy_image(self, image_input: QPixmap, stack: Stack): """Function that is called by the ClipboardManager upon image copy""" - _plugin = random.choice(list(filter(lambda plugin: plugin.__class__.name() - not in self._disabled_plugin_names, - self._image_plugins))) + _plugin = random.choice( + list(filter(lambda plugin: plugin.__class__.name() not in self._disabled_plugin_names, + self._image_plugins))) _plugin.on_copy(image_input, stack) - From f897e36b9648d7a31b4d89348993dfca28f71c22 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sun, 3 Mar 2019 19:45:39 +1100 Subject: [PATCH 52/60] TextEditor works --- project/TextEditor/Editor.py | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 project/TextEditor/Editor.py diff --git a/project/TextEditor/Editor.py b/project/TextEditor/Editor.py new file mode 100644 index 00000000..54a7080b --- /dev/null +++ b/project/TextEditor/Editor.py @@ -0,0 +1,45 @@ +from PyQt5 import QtCore, QtWidgets + + +class Editor(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(463, 258) + Dialog.setMinimumSize(QtCore.QSize(463, 258)) + Dialog.setMaximumSize(QtCore.QSize(463, 258)) + self.save_button = QtWidgets.QPushButton(Dialog) + self.save_button.setGeometry(QtCore.QRect(150, 230, 75, 21)) + self.save_button.setObjectName("pushButton") + self.save_button.clicked.connect(self.save) + self.cancel_button = QtWidgets.QPushButton(Dialog) + self.cancel_button.setGeometry(QtCore.QRect(230, 230, 75, 21)) + self.cancel_button.setObjectName("pushButton_2") + self.cancel_button.clicked.connect(self.cancel) + self.textEdit = QtWidgets.QTextEdit(Dialog) + self.textEdit.setGeometry(QtCore.QRect(0, 0, 461, 221)) + self.textEdit.setObjectName("textEdit") + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Dialog")) + self.save_button.setText(_translate("Dialog", "Save")) + self.cancel_button.setText(_translate("Dialog", "Cancel")) + + def save(self): + print(self.textEdit.toPlainText()) + + def cancel(self): + sys.exit(app.exec_()) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + Dialog = QtWidgets.QDialog() + ui = Editor() + ui.setupUi(Dialog) + Dialog.show() + sys.exit(app.exec_()) From 8927e77d4c4bd528d2d2f74ce89b629635d649bb Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Sun, 3 Mar 2019 20:04:02 +1100 Subject: [PATCH 53/60] text editor --- Pipfile.lock | 8 ++++++++ project/TextEditor/Editor.py | 9 +++++++++ project/__main__.py | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/Pipfile.lock b/Pipfile.lock index 7a81b829..b29635aa 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -214,6 +214,14 @@ ], "version": "==3.0.4" }, + "colorama": { + "hashes": [ + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.1" + }, "docutils": { "hashes": [ "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", diff --git a/project/TextEditor/Editor.py b/project/TextEditor/Editor.py index 54a7080b..2c47402d 100644 --- a/project/TextEditor/Editor.py +++ b/project/TextEditor/Editor.py @@ -34,6 +34,15 @@ def save(self): def cancel(self): sys.exit(app.exec_()) + def start(): + import sys + app = QtWidgets.QApplication(sys.argv) + Dialog = QtWidgets.QDialog() + ui = Editor() + ui.setupUi(Dialog) + Dialog.show() + sys.exit(app.exec_()) + if __name__ == "__main__": import sys diff --git a/project/__main__.py b/project/__main__.py index 33ad6d8a..e5f19714 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -15,6 +15,8 @@ from project.Widgets import MainListWidget, TextListWidgetItem from project.Widgets.MainListWidget import ImageListWidgetItem from project.Widgets.SettingsScreen import SettingsScreen +from project.TextEditor import Editor + from .utils import CONSTANTS @@ -37,6 +39,7 @@ def __init__(self): self._edit_btn = QtWidgets.QPushButton("Edit") # self._edit_btn.setGeometry(QtCore.QRect(100, 3, 51, 20)) self._edit_btn.setObjectName(MainWindow.EDIT_BUTTON_NAME) + self._edit_btn.clicked.connect(self._start_editor) self._move_up_btn = QtWidgets.QPushButton("Move Up") self._move_up_btn.setObjectName(MainWindow.MOVE_UP_BUTTON_NAME) @@ -52,6 +55,9 @@ def __init__(self): _horizontal_layout.addStretch(1) + def _start_editor(text): + Editor.Editor.start() + class MainWindow(QMainWindow): add_btn_signal = pyqtSignal() From 341a9c9c1a432a1edaf02a33874f35eb4662c480 Mon Sep 17 00:00:00 2001 From: kaleidagraph <26967284+kaleidagraph@users.noreply.github.com> Date: Sun, 3 Mar 2019 12:08:46 +0000 Subject: [PATCH 54/60] New Icon + Saving works, saves photos, filepicker --- project/ClipboardManager/ClipboardObject.py | 9 +++ project/Plugins/Save.py | 24 ++++++-- project/Plugins/Systray.py | 8 +-- project/__main__.py | 65 +++++++++++++++----- project/icon.ico | Bin 27758 -> 18686 bytes project/tempicon.ico | Bin 27758 -> 0 bytes project/utils.py | 8 +-- 7 files changed, 83 insertions(+), 31 deletions(-) delete mode 100644 project/tempicon.ico diff --git a/project/ClipboardManager/ClipboardObject.py b/project/ClipboardManager/ClipboardObject.py index a1c88e7a..198f6a19 100644 --- a/project/ClipboardManager/ClipboardObject.py +++ b/project/ClipboardManager/ClipboardObject.py @@ -32,6 +32,12 @@ def __init__(self, text): def set_text(self, text: str): self.text = text + def __str__(self): + return self.text + + def __repr__(self): + return self.__str__() + class ImageClipboardObject(ClipboardObject): @@ -47,3 +53,6 @@ def __ne__(self, other): def __init__(self, pixmap: QPixmap): super().__init__() self.pixmap = pixmap + + def getImage(self): + return self.pixmap diff --git a/project/Plugins/Save.py b/project/Plugins/Save.py index 50988f3d..5241f425 100644 --- a/project/Plugins/Save.py +++ b/project/Plugins/Save.py @@ -1,10 +1,24 @@ """ Contains logic for loading and saving states """ import json +import os from project.utils import CONSTANTS +from project.ClipboardManager.ClipboardObject import ImageClipboardObject, TextClipboardObject +def saveState(location, clipboard): + state = [] + image = 1 + for item in clipboard: + print(item, type(item)) + if type(item) == TextClipboardObject: + state.append({"type": "string", "content": str(item) }) + elif type(item) == ImageClipboardObject: + imagelocation = "{0}/images/image{1}.png".format(os.path.dirname(location), image) + state.append({"type": "image", "location": imagelocation}) + item.getImage().save(imagelocation, 'PNG') + image += 1 + + with open(location, 'w') as outfile: + json.dump(state, outfile) -def getQuotes(): - # due to some more complex characters in 'app.json' the encoding must be set utf-8 - with open(CONSTANTS['APP_DATA'], encoding='utf-8') as f: - data = json.load(f) - return data['quotes'] +def loadState(state): + pass \ No newline at end of file diff --git a/project/Plugins/Systray.py b/project/Plugins/Systray.py index b3a1a0a7..540226f3 100644 --- a/project/Plugins/Systray.py +++ b/project/Plugins/Systray.py @@ -1,17 +1,17 @@ import sys # noqa: F401 from PyQt5 import QtWidgets, QtGui +from project.utils import CONSTANTS class SystemTrayIcon(QtWidgets.QSystemTrayIcon): """ Class which contains logic for a system tray interactive icon""" - # temp icon & name - icon = "project\\tempicon.ico" - name = "Example tray icon" + icon = CONSTANTS["ICON_LOCATION"] + name = CONSTANTS["NAME"] def __init__(self, parent=None): QtWidgets.QSystemTrayIcon.__init__(self, QtGui.QIcon(self.icon), parent) menu = QtWidgets.QMenu(parent) - exitAction = menu.addAction("Temp Option One") # noqa: F841 + showAction = menu.addAction("Show Clipboard") # noqa: F841 self.setContextMenu(menu) self.setToolTip(self.name) diff --git a/project/__main__.py b/project/__main__.py index e5f19714..c55e97ea 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,12 +1,13 @@ import logging import sys +import os from PyQt5 import QtWidgets from PyQt5.QtGui import QIcon from PyQt5.QtCore import pyqtSlot, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QMainWindow, QApplication, \ - QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem + QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem, QFileDialog from project import ClipboardManager from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject @@ -17,7 +18,8 @@ from project.Widgets.SettingsScreen import SettingsScreen from project.TextEditor import Editor -from .utils import CONSTANTS +from project.utils import CONSTANTS +from project.Plugins import Save class ActionBar(QWidget): @@ -77,10 +79,6 @@ class MainWindow(QMainWindow): MOVE_UP_BUTTON_NAME = 'move_up_btn' MOVE_DOWN_BUTTON_NAME = 'move_down_btn' - # please label what these are / relate to: - num_of_objects = 0 - items = [] - def __init__(self, clipboard_manager: ClipboardManager): """ Initialises new MainWindow class """ super().__init__() @@ -170,26 +168,54 @@ def setupUi(self): self._central_widget_layout.addWidget(self._main_list_widget) + # Menu Bar self.menubar = self.menuBar() - self.menuFile = QtWidgets.QMenu(self.menubar) - self.menuFile.setObjectName("menuFile") - self.menuFile.setTitle("Settings") + # File Menu Bar + self.fileMenu = QtWidgets.QMenu(self.menubar) + self.fileMenu.setObjectName("fileMenu") + self.fileMenu.setTitle("File") + + # Save: + self.saveOption = QtWidgets.QAction(self) + self.saveOption.setObjectName("saveOption") + self.saveOption.setText("Save current clipboard") + self.saveOption.triggered.connect(self._save) + + self.fileMenu.addAction(self.saveOption) + + # Load: + self.loadOption = QtWidgets.QAction(self) + self.loadOption.setObjectName("loadOption") + self.loadOption.setText("Load existing clipboard") + self.loadOption.triggered.connect(self._load) + + self.fileMenu.addAction(self.loadOption) + + self.menubar.addAction(self.fileMenu.menuAction()) + + # Settings Menu Bar + self.settingsMenu = QtWidgets.QMenu(self.menubar) + self.settingsMenu.setObjectName("settingsMenu") + self.settingsMenu.setTitle("Settings") + + # General Settings self.actionSettings = QtWidgets.QAction(self) self.actionSettings.setObjectName("actionSettings") self.actionSettings.setText("General") self.actionSettings.triggered.connect(self._show_settings_window) - self.menuFile.addAction(self.actionSettings) + self.settingsMenu.addAction(self.actionSettings) + # Plugin Settings self.pluginSettings = QtWidgets.QAction(self) self.pluginSettings.setObjectName("actionPlugins") self.pluginSettings.setText('Plugins') self.pluginSettings.triggered.connect(self._show_plugins_window) - self.menuFile.addAction(self.pluginSettings) + self.settingsMenu.addAction(self.pluginSettings) - self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.settingsMenu.menuAction()) self._central_widget.setLayout(self._central_widget_layout) self.setCentralWidget(self._central_widget) @@ -205,9 +231,16 @@ def keyPressEvent(self, event): if event.matches(QKeySequence.Paste): self._logger.info("Detected paste") - def closeEvent(self, event): - """ Fires on window close""" - pass + def _load(self): + """ Function to load stack""" + filename, _ = QFileDialog.getOpenFileName(self, 'Load Clipboard State', os.environ["HOMEPATH"], '*.json') + print(filename) + # Save.saveState() self._clipboard_manager.clipboard_stack.items()) + + def _save(self): + """ Function to save stack""" + filename, _ = QFileDialog.getSaveFileName(self, 'Save Clipboard State', os.environ["HOMEPATH"], '*.json') + Save.saveState(filename, self._clipboard_manager.clipboard_stack.items()) if __name__ == '__main__': @@ -216,7 +249,7 @@ def closeEvent(self, event): logger.info("App Started") app = QApplication(sys.argv) - app.setWindowIcon(QIcon("./project/icon.ico")) + app.setWindowIcon(QIcon(CONSTANTS["ICON_LOCATION"])) clipboard_mgr = ClipboardManager.ClipboardManager() main_window = MainWindow(clipboard_mgr) diff --git a/project/icon.ico b/project/icon.ico index 7f4327b998e18e80e57b0017d32c10580c5e1ac8..eb0b77d788f760272ab5b5546aab50b41888c1a1 100644 GIT binary patch literal 18686 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 literal 27758 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 F`+t~XQda-~ diff --git a/project/tempicon.ico b/project/tempicon.ico deleted file mode 100644 index 7f4327b998e18e80e57b0017d32c10580c5e1ac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27758 zcmeHQ1$b1~)|~{a3w4FMyS>`$P@yf=SE2SHeJypFI#3EBxFtw&NC*T78h3XkAs&)I zLI??#5S+HO`(NwK+?hMWOeVbY{e6;r-{PFBv-dvx_+A%-!NbtSaOa%{q`eJ6*BK1= z8w`eX&M_Z<)YV|vf^$Zr`S`}i4Tioq8w@w%9z0?g4DdPicdfzD^K>)JCkzG=`JX{f zPL5&GqD3B4rcCh|GiHp(`|rQ+`OZ7o_X#WXPj}~>8GE5!D*+R zcG0P)o_fhCr<`&ra2arg1y>?<2424$;JugP*^BuOz6^Uptn zzuBu-uO2tubW^v-9(%0I_uqf-QD0wwoUfFXl^F&O9O!xX-FJ7TtQTBx!RZz`ds<|? zn7`MfM~^GJckg}`a2;@Cw{G2T?%K8MZNQzt-N1do1Hgm8!@wiJqrl%Sd7k4n-otzO z44=J?@4`E80ItRFT!r7G?w46~JD)bg-Z`BrL4ACEeN|blUcK6b<$B$9*LCOh zo;`b>Njt#C=ks~m3Ah69?Tztw_uIF#yw|e0>FK5|8h6`EVXXB4PaM@*-oqEeHw{)ZL>3xlQupAzFO?DrZ?ZgcR|)mo%qt3(4`Oj z;Fa5Nzr7pl&QCx6LtFONDeCw^ZJfD2>$u18+{BYMh?zp2H^<;To zdF7Qo=zEu3a>=R0#TQ>poW}AbEXV5FrI%iM>J?X9aZ2yry?b1H?X}%+zWL^E_uO+& zSEJF`rC+~(T?Pyo;K{ZjKR@39eT?wy7F_$|)?06#de>cdb#G7B%KRM9%&5=-1qspF zC25J(rD;hvq$7Vakb(EKgEC&j?=1A4QVp5+j~qEt{Qdpqi!Z+Ted4GQYqDb^E_J0t zT14>uc=qtFsuF1|-5}L@nSTj_m-)$^cib-De*3MgTD3|tGBRZ0>{(Kol`6S$kt!$#Y%pZ!7f+wXGVsa<%i$cWOk5&GP#n$a{dTX z8(NTW2W_|p_?TwWw-7hTGq6tc$DurW`{GE-d0-lBe!zuO+{%0!dFNxC5? zOEAuo2OoS;h7B7g-+lL;#6*P4LFx>d5AWM+MJ@b)JKDsJDe*4lPh7v+R9}=UB^i+4 zjf^g@)2{76vuR#thTM1Gy-I%cjq>%^UrTy&qE%kK?95aCZSal4q*#~o$FE&!+Oi>A ziqn%$OnwJ>X}|V#C@U(IhaY+f^4}*IgUh$yd?ST{kuK$r4hl3?=VnM@N&@6({j$mE%%0n~ z)~ojU&Hnvm0A%@T*ie}^X`;-YF|R8&u_o+hP?IW8xk0>M2a`$%gZmlsO*k8 zhO&EoZH=9rO6L8L+YbAr8uD*0$d;U#aF_B&tXOKQMB7u49N%vF(?5#x^W^<^-xbs6 zpUKL=Ws;wjDYdX;-KI*Zuh}G9sw$+qtVFU>lEoi=(MLmu$Q%7%7nA8r)y5C~;d^PQ z+w35xUhaLkWc_v^66z|{>T9h`;p%-lz$WY zrHqIWm-2@$^)q4oCwYl6R$0w5x5>ViJ<i$X}VADrw>CUCJLEu*ih|L2?o(f14ee zVXwxmbu#RSA7s+_ak6#uX4tS%_B1!ko*g>?q|5`m6`EvslNr03whOTvsIRG(5yOYe z67;WTJL}{50VuZWmmRM4O=BHGF(;$_``4BlA?lq zX@F0(?Aj@Nckfnc-L*?vU{mU`yBTsfLtdnNn77ET%BrbRvN0b1^pj7d31#A3-h()Q zP>vq5f%0Q)FNwixT*|+C(R>s72g!l<2S!8T`&$5+4&SRj317 z(Z*Du?(T-YTX*k*j4iT%?_Sy8)+PrOkms>ND^kLIOkLKmT_gS&W7^Ak7{@mJg1o|! z!$SEtro>6y+LbQlUon4B#{rz94G7++9p_|c$@4zP`ej(QwI**V94=xIg?d~hD- zRlh>yD=%UsI8bk0l@=3tT%5n?Mx*ykuvgz?D;^f`H%=~7iz zDtj?zU>!XSUp<0ywgJaHrvvXfjJl{&lqvnF0R3Ok%9W7qm*es4FY=oMC_lyyfO-&Vau1el;3Zrj|poKk`%UHl^M&;j9*lHnG_u< zJ`*QMWBnH4nC(Do3v}Z>w4r^utMj$0#en+Z- zZ3cZKWSPH9`4>%}W=aWLCkdhJu#4rmq@+ZAFh^}hAG;5>q-;)gu=us|Emc2Q2M)<*^xO02&zDxTw|_vc_JDN; z>mTipv4gBzvdE?Ub0$wPp?{E=wX0N_sv>SPm8)Re4zC zXWe1lrXDrb)q-_?X~ejLa-YZ_+dYgOWR2efm-73J8EuM%{L~>gJypul#%ZWPUPH-- z0*Q`{5bx2WB{X=w)NZPho#@9};8T0iPwm6lbuWCp1^wDi_;`6qG1{6HGHK#O$-y|A zV^-~59Z4yB0_tQkPLU+^7| z@jzsl6r*q3gto3Q2Yq(%S{d`>F!}P6k7e<~1vr-_=^c2tv)@cbyO@b_{qjZgUCZz7 zWy*$3nOFx)jE#|;jC4tWKG~Q9@;C!?k&PI;S%LXfb!EAfqdy467-{^taWeG#@5S`x zmojYVP&Lj^z!;~hqFk!V%WTi--_e1*CeH@UAy)Xg_W!A)N4OJZmSMu}x z9G{6jrg@L*Gj;UH*Z$4$vd`Gjz1x$$^O|$N?6ga#T{?ZB(+B=beSm5iq|IPB8z~Zl zp_jqn#nglU;16jE(;m3b%V6+4+hC}-9RIJT%1*EYjAyprznC&k>l~mrV2#s4Oqa7b zt>oln1LKt#uW;2>SM^}5!-W@Kcsk-d6p%lS@eS8pb4?G%Exq^Nd!7vq4Qi}~y$Vmp zL?9NXC*n0OL+r-2h&j0xu_uh9VN4BiH_zePHM|G$54{mbatijcRjdrw#s^kqr~6f8 zrTSql)E|4$&#P|Gd{?8Y&G zeQu(>s6egrC&tA}-NyW*+VfR8X+`#Xn&y2#>wX{hDY;HHXy8DJjlvox_G~s6Bk=n$K19(lzmc`oo;)Lf#gXVsWd7ZaOt-o_^H#t5Y^N9+z z_NuMx7NsX!pHGVnDLRDtKlg?yGxreoVGTrEqvRT98pinMHA(aOO+iY6_4&k*HAP&@ zNrQ~l7)S5NJW*Sx;`##D7790Pu&k$GK8!gq*5a+t$E;ad#B~j>pJZZAbOdX(+WHme z$6M>`Wjpo~wDkzCJz$<^eLiB<@}f;xhu}U>W(wA#F*n)*TQp-Gn{$)Y#006ud`d$N z?u!dvYkfW{WPJkXV%eCNRbWnA2_4cf*GYh%aE{A!dK6=x92*|CUGtyWQzo9`JI?#^ z6T!@hxjwlg^4teyEQ_3ZrZ|GaTlQc{w~ z!i5Vx1`i(W`OGuVsQ6jLo-sbJJL4+ZS25;}VE?3#&11YM!B|DcH!{`Ev2U})@14fJ zjxmjV2jcxsVIOz>_1AajZ!lJtv4#A7tm}CoW=!>0C(D=kKJ4?W*h=cfm_y1!ITSHV~Lf?5YVbCw25O3G;P6{UCN-h!)3ZS;`24%V0p4G(w8|_96EHU)dutr`U&D)yY=eT zi*dE8{OMCJ%AfwI*}<;-At%R}w*&g}r|gd9ua&))(g*bA&u8@If4j5thwfVZw_{AQ zDu4R0R{m^19)0xDu81@BWE-aWfIj7UUVr)JmsQ*`pP}#Y9c-_(`cL0*jLX;6e^vKs zBl;(01X!>2^`HKuht?)&_g$s)ZGHV`+_kFz^i9g3l`&;wIa4+~I~&(u*V;*UZGhee z?dAENAwz~J`#kZ)6RPc}->{uz+t2ocZ8qC)wnh53p7lx(%Bw%t^0YIbqs{paEry%@ z3hOCsjL6WBGo!+WW<`bD zBO1pi0oizmQ^er>zkuZ6)x*x~*)#6%fB(BoKs=bqWD;;!r0F~G~`-TIt zcl&EiUWRN%Y<0s%#IKxe6yu#I5nB+)`25pP34Bq!yu1V)0!d3tli=WB`SgP!+{>-Y ziV3~4y)x&uwCIR4aPJ|;-tMU`lP1KlGCq~DK>w~_4AsleJu9dif_7c}{QM*_F;TLz zvSjp#;fRmV71{@}0?Xa$pBlFQZ}lvMnwj z>lL;b_dlC=5+jeb2^GI@iHUa?GtcW>R~hj3TY^4Y#nmznK0G{J)~;QvbZYDUH+lM_^&4*%EuQlGZ#qbI;KKsoBy z^7Om|d;QIv2Y@1_oi2L4+~rZ$dcC!He`hJzGCx7=1nWD-J~Cp&2*G$vzCk>FP~cK~-N9!# zLLNqCnc^|94akd+a;tyzs^vz;bT^~U6s3U|fO5A3+Z`9MmZdwL9j|x52Gsp?#D!oy zCl5UEfZ~d=z5D2+k0dfQ*vvbjf9Rm;PaXvI$&HP4tAFImWyXrkWaTr3h(ERJew@zj zb5iu{&RX87eRT5bW!LBV{Fk47s&pq0;q%Wwm&ubS%X|O)r{XcFdl9Sd$N^D25Uj6~ zW5YUtF{NAm5pQV3n!e%#Zcx006W3GI*Di&g8mB?8o4Y*U@fA2182bzMK~z6S-qD~z zgTNulajLW44qRL2IEMVj?C3DJ`XgS^SdyNoxHF2^fZw;%<3x^iI%~RjB-L!fdxs+i zm17&~PM#ilOP^rhp%O7udOcm`sXuurtOFSTxz#^(nZL0ZeoyXAeiC>Q9o4skx*lMA z($2l)+z{M%8G|+*>wZditWOAePhZ0Kw~+_p!ryJ@&0HMnzquew=>xu>Tm6Fr78@D2 zO`pj_{PXepTX;I$7jlGyUd`YEB!D04?KMgUW32Mx3(w0_Pd*|2o_R*z2A|}I@4iKx z{Tfl69E;vccf4o(7;nKEp5h(7_~MJIo%`nNuM~en&ogQ_4^EHTTfumS`XHXtt^SC& zG?EjrWkZhSCQyHio({UXF2lXxYSaqHAiS-A4V>z0$6eAmL1r#cE%w(q zo}oU7XLPIoTK|Q{4dBx#?h|<_C!jaulLMFd%k%yE$(z_$M){%3y zRh3c&9uoBdU(>Drs}{{OGVY!}Ltc+nPqa50AIvdrLwx-AsLTCdeN}#*K3ysi$Jo4W ztHO>3aH-G^sN)9k#sC{Arm>XvGS}iE^nY_HQ*lmNO0(&ryGJ z+^7%cHg5G_xnQm_2Yed(Ocr8x9d&i&X|Zfr*Ixk-d+FlE;CR$p_qVynt$1ck9k^yY zv6pS*n{88j!rT{bgdNDW>5uk)=nvl^ejj5xot}<)S9+`S;F(bWa*SuFPu!Z7ZuMU= zf3`6@CQNbHGQf*+)R)J*F|XcITdfd^IVan5as%sYYo!V0P41b-P18~oKKcB&(E(_#kNOKUe(f(MqU^Z}R0t^R>?XBqKL3*|Ez z(GiMgM6Qt@2T09)op%3w}@W9HGCJCy4s82cRFc?b&7J3hqPv3S(Hz zF!NOvXAs;-ayi)^Ou{<0*T|7hc!T6RTDXH+df1*r$ha8Bxntc&=@YRcz^(rNvwV%@ z^l%KE3VwoFe>1m`T(k`E1p*L{lNuW>&-Q%^-<+5Soi~9KUM@}O>)7@;Af}#WZU(uA zd#qeS#^7l2JNpq=W9AtmW!{2)ND102JSZ8jvv zDt*EN-Rti+!^fBmJ`j1WDUqReen(l!Z3qiqC&9~?$*bU&GiIv>V+?Xs8t_|{8w-Uz zb@E(UzKUCkHq$O`(>RyrlpIXjh3(1#aOJd=zgGyp#CP~EOlfhky>50qMm?vIc^jvZ z`eWTk=@Yul&u#gG(`5u_Rtn)W$q~?BSI<-)ZA&YB+jqiPaP9j`0XQ1u3U00{mu8fI zEygm8(>e&9H0~nPgLVLK6LrZ7jmODz%p+C2O{Ci}b{K*2axVCrZh4#3+rs~2N}eR+ zt@6Nwq(0z+xz!(>Fk`~{Rq&Y@NeTxql6A{Ty_z|BqT-cn{LXsR``wKVQeTbwk2X@z z@6_ito+r;~`QuXy?-Tqt@|?(fqW(7CCv~&u|JfZ|d4xyNN7wKhLQ0=?0gK$~KY!X} zWBl46#T`uw3%2n>QJ3_*$bfmXY+% zYUan$r^vB%h6C`KW{f4qV7;TPv=p&-8b4A??YX3k-?IZ^_v+9llZQzzEaoJN2I{B3_bBTm>ZY=ZLu!8>&sqG8Z2-p_ z+{c?cXO8j@y-G zmoAavn8)uyz2AW`3-#xBfT+6`Cu&aZ>#DkLslR$VF;5#Y=9T>)>jb|`6(1L8&)L;; zRgc;DyX5g|{9P?2zm4NL>a%LmT(|nqnlRRgagyTx#-Sh7^sx6g`rohc$t^MpV-t=C z+2-xy7!UnEpK&ZJ?O4zA)!waA>W;G4IKOQF8Jmmm79z&BQE`+toy=<7``Gvaff5k4{CC2sh&H{@`{d%lAo{-(TegS2bD3!s(h7y{-!v# zXjXAK1U8NeH7mqmBT2%eH`nc-B#sn@q=Tqg=Rmd+BLK9 z+r}y^f9g$};Jc*~i0{em$GaRk)7Zo9@E`RjkC*x^pYL9OpD|v>kfnZtH~@*lH$d!t z&V`TRH)dengY6V`V*B5Q@ekWUy}vMTwF7k2{9iqz#u9E0Qj8$4N?&Y~d=-XL- zsy~EX6zAMh{?z#h`a_NhXeZj`AjU-Gsn3`(Lz*!E`LlnNlX3Utp%aT|`nuJB%IJ~C zApgaZgl`()`)m@0zA!wid|&ta`*@FfU{!#>;+62*fThqOE;>?uC(v15&p&a@ z*I?~&E83s!SjX6kez+Fjlc=hwP$`djz5&;{M&MSnnFNDTZ$_kmpOXZR5;^&<@|3-!;93m7MY9=p=;$+l=03g538-)2=Pz}oxBmPz z?~!lLnL7DMT0*=k|C3P`f7LsR^715d-C9AvzR7o-m&-A^eciiY+_`bwo*v#~w zjw#+FUz{^((y5L*b{@Ci7IfOD(>|R((CGu6KG5j{oj%a%1D!tbU+DuVR^8uGd@#W9 zn5YC9FCH53A5xkBJiIKa`W_0t9K-L(;P0_x=JUNQ&z)_#-kF;1a>91d?5NpQS3)N> F`+t~XQda-~ diff --git a/project/utils.py b/project/utils.py index 30e240e1..75a33521 100644 --- a/project/utils.py +++ b/project/utils.py @@ -6,15 +6,11 @@ """ -def add(x, y): - """Adds two numbers.""" - return 5 - - CONSTANTS = { 'NAME': 'Clipboard Mangler', 'NUMOFOBJECTS': 0, 'HISTORY_MAX_ITEMS': 10, 'APP_DATA': 'project/app_data.json', - 'CONFIG_FILE_LOCATION': 'project/config.ini' + 'CONFIG_FILE_LOCATION': 'project/config.ini', + 'ICON_LOCATION': "project\\icon.ico" } From 22fc8b5c9f46ce92f5c9d3dabfc73c44f4e9cce1 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Sun, 3 Mar 2019 23:50:43 +0800 Subject: [PATCH 55/60] Added dialog box to disable plugins --- project/ClipboardManager/ClipboardManager.py | 2 +- project/ConfigManager/ConfigManager.py | 41 ++++++- project/PluginManager/PluginManager.py | 53 ++++++--- project/Plugins/ImageRotate.py | 7 -- project/Widgets/PluginsScreen.py | 108 +++++++++++++++++++ project/Widgets/SettingsScreen.py | 5 +- project/__main__.py | 5 +- 7 files changed, 197 insertions(+), 24 deletions(-) delete mode 100644 project/Plugins/ImageRotate.py create mode 100644 project/Widgets/PluginsScreen.py diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index ad6aae35..7803e14a 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -20,7 +20,7 @@ def __init__(self): super().__init__() self._logger = logging.getLogger(self.__class__.__qualname__) - self._plugin_manager = PluginManager() + self._plugin_manager = PluginManager.get_instance() self._clipboard_state_callback = None self._last_text = None self._last_image = None diff --git a/project/ConfigManager/ConfigManager.py b/project/ConfigManager/ConfigManager.py index f3f1f489..4ac2d02c 100644 --- a/project/ConfigManager/ConfigManager.py +++ b/project/ConfigManager/ConfigManager.py @@ -1,4 +1,5 @@ import configparser +import json from project.utils import CONSTANTS @@ -10,7 +11,7 @@ class ConfigManager: @staticmethod def get_instance(): - """Static access method.""" + """Singleton access method.""" if ConfigManager.__instance is None: ConfigManager() return ConfigManager.__instance @@ -35,6 +36,8 @@ def _init_config(self): self._config.set('settings', 'auto_load_top', 'true') self._config.set('plugin_settings', 'chain_all_plugins', 'false') + self._config.set('plugin_settings', 'disabled_text_plugins', json.dumps([])) + self._config.set('plugin_settings', 'disabled_image_plugins', json.dumps([])) self.save() @@ -70,6 +73,42 @@ def chain_all_plugins(self): def chain_all_plugins(self, value: bool): self._config['plugin_settings']['chain_all_plugins'] = 'true' if value else 'false' + @property + def disabled_text_plugins(self): + return json.loads(self._config.get('plugin_settings', 'disabled_text_plugins')) + + @disabled_text_plugins.setter + def disabled_text_plugins(self, plugin_names: [str]): + self._config['plugin_settings']['disabled_text_plugins'] = json.dumps(plugin_names) + + def disable_text_plugin(self, text_plugin_name: str): + if text_plugin_name not in self.disabled_text_plugins: + self.disabled_text_plugins = self.disabled_text_plugins + [text_plugin_name] + + def enable_text_plugin(self, text_plugin_name): + _temp = self.disabled_text_plugins + if text_plugin_name in _temp: + _temp.remove(text_plugin_name) + self.disabled_text_plugins = _temp + + @property + def disabled_image_plugins(self): + return json.loads(self._config.get('plugin_settings', 'disabled_image_plugins')) + + @disabled_image_plugins.setter + def disabled_image_plugins(self, plugin_names: [str]): + self._config['plugin_settings']['disabled_image_plugins'] = json.dumps(plugin_names) + + def disable_image_plugin(self, image_plugin_name: str): + if image_plugin_name not in self.disabled_text_plugins: + self.disabled_image_plugins = self.disabled_image_plugins + [image_plugin_name] + + def enable_image_plugin(self, image_plugin_name): + _temp = self.disabled_image_plugins + if image_plugin_name in _temp: + _temp.remove(image_plugin_name) + self.disabled_image_plugins = _temp + def save(self): with open(CONSTANTS['CONFIG_FILE_LOCATION'], 'w') as file: self._config.write(file) diff --git a/project/PluginManager/PluginManager.py b/project/PluginManager/PluginManager.py index 4fe23b85..4f538406 100644 --- a/project/PluginManager/PluginManager.py +++ b/project/PluginManager/PluginManager.py @@ -3,6 +3,8 @@ from PyQt5.QtGui import QPixmap +from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject +from project.ConfigManager import ConfigManager from project.Plugins import SpellingMistakesPlugin from project.Plugins.ImageRotatePlugin import ImageRotatePlugin from project.Plugins.QuotePlugin import QuotePlugin @@ -11,28 +13,46 @@ class PluginManager: + __instance = None + + @staticmethod + def get_instance(): + """Static access method.""" + if PluginManager.__instance is None: + PluginManager() + return PluginManager.__instance def __init__(self): + if PluginManager.__instance is not None: + raise Exception("This class is a singleton. Please use get_instance().") + + PluginManager.__instance = self self._logger = logging.getLogger(self.__class__.__qualname__) - self._text_plugins = [] - self._image_plugins = [] + self.text_plugins = [] + self.image_plugins = [] - self._disabled_plugin_names = set() + self._config = ConfigManager.get_instance() # If this were a real application, would use importlib to dynamically import plugins # within this folder. - self._text_plugins.append(SpellingMistakesPlugin()) - self._text_plugins.append(SynonymPlugin()) - self._text_plugins.append(QuotePlugin()) + self.text_plugins.append(SpellingMistakesPlugin()) + self.text_plugins.append(SynonymPlugin()) + self.text_plugins.append(QuotePlugin()) - self._image_plugins.append(ImageRotatePlugin()) + self.image_plugins.append(ImageRotatePlugin()) def on_copy_text(self, text_input: str, stack: Stack): """Function that is called by the ClipboardManager upon text copy""" - _plugin = random.choice( - list(filter(lambda plugin: plugin.__class__.name() not in self._disabled_plugin_names, - self._text_plugins))) + _enabled_plugins = list( + filter(lambda plugin: plugin.__class__.name() not in self._config.disabled_text_plugins, + self.text_plugins)) + + if not _enabled_plugins: + stack.push_item(TextClipboardObject(text_input)) + return + + _plugin = random.choice(list(_enabled_plugins)) self._logger.info("Passing " + text_input + " to plugins!") self._logger.info("Randomly chose plugin " + _plugin.__class__.__qualname__) @@ -40,8 +60,15 @@ def on_copy_text(self, text_input: str, stack: Stack): def on_copy_image(self, image_input: QPixmap, stack: Stack): """Function that is called by the ClipboardManager upon image copy""" - _plugin = random.choice( - list(filter(lambda plugin: plugin.__class__.name() not in self._disabled_plugin_names, - self._image_plugins))) + + _enabled_plugins = list( + filter(lambda plugin: plugin.__class__.name()not in self._config.disabled_image_plugins, + self.image_plugins)) + + if not _enabled_plugins: + stack.push_item(ImageClipboardObject(image_input)) + return + + _plugin = random.choice(_enabled_plugins) _plugin.on_copy(image_input, stack) diff --git a/project/Plugins/ImageRotate.py b/project/Plugins/ImageRotate.py deleted file mode 100644 index 9dfd1f99..00000000 --- a/project/Plugins/ImageRotate.py +++ /dev/null @@ -1,7 +0,0 @@ -# from PIL import Image -# -# colorImage = Image.open("g.png") -# -# rotated = colorImage.rotate(45) -# -# rotated.save("img1.png") diff --git a/project/Widgets/PluginsScreen.py b/project/Widgets/PluginsScreen.py new file mode 100644 index 00000000..64ec7cc1 --- /dev/null +++ b/project/Widgets/PluginsScreen.py @@ -0,0 +1,108 @@ +import logging + +from PyQt5.QtWidgets import QMainWindow, QWidget, QVBoxLayout, \ + QGroupBox, QCheckBox, QHBoxLayout, QPushButton, QLabel + +from project.ConfigManager import ConfigManager +from project.PluginManager import PluginManager + + +class PluginsScreen(QMainWindow): + """Enable and disable some of our enhancers""" + + def _save_clicked(self): + _config_mgr = ConfigManager.get_instance() + _config_mgr.save() + self._dirty = False + self._save_btn.setDisabled(True) + + def _text_plugin_checkbox_clicked(self, checked, name): + self._dirty = True + self._save_btn.setDisabled(False) + # self._logger.info(name + ': ' + str(checked)) + _config_mgr = ConfigManager.get_instance() + if checked: + _config_mgr.enable_text_plugin(name) + else: + _config_mgr.disable_text_plugin(name) + + def _image_plugin_checkbox_clicked(self, checked, name): + self._dirty = True + self._save_btn.setDisabled(False) + # self._logger.info(name + ': ' + str(checked)) + _config_mgr = ConfigManager.get_instance() + if checked: + _config_mgr.enable_image_plugin(name) + else: + _config_mgr.disable_image_plugin(name) + + def __init__(self, parent=None): + super().__init__(parent) + + self._logger = logging.getLogger(self.__class__.__qualname__) + + self._plugin_manager = PluginManager.get_instance() + + self.setWindowTitle("Plugins") + + _config = ConfigManager.get_instance() + self._dirty = False + + self._central_widget_layout = QVBoxLayout() + self._central_widget = QWidget(self) + + self._text_plugins_group_box = QGroupBox("Text Enhancers") + self._image_plugins_group_box = QGroupBox("Image Enhancers") + + _vbox1 = QVBoxLayout() + + for plugin in self._plugin_manager.text_plugins: + + _checkbox = QCheckBox(plugin.__class__.name(), self) + + if plugin.__class__.name() not in _config.disabled_text_plugins: + _checkbox.setChecked(True) + + # https://stackoverflow.com/questions/19837486/python-lambda-in-a-loop + _checkbox.toggled.connect(lambda checked, name=plugin.__class__.name(): + self._text_plugin_checkbox_clicked(checked, name)) + + _vbox1.addWidget(_checkbox) + _vbox1.addWidget(QLabel(plugin.__class__.description())) + + self._text_plugins_group_box.setLayout(_vbox1) + + _vbox2 = QVBoxLayout() + + for plugin in self._plugin_manager.image_plugins: + _checkbox = QCheckBox(plugin.__class__.name(), self) + + if plugin.__class__.name() not in _config.disabled_image_plugins: + _checkbox.setChecked(True) + + _checkbox.toggled.connect(lambda checked, name=plugin.__class__.name(): + self._image_plugin_checkbox_clicked(checked, name)) + + _vbox2.addWidget(_checkbox) + _vbox2.addWidget(QLabel(plugin.__class__.description())) + + self._image_plugins_group_box.setLayout(_vbox2) + + self._central_widget_layout.addWidget(self._text_plugins_group_box) + self._central_widget_layout.addWidget(self._image_plugins_group_box) + + # Bottom save button + self._bottom_save_widget = QWidget() + self._bottom_save_layout = QHBoxLayout() + self._bottom_save_layout.addStretch(1) + self._save_btn = QPushButton("Save") + self._save_btn.clicked.connect(self._save_clicked) + self._bottom_save_layout.addWidget(self._save_btn) + + self._bottom_save_widget.setLayout(self._bottom_save_layout) + self._central_widget_layout.addWidget(self._bottom_save_widget) + + self._central_widget.setLayout(self._central_widget_layout) + self.setCentralWidget(self._central_widget) + + # self.setFixedSize(self.size()) diff --git a/project/Widgets/SettingsScreen.py b/project/Widgets/SettingsScreen.py index 74d7f393..0638102a 100644 --- a/project/Widgets/SettingsScreen.py +++ b/project/Widgets/SettingsScreen.py @@ -31,7 +31,8 @@ def _save_clicked(self): def __init__(self, parent=None): super(SettingsScreen, self).__init__(parent) - self.setWindowTitle("Settings") + + self.setWindowTitle('Settings') _config_mgr = ConfigManager.get_instance() self._dirty = False # Changed settings but not saved @@ -74,3 +75,5 @@ def __init__(self, parent=None): self._central_widget.setLayout(self._central_widget_layout) self.setCentralWidget(self._central_widget) + + # self.setFixedSize(self.size()) diff --git a/project/__main__.py b/project/__main__.py index e5f19714..9473c904 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -14,6 +14,7 @@ from project.Stack import Stack from project.Widgets import MainListWidget, TextListWidgetItem from project.Widgets.MainListWidget import ImageListWidgetItem +from project.Widgets.PluginsScreen import PluginsScreen from project.Widgets.SettingsScreen import SettingsScreen from project.TextEditor import Editor @@ -103,6 +104,8 @@ def __init__(self, clipboard_manager: ClipboardManager): self._settings_screen = SettingsScreen(self) + self._plugins_screen = PluginsScreen(self) + self._init_ui() @pyqtSlot(int) @@ -126,7 +129,7 @@ def _show_settings_window(self): self._settings_screen.show() def _show_plugins_window(self): - pass + self._plugins_screen.show() @pyqtSlot(Stack) def _render_clipboard_stack(self, clipboard_stack: Stack): From 12c79b6cef37370f2e878fea5d09d4d7e559e1bc Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Mon, 4 Mar 2019 02:28:43 +0800 Subject: [PATCH 56/60] Implemented saving and reloading the clipboard state from FS --- .gitignore | 1 + project/ClipboardManager/ClipboardManager.py | 48 +++++++++++++++++++- project/Plugins/Save.py | 24 ---------- project/__main__.py | 48 +++++++++++++------- project/utils.py | 2 +- 5 files changed, 81 insertions(+), 42 deletions(-) delete mode 100644 project/Plugins/Save.py diff --git a/.gitignore b/.gitignore index 92eab351..2ed482f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Project-specific files project/*.ini +project/**/autosave.data # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 7803e14a..311af569 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -1,8 +1,12 @@ """Class encapsulating clipboard events""" +import ast +import json import logging +import traceback from PyQt5.Qt import QApplication # noqa: F401 -from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot +from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot, QByteArray, QBuffer, QIODevice +from PyQt5.QtGui import QImage, QPixmap from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject from project.ConfigManager import ConfigManager @@ -12,6 +16,8 @@ # https://stackoverflow.com/questions/36522809/ # pyqt5-connection-doesnt-work-item-cannot-be-converted-to-pyqt5-qtcore-qobject + + class ClipboardManager(QObject): clipboard_changed_signal = pyqtSignal(Stack) stack_changed_signal = pyqtSignal(Stack) @@ -30,6 +36,7 @@ def __init__(self): QApplication.clipboard().dataChanged.connect(self._clipboard_changed) self.clipboard_stack = Stack() + self.stack_changed_signal.connect(self._stack_changed) @pyqtSlot(Stack) @@ -125,3 +132,42 @@ def _remove_clipboard_item(self, idx): self.clipboard_stack.pop(idx) self.stack_changed_signal.emit(self.clipboard_stack) # self.clipboard_changed_signal.emit(self.clipboard_stack) + + def save_state(self, location: str): + """Persists state of the stack to a JSON file""" + _list = [] + for item in self.clipboard_stack.items(): + if isinstance(item, TextClipboardObject): + _list.append({"type": "text", "value": item.text}) + elif isinstance(item, ImageClipboardObject): + _ba = QByteArray() + _buffer = QBuffer(_ba) + _buffer.open(QIODevice.WriteOnly) + item.pixmap.toImage().save(_buffer, 'PNG') + _base64_data = _ba.toBase64().data() + + _list.append({"type": "image", "value": str(_base64_data)}) + + with open(location, 'w') as outfile: + json.dump(_list, outfile) + + def load_state(self, location: str): + """Loads the state of the stack from a JSON file""" + try: + self.clipboard_stack.clear() + with open(location, 'r') as infile: + _stack = json.load(infile) + for saved_item in _stack: + + if saved_item['type'] == 'text': + self.clipboard_stack.push_item(TextClipboardObject(saved_item['value'])) + elif saved_item['type'] == 'image': + _ba = QByteArray.fromBase64(ast.literal_eval(saved_item['value'])) + _img = QImage.fromData(_ba, 'PNG') + _pixmap = QPixmap.fromImage(_img) + self.clipboard_stack.push_item(ImageClipboardObject(_pixmap)) + + self.stack_changed_signal.emit(self.clipboard_stack) + + except Exception: + traceback.print_exc() diff --git a/project/Plugins/Save.py b/project/Plugins/Save.py deleted file mode 100644 index 5241f425..00000000 --- a/project/Plugins/Save.py +++ /dev/null @@ -1,24 +0,0 @@ -""" Contains logic for loading and saving states """ -import json -import os -from project.utils import CONSTANTS -from project.ClipboardManager.ClipboardObject import ImageClipboardObject, TextClipboardObject - -def saveState(location, clipboard): - state = [] - image = 1 - for item in clipboard: - print(item, type(item)) - if type(item) == TextClipboardObject: - state.append({"type": "string", "content": str(item) }) - elif type(item) == ImageClipboardObject: - imagelocation = "{0}/images/image{1}.png".format(os.path.dirname(location), image) - state.append({"type": "image", "location": imagelocation}) - item.getImage().save(imagelocation, 'PNG') - image += 1 - - with open(location, 'w') as outfile: - json.dump(state, outfile) - -def loadState(state): - pass \ No newline at end of file diff --git a/project/__main__.py b/project/__main__.py index 2eff2b63..90548501 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -1,26 +1,26 @@ import logging -import sys import os +import sys +from pathlib import Path from PyQt5 import QtWidgets -from PyQt5.QtGui import QIcon from PyQt5.QtCore import pyqtSlot, pyqtSignal +from PyQt5.QtGui import QIcon from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QMainWindow, QApplication, \ QHBoxLayout, QVBoxLayout, QWidget, QListWidgetItem, QFileDialog from project import ClipboardManager from project.ClipboardManager.ClipboardObject import TextClipboardObject, ImageClipboardObject +from project.ConfigManager import ConfigManager from project.Plugins.Systray import SystemTrayIcon from project.Stack import Stack +from project.TextEditor import Editor from project.Widgets import MainListWidget, TextListWidgetItem from project.Widgets.MainListWidget import ImageListWidgetItem from project.Widgets.PluginsScreen import PluginsScreen from project.Widgets.SettingsScreen import SettingsScreen -from project.TextEditor import Editor - from project.utils import CONSTANTS -from project.Plugins import Save class ActionBar(QWidget): @@ -39,10 +39,10 @@ def __init__(self): # self._remove_btn.clicked.connect() self._remove_btn.setObjectName(MainWindow.REMOVE_BUTTON_NAME) - self._edit_btn = QtWidgets.QPushButton("Edit") + # self._edit_btn = QtWidgets.QPushButton("Edit") # self._edit_btn.setGeometry(QtCore.QRect(100, 3, 51, 20)) - self._edit_btn.setObjectName(MainWindow.EDIT_BUTTON_NAME) - self._edit_btn.clicked.connect(self._start_editor) + # self._edit_btn.setObjectName(MainWindow.EDIT_BUTTON_NAME) + # self._edit_btn.clicked.connect(self._start_editor) self._move_up_btn = QtWidgets.QPushButton("Move Up") self._move_up_btn.setObjectName(MainWindow.MOVE_UP_BUTTON_NAME) @@ -52,7 +52,7 @@ def __init__(self): # _horizontal_layout.addWidget(self._add_btn) _horizontal_layout.addWidget(self._remove_btn) - _horizontal_layout.addWidget(self._edit_btn) + # _horizontal_layout.addWidget(self._edit_btn) _horizontal_layout.addWidget(self._move_up_btn) _horizontal_layout.addWidget(self._move_down_btn) @@ -196,7 +196,7 @@ def setupUi(self): self.fileMenu.addAction(self.loadOption) self.menubar.addAction(self.fileMenu.menuAction()) - + # Settings Menu Bar self.settingsMenu = QtWidgets.QMenu(self.menubar) self.settingsMenu.setObjectName("settingsMenu") @@ -210,7 +210,7 @@ def setupUi(self): self.settingsMenu.addAction(self.actionSettings) - # Plugin Settings + # Plugin Settings self.pluginSettings = QtWidgets.QAction(self) self.pluginSettings.setObjectName("actionPlugins") self.pluginSettings.setText('Plugins') @@ -229,6 +229,21 @@ def setupUi(self): self.show() + _config = ConfigManager.get_instance() + + # check whether the autosave file is present and auto persist checked, if so, try to load it + _autosave_path_location = Path('./' + CONSTANTS['AUTOSAVE_DATA_FILE']).resolve() + print(_autosave_path_location) + if _config.persist_clipboard and os.path.isfile(_autosave_path_location): + self._clipboard_manager.load_state(_autosave_path_location) + # print(self.clipboard_stack.items_count()) + + def closeEvent(self, event): + """Fires on window close""" + _config = ConfigManager.get_instance() + if _config.persist_clipboard: + self._clipboard_manager.save_state(CONSTANTS['AUTOSAVE_DATA_FILE']) + def keyPressEvent(self, event): self._logger.info("Key press detected") if event.matches(QKeySequence.Paste): @@ -236,14 +251,15 @@ def keyPressEvent(self, event): def _load(self): """ Function to load stack""" - filename, _ = QFileDialog.getOpenFileName(self, 'Load Clipboard State', os.environ["HOMEPATH"], '*.json') - print(filename) - # Save.saveState() self._clipboard_manager.clipboard_stack.items()) + filename, _ = QFileDialog.getOpenFileName(self, 'Load Clipboard State', filter='*.json') + if filename: + self._clipboard_manager.load_state(filename) def _save(self): """ Function to save stack""" - filename, _ = QFileDialog.getSaveFileName(self, 'Save Clipboard State', os.environ["HOMEPATH"], '*.json') - Save.saveState(filename, self._clipboard_manager.clipboard_stack.items()) + filename, _ = QFileDialog.getSaveFileName(self, 'Save Clipboard State', filter='*.json') + if filename: + self._clipboard_manager.save_state(filename) if __name__ == '__main__': diff --git a/project/utils.py b/project/utils.py index 75a33521..915511e8 100644 --- a/project/utils.py +++ b/project/utils.py @@ -10,7 +10,7 @@ 'NAME': 'Clipboard Mangler', 'NUMOFOBJECTS': 0, 'HISTORY_MAX_ITEMS': 10, - 'APP_DATA': 'project/app_data.json', + 'AUTOSAVE_DATA_FILE': 'project/autosave.data', 'CONFIG_FILE_LOCATION': 'project/config.ini', 'ICON_LOCATION': "project\\icon.ico" } From 48ef2b00c4705892032a29376294238f470481c6 Mon Sep 17 00:00:00 2001 From: BWACpro <40532058+BWACpro@users.noreply.github.com> Date: Mon, 4 Mar 2019 06:44:38 +1100 Subject: [PATCH 57/60] cleaned up code --- project/ClipboardManager/ClipboardManager.py | 5 -- project/ConfigManager/ConfigManager.py | 9 ---- project/Plugins/ImageRotatePlugin.py | 2 - project/Plugins/SynonymPlugin.py | 2 - project/TextEditor/Editor.py | 54 -------------------- project/Widgets/MainListWidget.py | 2 - project/Widgets/PluginsScreen.py | 3 -- project/__main__.py | 1 - 8 files changed, 78 deletions(-) delete mode 100644 project/TextEditor/Editor.py diff --git a/project/ClipboardManager/ClipboardManager.py b/project/ClipboardManager/ClipboardManager.py index 311af569..428471bd 100644 --- a/project/ClipboardManager/ClipboardManager.py +++ b/project/ClipboardManager/ClipboardManager.py @@ -74,7 +74,6 @@ def _clipboard_changed(self): current_text = QApplication.clipboard().text() current_image = QApplication.clipboard().pixmap() - # current_text = PT.apply(QApplication.clipboard().text()) # TODO: Chain plugins together self._logger.info("Current Text:" + str(QApplication.clipboard().text())) self._logger.info("Current Image Info:" + str(QApplication.clipboard().pixmap())) @@ -92,9 +91,6 @@ def _clipboard_changed(self): self._last_image = current_image self._last_text = current_text - # DONE: use Qt signals properly - # https://stackoverflow.com/questions/36434706/pyqt-proper-use-of-emit-and-pyqtsignal - @pyqtSlot(int) def set_selected_object(self, idx): """Highlights a particular row in the main window""" @@ -131,7 +127,6 @@ def _remove_clipboard_item(self, idx): self.clipboard_stack.pop(idx) self.stack_changed_signal.emit(self.clipboard_stack) - # self.clipboard_changed_signal.emit(self.clipboard_stack) def save_state(self, location: str): """Persists state of the stack to a JSON file""" diff --git a/project/ConfigManager/ConfigManager.py b/project/ConfigManager/ConfigManager.py index 4ac2d02c..e9a19fcc 100644 --- a/project/ConfigManager/ConfigManager.py +++ b/project/ConfigManager/ConfigManager.py @@ -32,7 +32,6 @@ def _init_config(self): self._config.add_section('plugin_settings') self._config.set('settings', 'persist_clipboard', 'true') - # self._config.set('settings', 'delete_after_paste', 'true') self._config.set('settings', 'auto_load_top', 'true') self._config.set('plugin_settings', 'chain_all_plugins', 'false') @@ -49,14 +48,6 @@ def persist_clipboard(self): def persist_clipboard(self, value: bool): self._config['settings']["persist_clipboard"] = 'true' if value else 'false' - # @property - # def delete_after_paste(self): - # return self._config.getboolean('settings', "delete_after_paste") - # - # @delete_after_paste.setter - # def delete_after_paste(self, value: bool): - # self._config['settings']["delete_after_paste"] = 'true' if value else 'false' - @property def auto_load_top(self): return self._config.getboolean('settings', "auto_load_top") diff --git a/project/Plugins/ImageRotatePlugin.py b/project/Plugins/ImageRotatePlugin.py index d596382d..13913811 100644 --- a/project/Plugins/ImageRotatePlugin.py +++ b/project/Plugins/ImageRotatePlugin.py @@ -1,11 +1,9 @@ -# from PyQt5.QtGui import QPixmap import random from PyQt5.QtCore import Qt from PyQt5.QtGui import QPixmap, QTransform from project import Stack -# from project.ClipboardManager.ClipboardObject import TextClipboardObject from project.ClipboardManager.ClipboardObject import ImageClipboardObject from project.Plugins import AbstractPlugin diff --git a/project/Plugins/SynonymPlugin.py b/project/Plugins/SynonymPlugin.py index 1618ce1e..ef3f5abf 100644 --- a/project/Plugins/SynonymPlugin.py +++ b/project/Plugins/SynonymPlugin.py @@ -20,7 +20,6 @@ def _synonym(self, text): new_words = new_words + ' ' + word skip_word = False else: - # start_ = time.time() skip_word = True try: w = thesaurus.Word(word) @@ -35,7 +34,6 @@ def _synonym(self, text): new_words = new_words + ' ' + word except TypeError: new_words = new_words + ' ' + word - # end_ = time.time() end = time.time() self._logger.info('processing time: ' + str(end - start)) return new_words diff --git a/project/TextEditor/Editor.py b/project/TextEditor/Editor.py deleted file mode 100644 index 2c47402d..00000000 --- a/project/TextEditor/Editor.py +++ /dev/null @@ -1,54 +0,0 @@ -from PyQt5 import QtCore, QtWidgets - - -class Editor(object): - def setupUi(self, Dialog): - Dialog.setObjectName("Dialog") - Dialog.resize(463, 258) - Dialog.setMinimumSize(QtCore.QSize(463, 258)) - Dialog.setMaximumSize(QtCore.QSize(463, 258)) - self.save_button = QtWidgets.QPushButton(Dialog) - self.save_button.setGeometry(QtCore.QRect(150, 230, 75, 21)) - self.save_button.setObjectName("pushButton") - self.save_button.clicked.connect(self.save) - self.cancel_button = QtWidgets.QPushButton(Dialog) - self.cancel_button.setGeometry(QtCore.QRect(230, 230, 75, 21)) - self.cancel_button.setObjectName("pushButton_2") - self.cancel_button.clicked.connect(self.cancel) - self.textEdit = QtWidgets.QTextEdit(Dialog) - self.textEdit.setGeometry(QtCore.QRect(0, 0, 461, 221)) - self.textEdit.setObjectName("textEdit") - - self.retranslateUi(Dialog) - QtCore.QMetaObject.connectSlotsByName(Dialog) - - def retranslateUi(self, Dialog): - _translate = QtCore.QCoreApplication.translate - Dialog.setWindowTitle(_translate("Dialog", "Dialog")) - self.save_button.setText(_translate("Dialog", "Save")) - self.cancel_button.setText(_translate("Dialog", "Cancel")) - - def save(self): - print(self.textEdit.toPlainText()) - - def cancel(self): - sys.exit(app.exec_()) - - def start(): - import sys - app = QtWidgets.QApplication(sys.argv) - Dialog = QtWidgets.QDialog() - ui = Editor() - ui.setupUi(Dialog) - Dialog.show() - sys.exit(app.exec_()) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - Dialog = QtWidgets.QDialog() - ui = Editor() - ui.setupUi(Dialog) - Dialog.show() - sys.exit(app.exec_()) diff --git a/project/Widgets/MainListWidget.py b/project/Widgets/MainListWidget.py index bf9a2421..473faeca 100644 --- a/project/Widgets/MainListWidget.py +++ b/project/Widgets/MainListWidget.py @@ -31,13 +31,11 @@ def __init__(self, index: int, obj: TextClipboardObject, parent=None): self._right_vbox_layout = QVBoxLayout() self._text_area = QLabel() - # self._text_area.setReadOnly(True) self._text_area.setText(obj.text) self._date_label = QLabel() self._date_label.setText(obj.date().strftime("%Y-%m-%d %H:%M:%S")) - # Date should be at the bottom. self._right_vbox_layout.addWidget(self._text_area) self._right_vbox_layout.addWidget(self._date_label) diff --git a/project/Widgets/PluginsScreen.py b/project/Widgets/PluginsScreen.py index 64ec7cc1..13f2a2b1 100644 --- a/project/Widgets/PluginsScreen.py +++ b/project/Widgets/PluginsScreen.py @@ -29,7 +29,6 @@ def _text_plugin_checkbox_clicked(self, checked, name): def _image_plugin_checkbox_clicked(self, checked, name): self._dirty = True self._save_btn.setDisabled(False) - # self._logger.info(name + ': ' + str(checked)) _config_mgr = ConfigManager.get_instance() if checked: _config_mgr.enable_image_plugin(name) @@ -104,5 +103,3 @@ def __init__(self, parent=None): self._central_widget.setLayout(self._central_widget_layout) self.setCentralWidget(self._central_widget) - - # self.setFixedSize(self.size()) diff --git a/project/__main__.py b/project/__main__.py index 90548501..618f6e06 100644 --- a/project/__main__.py +++ b/project/__main__.py @@ -15,7 +15,6 @@ from project.ConfigManager import ConfigManager from project.Plugins.Systray import SystemTrayIcon from project.Stack import Stack -from project.TextEditor import Editor from project.Widgets import MainListWidget, TextListWidgetItem from project.Widgets.MainListWidget import ImageListWidgetItem from project.Widgets.PluginsScreen import PluginsScreen From 467f04b1e9222872c37bedd8e73bfe2711ca25a8 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Mon, 4 Mar 2019 04:01:33 +0800 Subject: [PATCH 58/60] Fill in README.md and prepare for submission with usage instructions and team details --- README.md | 54 +++++++++++++++++- azure-pipelines.yml | 5 +- docs/source/modules.rst | 7 +-- docs/source/project.ClipboardManager.rst | 38 ++++++++++++ docs/source/project.ConfigManager.rst | 22 +++++++ docs/source/project.PluginManager.rst | 22 +++++++ docs/source/project.Plugins.rst | 62 ++++++++++++++++++++ docs/source/project.Stack.rst | 22 +++++++ docs/source/project.Widgets.rst | 46 +++++++++++++++ docs/source/project.rst | 35 ++++++++++++ docs/source/project.tests.rst | 22 +++++++ project/Stack/Stack.py | 4 +- project/tests/test_example.py | 38 ------------ project/tests/test_stack.py | 73 ++++++++++++++++++++++++ 14 files changed, 401 insertions(+), 49 deletions(-) create mode 100644 docs/source/project.ClipboardManager.rst create mode 100644 docs/source/project.ConfigManager.rst create mode 100644 docs/source/project.PluginManager.rst create mode 100644 docs/source/project.Plugins.rst create mode 100644 docs/source/project.Stack.rst create mode 100644 docs/source/project.Widgets.rst create mode 100644 docs/source/project.rst create mode 100644 docs/source/project.tests.rst delete mode 100644 project/tests/test_example.py create mode 100644 project/tests/test_stack.py diff --git a/README.md b/README.md index 7f1a02d2..72e73240 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,50 @@ You should be using [Pipenv](https://pipenv.readthedocs.io/en/latest/). Take a l Knowledgeable Kois +##### Members + +[BWACPro](https://github.com/BWACpro) + +[kaleidawave](https://github.com/kaleidawave) + +[Transfusion](https://github.com/Transfusion) 👑 ## Description -A clipboard manager, Copy your text and images with ease! +### Theme +Clipboard Mangler + +### What does it do? +It's a clipboard manager in all its usefulness: + + - For when you `Ctrl-Z` but have no way to redo + - For when you need to quickly swap items in and out of the clipboard + - For when you need images and text to be quickly accessible at the same time + - ...etc + +However, it has a mind of its own... + +### Feature Breakdown +#### Core +* ~~Hooks into Ctrl-C, Ctrl-X and Ctrl-V~~ **done!** +* Able to select specific copied items and modify them + * Able to edit copied text + * ~~Able to add and remove copied items~~ **done!** + * ~~Able to rearrange copied items~~ **done!** + * ~~Able to delete specific items~~ **done!** +* ~~Clipboard should be saved after exiting the app~~ **done!** +* _(Keep entire clipboard history as a stack too?)_ +* _(Tray Logo, from which we can access settings?)_ +#### Crappifying +* Plugin-based architecture, each crappifier should be a class which applies its own transformation onto an image or text +* Ideas for text + * ~~Misspell words~~ **done!** + * Randomly transpose words around + * ~~Replace entire blocks of text with "funny" copypasta from APIs~~ **done!** +* Ideas for images + * Deep fry and load back into memory + * ~~Randomly rotate~~ **done!** + * Randomly add meme images to the front of the clipboard +* ~~Randomly select transformations to apply.~~ **done!** ## Setup & Installation @@ -47,7 +88,16 @@ Unit tests are written using the [pytest](https://docs.pytest.org/en/latest/) fr ## How do I use this thing? -Simply copy text/images (images will only work with right-click>copy) +As you copy and paste text or images, the copied content will be added to the scroll area of the main window. + +The numbers on the left, indicated by ③ in the infographic below indicate their position in the list of copied items. + +A selected item, ① in the infographic below, has a different background color compared to other items. After selection, it may be moved up or down the list, i.e. swapped with the item above or below it, as shown by ②. Remove removes the selected item. + +This may be useful if you want to organize your frequently accessed items at the top. Unchecking the `Always load top item into clipboard` option in the Settings menu will automatically copy the selected item into the system's clipboard. + +Saving the state of the clipboard is done automatically if the option in Settings is checked, or may be done manually in the File menu. +![Screenshot of Clipboard Mangler on macOS Mojave](https://i.imgur.com/FbxCbjF.png) ## Documentation diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 88c177c5..9e04de52 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -35,4 +35,7 @@ jobs: displayName: 'Install project dependencies' - script: pipenv run lint - displayName: 'Lint the project' \ No newline at end of file + displayName: 'Lint the project' + + - script: pipenv run test + displayName: 'Unit test the project' \ No newline at end of file diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 12d360d3..ef9d38c3 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -4,9 +4,4 @@ project .. toctree:: :maxdepth: 4 - ClipboardManager - PluginManager - Stack - Widgets - tests - utils + project diff --git a/docs/source/project.ClipboardManager.rst b/docs/source/project.ClipboardManager.rst new file mode 100644 index 00000000..bb210bac --- /dev/null +++ b/docs/source/project.ClipboardManager.rst @@ -0,0 +1,38 @@ +project.ClipboardManager package +================================ + +Submodules +---------- + +project.ClipboardManager.ClipboardManager module +------------------------------------------------ + +.. automodule:: project.ClipboardManager.ClipboardManager + :members: + :undoc-members: + :show-inheritance: + +project.ClipboardManager.ClipboardObject module +----------------------------------------------- + +.. automodule:: project.ClipboardManager.ClipboardObject + :members: + :undoc-members: + :show-inheritance: + +project.ClipboardManager.HistoryManager module +---------------------------------------------- + +.. automodule:: project.ClipboardManager.HistoryManager + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project.ClipboardManager + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/project.ConfigManager.rst b/docs/source/project.ConfigManager.rst new file mode 100644 index 00000000..66a6bfae --- /dev/null +++ b/docs/source/project.ConfigManager.rst @@ -0,0 +1,22 @@ +project.ConfigManager package +============================= + +Submodules +---------- + +project.ConfigManager.ConfigManager module +------------------------------------------ + +.. automodule:: project.ConfigManager.ConfigManager + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project.ConfigManager + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/project.PluginManager.rst b/docs/source/project.PluginManager.rst new file mode 100644 index 00000000..4cb043fb --- /dev/null +++ b/docs/source/project.PluginManager.rst @@ -0,0 +1,22 @@ +project.PluginManager package +============================= + +Submodules +---------- + +project.PluginManager.PluginManager module +------------------------------------------ + +.. automodule:: project.PluginManager.PluginManager + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project.PluginManager + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/project.Plugins.rst b/docs/source/project.Plugins.rst new file mode 100644 index 00000000..d544f449 --- /dev/null +++ b/docs/source/project.Plugins.rst @@ -0,0 +1,62 @@ +project.Plugins package +======================= + +Submodules +---------- + +project.Plugins.AbstractPlugin module +------------------------------------- + +.. automodule:: project.Plugins.AbstractPlugin + :members: + :undoc-members: + :show-inheritance: + +project.Plugins.ImageRotatePlugin module +---------------------------------------- + +.. automodule:: project.Plugins.ImageRotatePlugin + :members: + :undoc-members: + :show-inheritance: + +project.Plugins.QuotePlugin module +---------------------------------- + +.. automodule:: project.Plugins.QuotePlugin + :members: + :undoc-members: + :show-inheritance: + +project.Plugins.SpellingMistakesPlugin module +--------------------------------------------- + +.. automodule:: project.Plugins.SpellingMistakesPlugin + :members: + :undoc-members: + :show-inheritance: + +project.Plugins.SynonymPlugin module +------------------------------------ + +.. automodule:: project.Plugins.SynonymPlugin + :members: + :undoc-members: + :show-inheritance: + +project.Plugins.Systray module +------------------------------ + +.. automodule:: project.Plugins.Systray + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project.Plugins + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/project.Stack.rst b/docs/source/project.Stack.rst new file mode 100644 index 00000000..295b5432 --- /dev/null +++ b/docs/source/project.Stack.rst @@ -0,0 +1,22 @@ +project.Stack package +===================== + +Submodules +---------- + +project.Stack.Stack module +-------------------------- + +.. automodule:: project.Stack.Stack + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project.Stack + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/project.Widgets.rst b/docs/source/project.Widgets.rst new file mode 100644 index 00000000..359eaa4d --- /dev/null +++ b/docs/source/project.Widgets.rst @@ -0,0 +1,46 @@ +project.Widgets package +======================= + +Submodules +---------- + +project.Widgets.AddItemScreen module +------------------------------------ + +.. automodule:: project.Widgets.AddItemScreen + :members: + :undoc-members: + :show-inheritance: + +project.Widgets.MainListWidget module +------------------------------------- + +.. automodule:: project.Widgets.MainListWidget + :members: + :undoc-members: + :show-inheritance: + +project.Widgets.PluginsScreen module +------------------------------------ + +.. automodule:: project.Widgets.PluginsScreen + :members: + :undoc-members: + :show-inheritance: + +project.Widgets.SettingsScreen module +------------------------------------- + +.. automodule:: project.Widgets.SettingsScreen + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project.Widgets + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/project.rst b/docs/source/project.rst new file mode 100644 index 00000000..107c24ed --- /dev/null +++ b/docs/source/project.rst @@ -0,0 +1,35 @@ +project package +=============== + +Subpackages +----------- + +.. toctree:: + + project.ClipboardManager + project.ConfigManager + project.PluginManager + project.Plugins + project.Stack + project.Widgets + project.tests + +Submodules +---------- + +project.utils module +-------------------- + +.. automodule:: project.utils + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/project.tests.rst b/docs/source/project.tests.rst new file mode 100644 index 00000000..420aac32 --- /dev/null +++ b/docs/source/project.tests.rst @@ -0,0 +1,22 @@ +project.tests package +===================== + +Submodules +---------- + +project.tests.test\_stack module +-------------------------------- + +.. automodule:: project.tests.test_stack + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: project.tests + :members: + :undoc-members: + :show-inheritance: diff --git a/project/Stack/Stack.py b/project/Stack/Stack.py index c00cdee8..697fbc30 100644 --- a/project/Stack/Stack.py +++ b/project/Stack/Stack.py @@ -17,9 +17,9 @@ class SHIFT_DIRECTION(enum.Enum): UP = 1 DOWN = 2 - def __init__(self, existing_stack=[], cur_stack_pointer=None): + def __init__(self, cur_stack_pointer=None): # Stack is backwards??? - self._stack = existing_stack + self._stack = [] if cur_stack_pointer: self._stack_pointer = cur_stack_pointer diff --git a/project/tests/test_example.py b/project/tests/test_example.py deleted file mode 100644 index 4890919e..00000000 --- a/project/tests/test_example.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -.. module:: utils - :synopsis: File containing constants and static functions. - -.. moduleauthor:: Bryan Kok -""" - -import pytest - - -@pytest.fixture -def error_fixture(): - assert 0 - - -def test_ok(): - print("ok") - - -def test_fail(): - assert 0 - - -def test_error(error_fixture): - pass - - -def test_skip(): - pytest.skip("skipping this test") - - -def test_xfail(): - pytest.xfail("xfailing this test") - - -@pytest.mark.xfail(reason="always xfail") -def test_xpass(): - pass diff --git a/project/tests/test_stack.py b/project/tests/test_stack.py new file mode 100644 index 00000000..5cd7dab5 --- /dev/null +++ b/project/tests/test_stack.py @@ -0,0 +1,73 @@ +""" +.. module:: test_stack.py + :synopsis: Unit tests for the stack, the core of this app. We should have started testing earlier, eh? + +.. moduleauthor:: Bryan Kok +""" +import pytest + +from project.Stack import Stack + + +@pytest.fixture(scope='function') +def clean_stack(): + return Stack() + + +def test_clear(clean_stack): + """Ensure that clear empties the stack.""" + _stack = clean_stack + for i in range(5): + _stack.push_item(i) + + assert (_stack.items_count() == 5) + + _stack.clear() + assert (_stack.items_count() == 0) + + +def test_push_items(clean_stack): + """Ensure that the stack retains pushed items""" + + _stack = clean_stack + _list = [1, 2, 'a', 'b', 'c'] + for _item in _list: + _stack.push_item(_item) + + assert (_stack.items_count() == 5) + assert (_stack.items() == _list) + _stack.clear() + + +def test_shift_item_down(clean_stack): + """Shifting an item down should not affect order of other items in stack""" + + _stack = clean_stack + _list = [1, 2, 'a', 'b', 'c', 3, 4, 5] + for _item in _list: + _stack.push_item(_item) + + _stack.set_current_item(3) # b + _stack.shift_current_item(Stack.SHIFT_DIRECTION.DOWN) + assert (_stack.items() == [1, 2, 'b', 'a', 'c', 3, 4, 5]) + + +def test_shift_item_up(clean_stack): + """Shifting an item up should not affect order of other items in stack""" + + _stack = clean_stack + _list = [1, 2, 'a', 'b', 'c', 3, 4, 5] + for _item in _list: + _stack.push_item(_item) + + _stack.set_current_item(3) # b + _stack.shift_current_item(Stack.SHIFT_DIRECTION.UP) + assert (_stack.items() == [1, 2, 'a', 'c', 'b', 3, 4, 5]) + + +def test_peek(clean_stack): + """The top of the stack should always be returned by peek""" + _stack = clean_stack + for _item in [1, 2, 3]: + _stack.push_item(_item) + assert (_stack.peek() == _item) From 5ead5a0cc3d2b2ac35692848a434d8858bd7f855 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Mon, 4 Mar 2019 04:05:14 +0800 Subject: [PATCH 59/60] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 72e73240..da701e46 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ A selected item, ① in the infographic below, has a different background color This may be useful if you want to organize your frequently accessed items at the top. Unchecking the `Always load top item into clipboard` option in the Settings menu will automatically copy the selected item into the system's clipboard. Saving the state of the clipboard is done automatically if the option in Settings is checked, or may be done manually in the File menu. + ![Screenshot of Clipboard Mangler on macOS Mojave](https://i.imgur.com/FbxCbjF.png) ## Documentation From 6a2a7ff6493bf3992f76d14b5b391a9ac2f023f7 Mon Sep 17 00:00:00 2001 From: Bryan Kok Date: Mon, 4 Mar 2019 04:10:25 +0800 Subject: [PATCH 60/60] Remove a stray Text.py --- project/Plugins/Text.py | 85 ----------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 project/Plugins/Text.py diff --git a/project/Plugins/Text.py b/project/Plugins/Text.py deleted file mode 100644 index 11f31a97..00000000 --- a/project/Plugins/Text.py +++ /dev/null @@ -1,85 +0,0 @@ -from random import randint, choice -import string - -quotes = [ - 'O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A-JO-ooo-oo-oo-oo', - '╠═══╣Lets build a ladder╠═══╣', - '( ͠° ͟ʖ ͡°) OVERCONFIDENCE IS A SLOW AND INSIDIOUS KILLER ( ͠° ͟ʖ ͡°)', - '┴┬┴┤( ͡° ͜ʖ├┬┴┬ HEY KIDS DO YOU WANT SOME DANK MEMES?', - "(▀̿Ĺ̯▀̿ ̿) This is the 0-3 Police, You're coming with us. (▀̿Ĺ̯▀̿ ̿)", - 'Born too late to explore the Earth, born too early to explore the universe, born perfectly to explore dank memes', - 'Hi, my name is Bill Gates and today I’ll teach you how to count to ten: 1, 2, 3, 95, 98, NT, 2000, XP, Vista, 7,\ - 8, 10', -] - -class Vars: - - times_appled = 0 - - -'''Use this function, not any other one. It as a 50/50 chance of applying each''' - - -def apply(text): - """First time coping, its normal, then it starts to go down hill....""" - Vars.times_appled = + 1 - if Vars.times_appled > 0 and Vars.times_appled < 2: - if randint(0, 5) == 5: - text = random_spelling_mistakes(text) - return text - else: - return text - elif Vars.times_appled > 2 and Vars.times_appled < 4: - if randint(0, 5) == 5: - text = random_spelling_mistakes(text) - return text - else: - text = quotify(text) - return text - elif Vars.times_appled > 4 and Vars.times_appled < 15: - if randint(0, 1) == 3: - text = random_spelling_mistakes(text) - return text - else: - text = quotify(text) - return text - - elif Vars.times_appled > 15: - text = quotify(text) - return text - else: - return text - - -def random_spelling_mistakes(text): - text = text.split() - new_words = '' - for word in text: - if len(word) == 1 or len(word) == 2: - final = ''.join(word) - new_words = new_words + ' ' + final - else: - spot = randint(0, len(word) - 1) - if spot == 0: - '''Give it two chances to not be 0, I think its better if its mostly the middle letters that get - removed''' - spot = randint(0, len(word) - 1) - if spot == 0: - pass - final = ''.join(word) - final = final[0:spot] + choice(string.ascii_letters) + final[spot:] - new_words = new_words + ' ' + final - return new_words - - -def quotify(text): - try: - text = quotes[randint(0, len(quotes))] - except IndexError: - try: - text = quotes[randint(0, len(quotes))] - except IndexError: - print("Error: (IndexError) in PredictiveText.py. Try'ed to quotify but failed") - return text - finally: - return text