commit 0a48dbecf9bdd32985a544cafa0f8f457b0f30f7 Author: 谢炜 Date: Thu Jun 2 16:27:58 2022 +0800 Import Upstream version 3.3.0.1.0519.1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..cda3b0c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,90 @@ +name: Check build + +on: + push: + branches: + - master + + pull_request: + branches: + - master + + schedule: + - cron: '0 0 * * *' + +jobs: + archlinux: + name: on Archlinux + runs-on: ubuntu-20.04 + container: docker.io/library/archlinux:latest + steps: + - name: Checkout ukui-sidebar source code + uses: actions/checkout@v2 + - name: Refresh pacman repository + run: pacman -Sy + - name: Install build dependencies + run: pacman -S --noconfirm base-devel qt5-base qt5-multimedia qt5-svg qt5-tools gsettings-qt dconf glib2 kwindowsystem glibc ruby-pkg-config libxrandr libxinerama libxcursor libxtst libx11 qt5-x11extras icu + - name: QMake configure & Make + run: | + mkdir build; + cd build; + qmake-qt5 ..; + make -j$(nproc); + + debian: + name: on Debian Sid + runs-on: ubuntu-20.04 + container: docker.io/library/debian:sid + env: + DEBIAN_FRONTEND: noninteractive + steps: + - name: Checkout ukui-sidebar source code + uses: actions/checkout@v2 + - name: Update apt repository + run: apt-get update -y + - name: Install build dependcies + run: apt-get install -y build-essential qttools5-dev-tools qtmultimedia5-dev libglib2.0-dev qtbase5-dev libqt5svg5-dev qttools5-dev-tools libgsettings-qt-dev libdconf-dev libkf5windowsystem-dev libburner-media3-1 gstreamer1.0-plugins-good gstreamer1.0-pulseaudio libqt5x11extras5-dev pkg-config libxrandr-dev libxinerama-dev libxcursor-dev libburner-media3-1 libxtst-dev + - name: QMake configure & Make + run: | + mkdir build; + cd build; + qmake ..; + make -j$(nproc); + + fedora: + name: on Fedora 32 + runs-on: ubuntu-20.04 + container: docker.io/library/fedora:32 + steps: + - name: Checkout ukui-sidebar source code + uses: actions/checkout@v2 + - name: Install curl and patch + run: dnf install --refresh -y curl patch + - name: Install build dependencies + run: dnf install -y which gcc gcc-c++ make cmake cmake-rpm-macros autoconf automake intltool rpm-build qt5-rpm-macros qt5-qtbase-devel qt5-qttools-devel glib2-devel qt5-qtbase-devel qt5-qtsvg-devel dconf-devel gsettings-qt-devel qt5-qtmultimedia-devel kf5-kwindowsystem-devel libXtst-devel qt5-qtx11extras-devel pkgconf-pkg-config libXrandr-devel libXinerama-devel libXcursor-devel gstreamer1-plugins-good-qt + - name: QMake configure & Make + run: | + mkdir build; + cd build; + qmake-qt5 ..; + make -j$(nproc); + + ubuntu: + name: on Ubuntu 20.04 + runs-on: ubuntu-20.04 + container: docker.io/library/ubuntu:focal + env: + DEBIAN_FRONTEND: noninteractive + steps: + - name: Checkout ukui-sidebar source code + uses: actions/checkout@v2 + - name: Update apt repository + run: apt-get update -y + - name: Install build dependcies + run: apt-get install -y build-essential qt5-default qttools5-dev-tools qtmultimedia5-dev libglib2.0-dev qtbase5-dev libqt5svg5-dev qttools5-dev-tools libgsettings-qt-dev libdconf-dev libkf5windowsystem-dev libburner-media3-1 gstreamer1.0-plugins-good gstreamer1.0-pulseaudio libqt5x11extras5-dev pkg-config libxrandr-dev libxinerama-dev libxcursor-dev libxtst-dev libburner-media3-1 + - name: QMake configure & Make + run: | + mkdir build; + cd build; + qmake ..; + make -j$(nproc); diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..84d29cb --- /dev/null +++ b/AUTHORS @@ -0,0 +1,7 @@ +ukui-sidebar authors +------------------ + +chenchunan +liushanwen + + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..74cd57b --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# ukui-sidebar + +![build](https://github.com/ukui/ukui-sidebar/workflows/Check%20build/badge.svg?branch=master) + +The sidebar mainly consists of two parts: notification center and cutting board. It starts from the start-up and is placed in the tray bar in the form of a tray. After clicking, it can pop up dynamically from the right side of the screen. + + + The notification center can display the pop-up messages sent by each application to mate notification teamon in a list form. Unimportant information can be stored in the storage box for viewing. At the same time, it can call the control panel directly. + + + + The main function of the clipboard is to save the latest cutting information, and display it under the sidebar in the form of a list. At the same time, it can also put the previous cutting information at the top, so that it can be pasted directly. In addition, it can record the cut text information as well as the URL. + +The ukui-sidebar is a shortcut tool on the right side of the screen for UKUI. + +# How to test notification-center +`notify-send -a wechat -i "/home/ccn/heart.png" Summary Body` + +# How to report bugs +Bugs should be reported to the UKUI bug tracking system: + + https://github.com/ukui/ukui-sidebar/issues + +You will need to create an account for yourself. + +Please read the HACKING file for information on where to send changes or +bugfixes for this package. + +# How to build +## Preparation +You can build pre-depends with such command: + +`sudo apt install libglib2.0-dev qtbase5-dev libqt5svg5-dev qttools5-dev-tools` + +Note: build-depends references the paragraph in debian/control. + +## Build from source and test + +> git clone https://github.com/ukui/ukui-sidebar + +> cd ukui-sidebar && mkdir build && cd build + +> qmake .. && make + +> sudo make install + +Note: If you want to run ukui-sidebar, you need to make some changes in the code after build. + + Find `libnotification_plugin.so` in your build path like `/home/XX/ukui-sidebar/build/src/plugins/notification_plugins`. Then set this path as pluginDir in file widget.cpp fuction `bool Widget::loadNotificationPlugin()`. + + + Find `libclipboardPlugin.so` in your build path like `/home/XX/ukui-sidebar/build/src/plugins/sidebar_pushbutton_plugins`. Then set this path as pluginDir in file pluginmanage.cpp fuction `PluginManager::PluginManager(QObject *parent) : QObject(parent)`. \ No newline at end of file diff --git a/man/ukui-sidebar.1 b/man/ukui-sidebar.1 new file mode 100644 index 0000000..d2e2bf0 --- /dev/null +++ b/man/ukui-sidebar.1 @@ -0,0 +1,22 @@ +.\" Man Page for ukui-sidebar +.TH UKUI-SIDEBAR 1 "2020-02-03" "UKUI Desktop Environment" +.\" Please adjust this date when revising the manpage. +.\" +.SH "NAME" +\fBukui-sidebar\fR \- SOME UKUI SHORTCUT OPERATION +.SH "SYNOPSIS" +.B ukui-sidebar [OPTIONS] +.SH "DESCRIPTION" +some shortcut operation in the right of screen for UKUI. +.SH "OPTIONS" +.TP +\fB\-v, \-\-version\fR +Output version information and exit. +.SH "BUGS" +.SS Should you encounter any bugs, they may be reported at: +http://github.com/ukui-desktop/ukui-sidebar/issues +.SH "AUTHORS" +.SS This Manual Page has been written for the UKUI Desktop Environment by: +Adam Erdman (2014) +.SH "SEE ALSO" +.SS Further information may also be available at: http://wiki.ukui-desktop.org/docs diff --git a/src/customstyle.cpp b/src/customstyle.cpp new file mode 100644 index 0000000..c1b44ca --- /dev/null +++ b/src/customstyle.cpp @@ -0,0 +1,257 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +CustomStyle::CustomStyle(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) +{ + +} + +void CustomStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + switch (control) { + case CC_ToolButton: + { + if (const QStyleOptionToolButton *toolbutton + = qstyleoption_cast(option)) { + QRect button, menuarea,rect; + button = proxy()->subControlRect(control, toolbutton, SC_ToolButton, widget); + menuarea = proxy()->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget); + rect = proxy()->subControlRect(CC_ToolButton,toolbutton,SC_None,widget); + + State bflags = toolbutton->state & ~State_Sunken; + + if (bflags & State_AutoRaise) { + if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) { + bflags &= ~State_Raised; + } + } + State mflags = bflags; + if (toolbutton->state & State_Sunken) { + if (toolbutton->activeSubControls & SC_ToolButton) + bflags |= State_Sunken; + mflags |= State_Sunken; + } + + QStyleOption tool = *toolbutton; + tool.state = bflags; + if(mflags & (State_Sunken | State_MouseOver)) + { + tool.state = mflags; + } + tool.rect = rect; + proxy()->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget); + + if (toolbutton->state & State_HasFocus) { + QStyleOptionFocusRect fr; + fr.QStyleOption::operator=(*toolbutton); + fr.rect.adjust(3, 3, -3, -3); + if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup) + fr.rect.adjust(0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, + toolbutton, widget), 0); + proxy()->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget); + } + QStyleOptionToolButton label = *toolbutton; + label.state = bflags; + label.rect = button; + proxy()->drawControl(CE_ToolButtonLabel, &label, painter, widget); + + if (toolbutton->subControls & SC_ToolButtonMenu) { + tool.rect = menuarea; + tool.state = mflags; + proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget); + } + } + break; + } + default:break; + } + return QProxyStyle::drawComplexControl(control, option, painter, widget); +} + +void CustomStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case QStyle::CE_PushButton: { + QStyleOptionButton button = *qstyleoption_cast(option); + button.palette.setColor(QPalette::HighlightedText, button.palette.buttonText().color()); + return QProxyStyle::drawControl(element, option, painter, widget); + break; + } + case CE_ToolButtonLabel:{ + QStyleOptionToolButton toolButton = *qstyleoption_cast(option); + toolButton.palette.setColor(QPalette::HighlightedText, toolButton.palette.windowText().color()); + return QProxyStyle::drawControl(element, &toolButton, painter, widget); + break; + } + default: + break; + } + return QProxyStyle::drawControl(element, option, painter, widget); +} +//UKUI ToolBar item style +void CustomStyle::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +} + +void CustomStyle::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +} + +void CustomStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) + { + case PE_PanelButtonTool: + { + if(!(option->state & State_Enabled)) { + painter->save(); + painter->setPen(Qt::NoPen); + painter->setBrush(option->palette.color(QPalette::Disabled,QPalette::Button)); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->drawRoundedRect(option->rect,4,4); + painter->restore(); + return; + } + painter->save(); + painter->setPen(Qt::NoPen); + painter->setBrush(option->palette.color(QPalette::WindowText)); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setOpacity(0.04); + if (option->state & (State_Sunken | State_On)) { + painter->setOpacity(0.08); + } + else if(option->state & State_MouseOver) { + painter->setOpacity(0.12); + } + painter->drawRoundedRect(option->rect,4,4); + painter->restore(); + return; + } + default: + break; + } + return QProxyStyle::drawPrimitive(element, option, painter, widget); +} + +QPixmap CustomStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl CustomStyle::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +{ + return QProxyStyle::hitTestComplexControl(control, option, position, widget); +} + +QRect CustomStyle::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +} + +QRect CustomStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +{ + return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +} + +int CustomStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::pixelMetric(metric, option, widget); +} + +void CustomStyle::polish(QWidget *widget) +{ + return QProxyStyle::polish(widget); +} + +void CustomStyle::polish(QApplication *application) +{ + return QProxyStyle::polish(application); +} + +void CustomStyle::polish(QPalette &palette) +{ + return QProxyStyle::polish(palette); +} + +void CustomStyle::unpolish(QWidget *widget) +{ + return QProxyStyle::unpolish(widget); +} + +void CustomStyle::unpolish(QApplication *application) +{ + return QProxyStyle::unpolish(application); +} + +QSize CustomStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} + +QIcon CustomStyle::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::standardIcon(standardIcon, option, widget); +} + +QPalette CustomStyle::standardPalette() const +{ + return QProxyStyle::standardPalette(); +} + +int CustomStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +QRect CustomStyle::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +{ + return QProxyStyle::subControlRect(control, option, subControl, widget); +} + +QRect CustomStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::subElementRect(element, option, widget); +} diff --git a/src/customstyle.h b/src/customstyle.h new file mode 100644 index 0000000..3913c14 --- /dev/null +++ b/src/customstyle.h @@ -0,0 +1,150 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + + +// * \brief The CustomStyle class +// * \details +// * 自定义QStyle +// * 基于QProxyStyle,默认使用QProxyStyle的实例绘制控件,你需要针对某一个控件重新实现若干对应的接口。 +// * QProxyStyle可以从现有的qt style实例化,我们只需要知道这个style的名字即可。 +// * 这种做法带来了不错的扩展性和自由度,因为我们不需要将某个style的代码直接引入我们的项目中, +// * 也能够“继承”这个style类进行二次开发。 +// * +// * 下面的方法展现了QStyle的所有的接口,使用QStyle进行控件的绘制使得qt应用能够进行风格的切换, +// * 从而达到不修改项目源码却对应用外观产生巨大影响的效果。 +// * +// * \note +// * 需要注意QStyle与QSS并不兼容,因为QSS本身其实上也是QStyle的一种实现,对一个控件而言,本身理论上只能 +// * 在同一时间调用唯一一个QStyle进行绘制。 + +class CustomStyle : public QProxyStyle +{ + Q_OBJECT +public: + explicit CustomStyle(const QString &proxyStyleName = "windows", QObject *parent = nullptr); + +// * \brief drawComplexControl +// * \param control 比如ScrollBar,对应CC枚举类型 +// * \param option +// * \param painter +// * \param widget +// * \details +// * drawComplexControl用于绘制具有子控件的复杂控件,它本身一般不直接绘制控件, +// * 而是通过QStyle的其它方法将复杂控件分解成子控件再调用其它的draw方法绘制。 +// * 如果你需要重新实现一个复杂控件的绘制方法,首先考虑的应该是在不改变它原有的绘制流程的情况下, +// * 对它调用到的其它方法进行重写。 +// * +// * 如果你不想使用原有的绘制流程,那你需要重写这个接口,然后自己实现一切, +// * 包括背景的绘制,子控件的位置和状态计算,子控件的绘制等。 +// * 所以,你需要对这个控件有足够的了解之后再尝试直接重写这个接口。 + + virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + +// * \brief drawControl +// * \param element 比如按钮,对应CE枚举类型 +// * \param option +// * \param painter +// * \param widget +// * \details +// * drawControl用于绘制基本控件元素,它本身一般只负责绘制控件的一部分或者一层。 +// * 如果你想要知道控件具体如何绘制,你需要同时研究这个控件的源码和QStyle中的源码, +// * 因为它们都有可能改变控件的绘制流程。 +// * +// * QStyle一般会遵循QCommonStyle的绘制流程,QCommenStyle是大部分主流style的最基类, +// * 它本身不能完全称之为一个主题,如果你直接使用它,你的控件将不能被正常绘制,因为它有可能只是 +// * 在特定的时候执行了特定却未实现的绘制方法,它更像一个框架或者规范。 + + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + +// * \brief drawPrimitive +// * \param element 背景绘制,对应PE枚举类型 +// * \param option +// * \param painter +// * \param widget +// * \details +// * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, +// * 我们一般需要判断控件的状态来绘制不同的背景, +// * 比如按钮的hover和点击效果。 + + virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; + virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; + virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; + virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + +// * \brief polish +// * \param widget +// * \details +// * polish用于对widget进行预处理,一般我们可以在polish中修改其属性, +// * 另外,polish是对动画和特效实现而言十分重要的一个方法, +// * 通过polish我们能够使widget和特效和动画形成对应关系。 + + virtual void polish(QWidget *widget); + virtual void polish(QApplication *application); + virtual void polish(QPalette &palette); + virtual void unpolish(QWidget *widget); + virtual void unpolish(QApplication *application); + + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + virtual QPalette standardPalette() const; + +// * \brief styleHint +// * \param hint 对应的枚举是SH +// * \param option +// * \param widget +// * \param returnData +// * \return +// * \details +// * styleHint比较特殊,通过它我们能够改变一些控件的绘制流程或者方式,比如说QMenu是否可以滚动。 + + virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; + +// * \brief subControlRect +// * \param control +// * \param option +// * \param subControl +// * \param widget +// * \return +// * \details +// * subControlRect返回子控件的位置和大小信息,这个方法一般在内置流程中调用, +// * 如果我们要重写某个绘制方法,可能需要用到它 + + virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; + +// * \brief subElementRect +// * \param element +// * \param option +// * \param widget +// * \return +// * \details +// * 与subControlRect类似 + + virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; + +}; + +#endif // CUSTOMSTYLE_H diff --git a/src/customstyleCleanPushbutton.cpp b/src/customstyleCleanPushbutton.cpp new file mode 100644 index 0000000..59fb063 --- /dev/null +++ b/src/customstyleCleanPushbutton.cpp @@ -0,0 +1,187 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +#include +#include + +#include + +customstyle_clean_pushbutton::customstyle_clean_pushbutton(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) +{ + Q_UNUSED(parent); +} + +void customstyle_clean_pushbutton::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + return QProxyStyle::drawComplexControl(control, option, painter, widget); +} + +void customstyle_clean_pushbutton::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case QStyle::CE_PushButton: { + QStyleOptionButton button = *qstyleoption_cast(option); + button.palette.setColor(QPalette::HighlightedText, button.palette.buttonText().color()); + return QProxyStyle::drawControl(element, &button, painter, widget); + break; + } + default: + break; + } + return QProxyStyle::drawControl(element, option, painter, widget); +} + +void customstyle_clean_pushbutton::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +} + +void customstyle_clean_pushbutton::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +} + +/// 我们重写button的绘制方法,通过state和当前动画的状态以及value值改变相关的绘制条件 +/// 这里通过判断hover与否,动态的调整painter的透明度然后绘制背景 +/// 需要注意的是,默认控件的绘制流程只会触发一次,而动画需要我们在一段时间内不停绘制才行, +/// 要使得动画能够持续,我们需要使用QWidget::update()在动画未完成时, +/// 手动更新一次,这样button将在一段时间后再次调用draw方法,从而达到更新动画的效果 +/// +/// 需要注意绘制背景的流程会因主题不同而产生差异,所以这一部分代码在一些主题中未必正常, +/// 如果你需要自己实现一个主题,这同样是你需要注意和考虑的点 +void customstyle_clean_pushbutton::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + if (element == PE_PanelButtonCommand) { + if (widget) { + if (option->state & State_MouseOver) { + if (option->state & State_Sunken) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,21); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,0); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,0); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + return; + } + } + return QProxyStyle::drawPrimitive(element, option, painter, widget); +} + +QPixmap customstyle_clean_pushbutton::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl customstyle_clean_pushbutton::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +{ + return QProxyStyle::hitTestComplexControl(control, option, position, widget); +} + +QRect customstyle_clean_pushbutton::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +} + +QRect customstyle_clean_pushbutton::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +{ + return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +} + +int customstyle_clean_pushbutton::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::pixelMetric(metric, option, widget); +} + +/// 我们需要将动画与widget一一对应起来, +/// 在一个style的生命周期里,widget只会进行polish和unpolish各一次, +/// 所以我们可以在polish时将widget与一个新的动画绑定,并且对应的在unpolish中解绑定 +void customstyle_clean_pushbutton::polish(QWidget *widget) +{ + return QProxyStyle::polish(widget); +} + +void customstyle_clean_pushbutton::polish(QApplication *application) +{ + return QProxyStyle::polish(application); +} + +void customstyle_clean_pushbutton::polish(QPalette &palette) +{ + return QProxyStyle::polish(palette); +} + +void customstyle_clean_pushbutton::unpolish(QWidget *widget) +{ + return QProxyStyle::unpolish(widget); +} + +void customstyle_clean_pushbutton::unpolish(QApplication *application) +{ + return QProxyStyle::unpolish(application); +} + +QSize customstyle_clean_pushbutton::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} + +QIcon customstyle_clean_pushbutton::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::standardIcon(standardIcon, option, widget); +} + +QPalette customstyle_clean_pushbutton::standardPalette() const +{ + return QProxyStyle::standardPalette(); +} + +int customstyle_clean_pushbutton::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +QRect customstyle_clean_pushbutton::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +{ + return QProxyStyle::subControlRect(control, option, subControl, widget); +} + +QRect customstyle_clean_pushbutton::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::subElementRect(element, option, widget); +} diff --git a/src/customstyleCleanPushbutton.h b/src/customstyleCleanPushbutton.h new file mode 100644 index 0000000..9aa4a8f --- /dev/null +++ b/src/customstyleCleanPushbutton.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +class customstyle_clean_pushbutton : public QProxyStyle +{ + Q_OBJECT +public: + explicit customstyle_clean_pushbutton(const QString &proxyStyleName = "windows", QObject *parent = nullptr); + virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + /*! + * \brief drawPrimitive + * \param element 背景绘制,对应PE枚举类型 + * \param option + * \param painter + * \param widget + * \details + * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, + * 我们一般需要判断控件的状态来绘制不同的背景, + * 比如按钮的hover和点击效果。 + */ + virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; + virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; + virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; + //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); + virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + + virtual void polish(QWidget *widget); + virtual void polish(QApplication *application); + virtual void polish(QPalette &palette); + virtual void unpolish(QWidget *widget); + virtual void unpolish(QApplication *application); + + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + virtual QPalette standardPalette() const; + virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; + + virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; + + virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; + +signals: + +public slots: + +private: +}; + +#endif // CUSTOMSTYLE_CLEAN_PUSHBUTTON_H diff --git a/src/data/images/application-menu.svg b/src/data/images/application-menu.svg new file mode 100644 index 0000000..9bf6e17 --- /dev/null +++ b/src/data/images/application-menu.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/src/data/images/kylin-alarm-clock.svg b/src/data/images/kylin-alarm-clock.svg new file mode 100644 index 0000000..db3a197 --- /dev/null +++ b/src/data/images/kylin-alarm-clock.svg @@ -0,0 +1,57 @@ + + + +画板 18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/data/images/kylin-feedback.png b/src/data/images/kylin-feedback.png new file mode 100644 index 0000000..24eeda8 Binary files /dev/null and b/src/data/images/kylin-feedback.png differ diff --git a/src/data/images/kylin-notebook.svg b/src/data/images/kylin-notebook.svg new file mode 100644 index 0000000..a77e749 --- /dev/null +++ b/src/data/images/kylin-notebook.svg @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/data/images/kylin-tool-box-null.svg b/src/data/images/kylin-tool-box-null.svg new file mode 100644 index 0000000..8185a20 --- /dev/null +++ b/src/data/images/kylin-tool-box-null.svg @@ -0,0 +1 @@ +通知中心-新消息 \ No newline at end of file diff --git a/src/data/images/kylin-tool-box.svg b/src/data/images/kylin-tool-box.svg new file mode 100644 index 0000000..ccc3ea7 --- /dev/null +++ b/src/data/images/kylin-tool-box.svg @@ -0,0 +1 @@ +通知中心-普通 \ No newline at end of file diff --git a/src/data/org.ukui.log4qt.ukui-sidebar.gschema.xml b/src/data/org.ukui.log4qt.ukui-sidebar.gschema.xml new file mode 100644 index 0000000..8c9476a --- /dev/null +++ b/src/data/org.ukui.log4qt.ukui-sidebar.gschema.xml @@ -0,0 +1,39 @@ + + + + "true" + hook qt messages + Control if hook qt messages + + + "DEBUG,console,daily" + config rootLogger's level and appenders + config rootLogger's level and appenders:"level,appender" + + + ".yyyy-MM-dd" + daily log file pattern + set daily log file pattern format:one day + + + "%d{yyyy-MM-dd HH:mm:ss,zzz}(%-4r)[%t]|%-5p| - %m%n" + set log message's format + set log message's format + + + 3600 + set check log files delay time + set check log files delay time + + + 7 + set log files count + set log files count,unit s + + + 512 + set log files total size + set log files total size, unit M + + + diff --git a/src/data/org.ukui.sidebar.gschema.xml b/src/data/org.ukui.sidebar.gschema.xml new file mode 100644 index 0000000..701f8f4 --- /dev/null +++ b/src/data/org.ukui.sidebar.gschema.xml @@ -0,0 +1,10 @@ + + + + false + remind + remind + + + + diff --git a/src/data/qss/SidebarSmallPlugins.css b/src/data/qss/SidebarSmallPlugins.css new file mode 100644 index 0000000..09d0288 --- /dev/null +++ b/src/data/qss/SidebarSmallPlugins.css @@ -0,0 +1,41 @@ +QPushButton#SidebarPluginButton:hover{ + width:90px; + height:34px; + background:rgba(61,107,229,0); + border-radius:4px; +} + +QPushButton#SidebarPluginButton:pressed { + background-color:rgba(255,255,255,0.08); /*改变背景色*/ + opacity:0.08; + border: 0px solid rgba(255,0,0,1); +} + +QPushButton#ClipboardButton:hover{ + width:90px; + height:34px; + background:rgba(61,107,229,0); + border-radius:4px; +} + +QPushButton#ClipboardButton:pressed{ + width:90px; + height:34px; + background:rgba(61,107,229,0); + border-radius:4px; +} + +QPushButton#BlueBackgroundButton{ + width:90px; + height:34px; + background:rgba(61,107,229,1); + border-radius:4px; +} + +QToolButton{ + font-size:14px; + font-family:Noto Sans CJK SC; + font-weight:400; + color:rgba(255,255,255,1); + line-height:34px; +} diff --git a/src/data/qss/psblack.css b/src/data/qss/psblack.css new file mode 100644 index 0000000..01f1e4a --- /dev/null +++ b/src/data/qss/psblack.css @@ -0,0 +1,632 @@ +QPalette{background:#444444;}*{outline:0px;color:#DCDCDC;} + +QWidget[form="true"],QLabel[frameShape="1"]{ +border:1px solid #242424; +border-radius:0px; +} + +QWidget[form="bottom"]{ +background:#484848; +} + +QWidget[form="bottom"] .QFrame{ +border:1px solid #DCDCDC; +} + +QWidget[form="bottom"] QLabel,QWidget[form="title"] QLabel{ +border-radius:0px; +color:#DCDCDC; +background:none; +border-style:none; +} + +QWidget[form="title"],QWidget[nav="left"],QWidget[nav="top"] QAbstractButton{ +border-style:none; +border-radius:0px; +padding:5px; +color:#DCDCDC; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +QWidget[nav="top"] QAbstractButton:hover,QWidget[nav="top"] QAbstractButton:pressed,QWidget[nav="top"] QAbstractButton:checked{ +border-style:solid; +border-width:0px 0px 2px 0px; +padding:4px 4px 2px 4px; +border-color:#00BB9E; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #646464,stop:1 #525252); +} + +QWidget[nav="left"] QAbstractButton{ +border-radius:0px; +color:#DCDCDC; +background:none; +border-style:none; +} + +QWidget[nav="left"] QAbstractButton:hover{ +color:#FFFFFF; +background-color:#00BB9E; +} + +QWidget[nav="left"] QAbstractButton:checked,QWidget[nav="left"] QAbstractButton:pressed{ +color:#DCDCDC; +border-style:solid; +border-width:0px 0px 0px 2px; +padding:4px 4px 4px 2px; +border-color:#00BB9E; +background-color:#444444; +} + +QWidget[video="true"] QLabel{ +color:#DCDCDC; +border:1px solid #242424; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +QWidget[video="true"] QLabel:focus{ +border:1px solid #00BB9E; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #646464,stop:1 #525252); +} + +QLineEdit,QTextEdit,QPlainTextEdit,QSpinBox,QDoubleSpinBox,QComboBox,QDateEdit,QTimeEdit,QDateTimeEdit{ +border:1px solid #242424; +border-radius:3px; +padding:2px; +background:none; +selection-background-color:#484848; +selection-color:#DCDCDC; +} + +QLineEdit:focus,QTextEdit:focus,QPlainTextEdit:focus,QSpinBox:focus,QDoubleSpinBox:focus,QComboBox:focus,QDateEdit:focus,QTimeEdit:focus,QDateTimeEdit:focus,QLineEdit:hover,QTextEdit:hover,QPlainTextEdit:hover,QSpinBox:hover,QDoubleSpinBox:hover,QComboBox:hover,QDateEdit:hover,QTimeEdit:hover,QDateTimeEdit:hover{ +border:1px solid #242424; +} + +QLineEdit[echoMode="2"]{ +lineedit-password-character:9679; +} + +.QFrame{ +border:1px solid #242424; +border-radius:3px; +} + +.QGroupBox{ +border:1px solid #242424; +border-radius:5px; +margin-top:3ex; +} + +.QGroupBox::title{ +subcontrol-origin:margin; +position:relative; +left:10px; +} + +.QPushButton,.QToolButton{ +border-style:none; +border:1px solid #242424; +color:#DCDCDC; +padding:5px; +min-height:15px; +border-radius:5px; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +.QPushButton:hover,.QToolButton:hover{ +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #646464,stop:1 #525252); +} + +.QPushButton:pressed,.QToolButton:pressed{ +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +.QToolButton::menu-indicator{ +image:None; +} + +QToolButton#btnMenu,QPushButton#btnMenu_Min,QPushButton#btnMenu_Max,QPushButton#btnMenu_Close{ +border-radius:3px; +color:#DCDCDC; +padding:3px; +margin:0px; +background:none; +border-style:none; +} + +QToolButton#btnMenu:hover,QPushButton#btnMenu_Min:hover,QPushButton#btnMenu_Max:hover{ +color:#FFFFFF; +margin:1px 1px 2px 1px; +background-color:rgba(51,127,209,230); +} + +QPushButton#btnMenu_Close:hover{ +color:#FFFFFF; +margin:1px 1px 2px 1px; +background-color:rgba(238,0,0,128); +} + +QRadioButton::indicator{ +width:15px; +height:15px; +} + +QRadioButton::indicator::unchecked{ +image:url(:/qss/psblack/radiobutton_unchecked.png); +} + +QRadioButton::indicator::unchecked:disabled{ +image:url(:/qss/psblack/radiobutton_unchecked_disable.png); +} + +QRadioButton::indicator::checked{ +image:url(:/qss/psblack/radiobutton_checked.png); +} + +QRadioButton::indicator::checked:disabled{ +image:url(:/qss/psblack/radiobutton_checked_disable.png); +} + +QGroupBox::indicator,QTreeWidget::indicator,QListWidget::indicator{ +padding:0px -3px 0px 3px; +} + +QCheckBox::indicator,QGroupBox::indicator,QTreeWidget::indicator,QListWidget::indicator{ +width:13px; +height:13px; +} + +QCheckBox::indicator:unchecked,QGroupBox::indicator:unchecked,QTreeWidget::indicator:unchecked,QListWidget::indicator:unchecked{ +image:url(:/qss/psblack/checkbox_unchecked.png); +} + +QCheckBox::indicator:unchecked:disabled,QGroupBox::indicator:unchecked:disabled,QTreeWidget::indicator:unchecked:disabled,QListWidget::indicator:disabled{ +image:url(:/qss/psblack/checkbox_unchecked_disable.png); +} + +QCheckBox::indicator:checked,QGroupBox::indicator:checked,QTreeWidget::indicator:checked,QListWidget::indicator:checked{ +image:url(:/qss/psblack/checkbox_checked.png); +} + +QCheckBox::indicator:checked:disabled,QGroupBox::indicator:checked:disabled,QTreeWidget::indicator:checked:disabled,QListWidget::indicator:checked:disabled{ +image:url(:/qss/psblack/checkbox_checked_disable.png); +} + +QCheckBox::indicator:indeterminate,QGroupBox::indicator:indeterminate,QTreeWidget::indicator:indeterminate,QListWidget::indicator:indeterminate{ +image:url(:/qss/psblack/checkbox_parcial.png); +} + +QCheckBox::indicator:indeterminate:disabled,QGroupBox::indicator:indeterminate:disabled,QTreeWidget::indicator:indeterminate:disabled,QListWidget::indicator:indeterminate:disabled{ +image:url(:/qss/psblack/checkbox_parcial_disable.png); +} + +QTimeEdit::up-button,QDateEdit::up-button,QDateTimeEdit::up-button,QDoubleSpinBox::up-button,QSpinBox::up-button{ +image:url(:/qss/psblack/add_top.png); +width:10px; +height:10px; +padding:2px 5px 0px 0px; +} + +QTimeEdit::down-button,QDateEdit::down-button,QDateTimeEdit::down-button,QDoubleSpinBox::down-button,QSpinBox::down-button{ +image:url(:/qss/psblack/add_bottom.png); +width:10px; +height:10px; +padding:0px 5px 2px 0px; +} + +QTimeEdit::up-button:pressed,QDateEdit::up-button:pressed,QDateTimeEdit::up-button:pressed,QDoubleSpinBox::up-button:pressed,QSpinBox::up-button:pressed{ +top:-2px; +} + +QTimeEdit::down-button:pressed,QDateEdit::down-button:pressed,QDateTimeEdit::down-button:pressed,QDoubleSpinBox::down-button:pressed,QSpinBox::down-button:pressed,QSpinBox::down-button:pressed{ +bottom:-2px; +} + +QComboBox::down-arrow,QDateEdit[calendarPopup="true"]::down-arrow,QTimeEdit[calendarPopup="true"]::down-arrow,QDateTimeEdit[calendarPopup="true"]::down-arrow{ +image:url(:/qss/psblack/add_bottom.png); +width:10px; +height:10px; +right:2px; +} + +QComboBox::drop-down,QDateEdit::drop-down,QTimeEdit::drop-down,QDateTimeEdit::drop-down{ +subcontrol-origin:padding; +subcontrol-position:top right; +width:15px; +border-left-width:0px; +border-left-style:solid; +border-top-right-radius:3px; +border-bottom-right-radius:3px; +border-left-color:#242424; +} + +QComboBox::drop-down:on{ +top:1px; +} + +QMenuBar::item{ +color:#DCDCDC; +background-color:#484848; +margin:0px; +padding:3px 10px; +} + +QMenu,QMenuBar,QMenu:disabled,QMenuBar:disabled{ +color:#DCDCDC; +background-color:#484848; +border:1px solid #242424; +margin:0px; +} + +QMenu::item{ +padding:3px 20px; +} + +QMenu::indicator{ +width:13px; +height:13px; +} + +QMenu::item:selected,QMenuBar::item:selected{ +color:#DCDCDC; +border:0px solid #242424; +background:#646464; +} + +QMenu::separator{ +height:1px; +background:#242424; +} + +QProgressBar{ +min-height:10px; +background:#484848; +border-radius:5px; +text-align:center; +border:1px solid #484848; +} + +QProgressBar:chunk{ +border-radius:5px; +background-color:#242424; +} + +QSlider::groove:horizontal{ +background:#484848; +height:8px; +border-radius:4px; +} + +QSlider::add-page:horizontal{ +background:#484848; +height:8px; +border-radius:4px; +} + +QSlider::sub-page:horizontal{ +background:#242424; +height:8px; +border-radius:4px; +} + +QSlider::handle:horizontal{ +width:13px; +margin-top:-3px; +margin-bottom:-3px; +border-radius:6px; +background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 #444444,stop:0.8 #242424); +} + +QSlider::groove:vertical{ +width:8px; +border-radius:4px; +background:#484848; +} + +QSlider::add-page:vertical{ +width:8px; +border-radius:4px; +background:#484848; +} + +QSlider::sub-page:vertical{ +width:8px; +border-radius:4px; +background:#242424; +} + +QSlider::handle:vertical{ +height:14px; +margin-left:-3px; +margin-right:-3px; +border-radius:6px; +background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 #444444,stop:0.8 #242424); +} + +QScrollBar:horizontal{ +background:#484848; +padding:0px; +border-radius:6px; +max-height:12px; +} + +QScrollBar::handle:horizontal{ +background:#242424; +min-width:50px; +border-radius:6px; +} + +QScrollBar::handle:horizontal:hover{ +background:#00BB9E; +} + +QScrollBar::handle:horizontal:pressed{ +background:#00BB9E; +} + +QScrollBar::add-page:horizontal{ +background:none; +} + +QScrollBar::sub-page:horizontal{ +background:none; +} + +QScrollBar::add-line:horizontal{ +background:none; +} + +QScrollBar::sub-line:horizontal{ +background:none; +} + +QScrollBar:vertical{ +background:#484848; +padding:0px; +border-radius:6px; +max-width:12px; +} + +QScrollBar::handle:vertical{ +background:#242424; +min-height:50px; +border-radius:6px; +} + +QScrollBar::handle:vertical:hover{ +background:#00BB9E; +} + +QScrollBar::handle:vertical:pressed{ +background:#00BB9E; +} + +QScrollBar::add-page:vertical{ +background:none; +} + +QScrollBar::sub-page:vertical{ +background:none; +} + +QScrollBar::add-line:vertical{ +background:none; +} + +QScrollBar::sub-line:vertical{ +background:none; +} + +QScrollArea{ +border:0px; +} + +QTreeView,QListView,QTableView,QTabWidget::pane{ +border:1px solid #242424; +selection-background-color:#646464; +selection-color:#DCDCDC; +alternate-background-color:#525252; +gridline-color:#242424; +} + +QTreeView::branch:closed:has-children{ +margin:4px; +border-image:url(:/qss/psblack/branch_open.png); +} + +QTreeView::branch:open:has-children{ +margin:4px; +border-image:url(:/qss/psblack/branch_close.png); +} + +QTreeView,QListView,QTableView,QSplitter::handle,QTreeView::branch{ +background:#444444; +} + +QTableView::item:selected,QListView::item:selected,QTreeView::item:selected{ +color:#DCDCDC; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +QTableView::item:hover,QListView::item:hover,QTreeView::item:hover{ +color:#DCDCDC; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #646464,stop:1 #525252); +} + +QTableView::item,QListView::item,QTreeView::item{ +padding:1px; +margin:0px; +} + +QHeaderView::section,QTableCornerButton:section{ +padding:3px; +margin:0px; +color:#DCDCDC; +border:1px solid #242424; +border-left-width:0px; +border-right-width:1px; +border-top-width:0px; +border-bottom-width:1px; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #646464,stop:1 #525252); +} + +QTabBar::tab{ +border:1px solid #242424; +color:#DCDCDC; +margin:0px; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #646464,stop:1 #525252); +} + +QTabBar::tab:selected,QTabBar::tab:hover{ +border-style:solid; +border-color:#00BB9E; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +QTabBar::tab:top,QTabBar::tab:bottom{ +padding:3px 8px 3px 8px; +} + +QTabBar::tab:left,QTabBar::tab:right{ +padding:8px 3px 8px 3px; +} + +QTabBar::tab:top:selected,QTabBar::tab:top:hover{ +border-width:2px 0px 0px 0px; +} + +QTabBar::tab:right:selected,QTabBar::tab:right:hover{ +border-width:0px 0px 0px 2px; +} + +QTabBar::tab:bottom:selected,QTabBar::tab:bottom:hover{ +border-width:0px 0px 2px 0px; +} + +QTabBar::tab:left:selected,QTabBar::tab:left:hover{ +border-width:0px 2px 0px 0px; +} + +QTabBar::tab:first:top:selected,QTabBar::tab:first:top:hover,QTabBar::tab:first:bottom:selected,QTabBar::tab:first:bottom:hover{ +border-left-width:1px; +border-left-color:#242424; +} + +QTabBar::tab:first:left:selected,QTabBar::tab:first:left:hover,QTabBar::tab:first:right:selected,QTabBar::tab:first:right:hover{ +border-top-width:1px; +border-top-color:#242424; +} + +QTabBar::tab:last:top:selected,QTabBar::tab:last:top:hover,QTabBar::tab:last:bottom:selected,QTabBar::tab:last:bottom:hover{ +border-right-width:1px; +border-right-color:#242424; +} + +QTabBar::tab:last:left:selected,QTabBar::tab:last:left:hover,QTabBar::tab:last:right:selected,QTabBar::tab:last:right:hover{ +border-bottom-width:1px; +border-bottom-color:#242424; +} + +QStatusBar::item{ +border:0px solid #484848; +border-radius:3px; +} + +QPrintPreviewDialog QToolButton{ +border:0px solid #DCDCDC; +border-radius:0px; +margin:0px; +padding:3px; +background:none; +} + +QToolBox::tab,QGroupBox#gboxDevicePanel,QGroupBox#gboxDeviceTitle,QFrame#gboxDevicePanel,QFrame#gboxDeviceTitle{ +padding:3px; +border-radius:5px; +color:#DCDCDC; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +QColorDialog QPushButton,QFileDialog QPushButton{ +min-width:80px; +} + +QToolButton#qt_calendar_prevmonth{ +icon-size:0px; +min-width:20px; +image:url(:/qss/psblack/calendar_prevmonth.png); +} + +QToolButton#qt_calendar_nextmonth{ +icon-size:0px; +min-width:20px; +image:url(:/qss/psblack/calendar_nextmonth.png); +} + +QToolButton#qt_calendar_prevmonth,QToolButton#qt_calendar_nextmonth,QToolButton#qt_calendar_monthbutton,QToolButton#qt_calendar_yearbutton{ +border:0px solid #DCDCDC; +border-radius:3px; +margin:3px 3px 3px 3px; +padding:3px; +background:none; +} + +QToolButton#qt_calendar_prevmonth:hover,QToolButton#qt_calendar_nextmonth:hover,QToolButton#qt_calendar_monthbutton:hover,QToolButton#qt_calendar_yearbutton:hover,QToolButton#qt_calendar_prevmonth:pressed,QToolButton#qt_calendar_nextmonth:pressed,QToolButton#qt_calendar_monthbutton:pressed,QToolButton#qt_calendar_yearbutton:pressed{ +border:1px solid #242424; +} + +QCalendarWidget QSpinBox#qt_calendar_yearedit{ +margin:2px; +} + +QCalendarWidget QToolButton::menu-indicator{ +image:None; +} + +QCalendarWidget QTableView{ +border-width:0px; +} + +QCalendarWidget QWidget#qt_calendar_navigationbar{ +border:1px solid #242424; +border-width:1px 1px 0px 1px; +background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #484848,stop:1 #383838); +} + +QComboBox QAbstractItemView::item{ +min-height:20px; +min-width:10px; +} + +QTableView[model="true"]::item{ +padding:0px; +margin:0px; +} + +QTableView QLineEdit,QTableView QComboBox,QTableView QSpinBox,QTableView QDoubleSpinBox,QTableView QDateEdit,QTableView QTimeEdit,QTableView QDateTimeEdit{ +border-width:0px; +border-radius:0px; +} + +QTableView QLineEdit:focus,QTableView QComboBox:focus,QTableView QSpinBox:focus,QTableView QDoubleSpinBox:focus,QTableView QDateEdit:focus,QTableView QTimeEdit:focus,QTableView QDateTimeEdit:focus{ +border-width:0px; +border-radius:0px; +} + +QLineEdit,QTextEdit,QPlainTextEdit,QSpinBox,QDoubleSpinBox,QComboBox,QDateEdit,QTimeEdit,QDateTimeEdit{ +background:#444444; +} + +*:disabled{ +background:#444444; +border-color:#484848; +color:#242424; +} + +/*TextColor:#DCDCDC*/ +/*PanelColor:#444444*/ +/*BorderColor:#242424*/ +/*NormalColorStart:#484848*/ +/*NormalColorEnd:#383838*/ +/*DarkColorStart:#646464*/ +/*DarkColorEnd:#525252*/ +/*HighColor:#00BB9E*/ diff --git a/src/data/ukui-sidebar.desktop b/src/data/ukui-sidebar.desktop new file mode 100644 index 0000000..cf28543 --- /dev/null +++ b/src/data/ukui-sidebar.desktop @@ -0,0 +1,22 @@ +[Desktop Entry] +Name=ukui-sidebar +Name[zh_CN]=侧边栏 +Comment=ukui-sidebar +Exec=ukui-sidebar +Terminal=false +Type=Application +#Categories= +Keywords=UKUI; +NoDisplay=true +OnlyShowIn=UKUI; +X-UKUI-Autostart-Phase=Application +X-UKUI-Bugzilla-Bugzilla=UKUI +X-UKUI-Bugzilla-Product=ukui-media +X-UKUI-Bugzilla-Component=ukui-sidebar +X-MATE-Autostart-Phase=Applications +X-KDE-autostart-after=panel +X-UKUI-Autostart-Notify=true +X-UKUI-Autostart-Delay=3 +X-UKUI-AutoRestart=true + + diff --git a/src/env.pri b/src/env.pri new file mode 100644 index 0000000..7b3c07e --- /dev/null +++ b/src/env.pri @@ -0,0 +1 @@ +PLUGIN_INSTALL_DIRS = $$[QT_INSTALL_LIBS]/ukui-sidebar diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..e4555cf --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,130 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include "sidebarpluginswidgets.h" +#include "smallpluginsmanage.h" +#include "mostgrandwidget.h" +#include "qtsingleapplication.h" + +int getScreenWidth() { + Display *disp = XOpenDisplay(NULL); + Screen *scrn = DefaultScreenOfDisplay(disp); + if (NULL == scrn) { + return 0; + } + int width = scrn->width; + + if (NULL != disp) { + XCloseDisplay(disp); + } + return width; +} + +int main(int argc, char *argv[]) +{ + #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + #endif + initUkuiLog4qt("ukui-sidebar"); + /* 如果系统中有实例在运行则退出 */ + QString id = QString("ukui-sidebar-" + QLatin1String(getenv("DISPLAY"))); + QtSingleApplication a(id, argc, argv); + if (a.isRunning()) { + a.sendMessage(QApplication::arguments().length() > 1 ? QApplication::arguments().at(1) : a.applicationFilePath()); + qDebug() << QObject::tr("ukui-sidebar is already running!"); + return EXIT_SUCCESS; + } else { + QCommandLineParser parser; + QCommandLineOption debugOption({"d", "debug"}, QObject::tr("Display debug information")); + QCommandLineOption sidebarState({"s", "state"}, QObject::tr("show or hide sidebar widget")); + QCommandLineOption showSidebar({"s", "show"}, QObject::tr("show sidebar widget")); + QCommandLineOption hideSidebar({"h", "hide"}, QObject::tr("hide sidebar widget")); + + parser.addOptions({debugOption, sidebarState,showSidebar,hideSidebar}); + parser.process(a); + + if (parser.isSet(debugOption)) { /* 根据命令行设定日志等级 */ + setLogLevel(QtDebugMsg); + setLogPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + LOG_FILE_NAME); /* 绑定打印日志文件路径 */ + qInstallMessageHandler(customLogMessageHandler); + } else { + setLogLevel(QtWarningMsg); + } + + QApplication::setQuitOnLastWindowClosed(false); + SmallPluginsManage::SmallPluginsManageInit(); /* 初始化侧边栏小插件管理容器 */ + PluginManager::init(); /* 初始化插件管理器 */ + mostGrandWidget::mostGrandWidgetInit(); /* 初始化最里层Widget空白界面 */ + + bool startOrNot = false; + + Widget *w = new Widget; + w->setObjectName("SidebarWidget"); + w->setAttribute(Qt::WA_TranslucentBackground); + mostGrandWidget::getInstance()->m_pmostGrandWidgetVLaout->addWidget(w); + mostGrandWidget::getInstance()->LaoutSidebarWidget(); + mostGrandWidget::getInstance()->setMostGrandwidgetCoordinates(-500, 0); + mostGrandWidget::getInstance()->setProperty("useSystemStyleBlur", true); + mostGrandWidget::getInstance()->hide(); + + QTimer *startTimer = new QTimer; + startTimer->setSingleShot(true); + + QObject::connect(w,&Widget::startRun,[=](QSystemTrayIcon::ActivationReason reason){ + qDebug()<<"主动启动"; + startTimer->stop(); + w->startBackgroundFunction(); + QTimer *startTimer = new QTimer; + startTimer->setSingleShot(true); + QObject::connect(startTimer,&QTimer::timeout,[=](){ + w->iconActivated(reason); //设定延时,防止消息界面未完全显示就展示 + }); + startTimer->start(1); + }); + + QObject::connect(startTimer,&QTimer::timeout,[=](){ + qDebug()<<"自发启动"; + w->startBackgroundFunction(); + w->oneShotBool=true; + }); + startTimer->start(5000); + + QObject::connect(&a, SIGNAL(messageReceived(const QString&)),w, SLOT(bootOptionsFilter(const QString&))); + return a.exec(); + } +} diff --git a/src/mostgrandwidget.cpp b/src/mostgrandwidget.cpp new file mode 100644 index 0000000..36d6ce1 --- /dev/null +++ b/src/mostgrandwidget.cpp @@ -0,0 +1,67 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see setContentsMargins(0,0,0,0); + m_pmostGrandWidgetVLaout = new QVBoxLayout(); + m_pmostGrandWidgetVLaout->setContentsMargins(0,0,0,0); + this->setWindowFlags(Qt::FramelessWindowHint); + this->setAttribute(Qt::WA_TranslucentBackground); +} + +mostGrandWidget::~mostGrandWidget() +{ + +} + +void mostGrandWidget::mostGrandWidgetInit() +{ + mostGrandWidget::getInstance(); + return; +} + +mostGrandWidget* mostGrandWidget::getInstance() +{ + if (global_Most_Grand_Widgets_instance == nullptr) + global_Most_Grand_Widgets_instance = new mostGrandWidget(); + return global_Most_Grand_Widgets_instance; +} + +/* last Laout MostGrand Widget */ +void mostGrandWidget::LaoutSidebarWidget() +{ + this->setLayout(m_pmostGrandWidgetVLaout); + return; +} + +void mostGrandWidget::setMostGrandwidgetSize(int w, int h) +{ + this->setFixedSize(w,h); + return; +} + +void mostGrandWidget::setMostGrandwidgetCoordinates(int x, int y) +{ + this->move(x, y); + return; +} diff --git a/src/mostgrandwidget.h b/src/mostgrandwidget.h new file mode 100644 index 0000000..22873cd --- /dev/null +++ b/src/mostgrandwidget.h @@ -0,0 +1,41 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include + +class mostGrandWidget : public QWidget +{ + Q_OBJECT +public: + mostGrandWidget(QWidget *parent = nullptr); + ~mostGrandWidget(); + + static void mostGrandWidgetInit(); + static mostGrandWidget* getInstance(); + void LaoutSidebarWidget(); + void setMostGrandwidgetSize(int w, int h); + void setMostGrandwidgetCoordinates(int x, int y); + QVBoxLayout *m_pmostGrandWidgetVLaout; +}; + +#endif // MOSTGRANDWIDGET_H diff --git a/src/plugin-interface/clipboardpluginiface.h b/src/plugin-interface/clipboardpluginiface.h new file mode 100644 index 0000000..2771060 --- /dev/null +++ b/src/plugin-interface/clipboardpluginiface.h @@ -0,0 +1,37 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include "plugin-iface.h" +#include "sidebarclipboardsignal.h" +class ClipboardInterface : public PluginInterface +{ +public: + virtual ~ClipboardInterface() {} + virtual QListWidget* getClipbaordListWidget() = 0; + virtual SidebarClipBoardSignal* createClipSignal() = 0; + virtual QWidget* getClipbaordGroupBox() = 0; +}; +#define ClipboardInterface_iid "org.ukui.sidebar-qt.plugin-iface.ClipboardInterface" +Q_DECLARE_INTERFACE(ClipboardInterface, ClipboardInterface_iid) +#endif // CLIPBOARDPLUGINIFACE_H diff --git a/src/plugin-interface/notification_interface.h b/src/plugin-interface/notification_interface.h new file mode 100644 index 0000000..bbc2e37 --- /dev/null +++ b/src/plugin-interface/notification_interface.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +//定义接口 +class NotificationInterface +{ +public: + virtual ~NotificationInterface() {} + + //返回一个Widget设置到centerwidget中进行显示 + virtual QWidget* centerWidget() = 0; + //当侧边栏展开时给通知中心一个通知 + virtual void showNotification() = 0; + //当侧边栏隐藏时给通知中心一个通知 + virtual void hideNotification() = 0; + //virtual void Notify(QString strAppName, QString strIconPath, QString strSummary, QString strTime, QString strBody) = 0; +}; + +//声明接口 +#define NotificationInterface_iid "org.qt-project.Qt.QGenericPluginFactoryInterface" +Q_DECLARE_INTERFACE(NotificationInterface, NotificationInterface_iid) + +#endif // NOTIFICATION_INTERFACE_H diff --git a/src/plugin-interface/plugin-iface.h b/src/plugin-interface/plugin-iface.h new file mode 100644 index 0000000..fef93e7 --- /dev/null +++ b/src/plugin-interface/plugin-iface.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include + +class PluginInterface +{ +public: + enum PluginType + { + PushBtton1 = 1, + PushBtton2, + PushBtton3, + SmallPlugin, + ClipBoard, + Other + }; + + virtual ~PluginInterface() {} + + virtual PluginType pluginType() = 0; + + virtual const QString name() = 0; + virtual const QString description() = 0; + virtual const QIcon icon() = 0; + virtual void setEnable(bool enable) = 0; + virtual bool isEnable() = 0; +}; +//#define PluginInterface_iid "org.ukui.peony-qt.plugin-iface.PluginInterface" +//Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid) + +#endif // PLUGINIFACE_H diff --git a/src/plugin-interface/plugin-interface.pri b/src/plugin-interface/plugin-interface.pri new file mode 100644 index 0000000..31874ac --- /dev/null +++ b/src/plugin-interface/plugin-interface.pri @@ -0,0 +1,8 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/plugin-iface.h \ + $$PWD/clipboardpluginiface.h \ + $$PWD/notification_interface.h \ + $$PWD/sidebarSmallPluginInterface.h + diff --git a/src/plugin-interface/sidebarSmallPluginInterface.h b/src/plugin-interface/sidebarSmallPluginInterface.h new file mode 100644 index 0000000..fbb20ba --- /dev/null +++ b/src/plugin-interface/sidebarSmallPluginInterface.h @@ -0,0 +1,41 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +class SidebarClipBoardSignal : public QObject +{ + Q_OBJECT +public: + explicit SidebarClipBoardSignal() {} + +signals: + void finishSignal(); + void removeSignal(); + void popSignal(); + void ClipboardHideSignal(); + void CLipBoardEditConfirmButtonSignal(); + void ClipBoardWidgetEntryEditButtonSignal(); + void ClipboardPreviewSignal(int width, int height, int x, int y, int taskHeight); +public slots: +}; +#endif // SIDEBARCLIPBOARDSIGNAL_H diff --git a/src/pluginmanage.cpp b/src/pluginmanage.cpp new file mode 100644 index 0000000..9383a87 --- /dev/null +++ b/src/pluginmanage.cpp @@ -0,0 +1,98 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +static PluginManager *global_instance = nullptr; + +PluginManager::PluginManager(QObject *parent) : QObject(parent) +{ + QString plugins_path(PLUGIN_INSTALL_DIRS); + QDir pluginsDir(plugins_path + "/sidebarSmallPlugins"); + pluginsDir.setFilter(QDir::Files); + + qDebug()<(pPlugin); + if (!pPluginInterface) + continue; + + qDebug()<name(); + m_PluginInterfaceHash.insert(pPluginInterface->name(), pPluginInterface); + switch (pPluginInterface->pluginType()) { + case PluginInterface::SmallPlugin: { + /* Plugins Num++, add Hash SmallPlugins pPluginInterface-->SmallPluginsInterface */ + SidebarSmallPluginInterface *p_SmallPluginsInterface = dynamic_cast(pPluginInterface); + SmallPluginsManage::getInstance()->registerSmallplugin(pPluginInterface, p_SmallPluginsInterface); + break; + } + case PluginInterface::ClipBoard: { + break; + } + case PluginInterface::PushBtton3: { + break; + } + default: + break; + } + } +} + +PluginManager::~PluginManager() +{ + m_PluginInterfaceHash.clear(); +} + +PluginManager *PluginManager::getInstance() +{ + if (!global_instance) + global_instance = new PluginManager; + return global_instance; +} + +void PluginManager::setPluginEnableByName(const QString &name, bool enable) +{ + m_PluginInterfaceHash.value(name)->setEnable(enable); +} + +void PluginManager::close() +{ + if (global_instance) + global_instance->deleteLater(); +} + +void PluginManager::init() +{ + PluginManager::getInstance(); +} diff --git a/src/pluginmanage.h b/src/pluginmanage.h new file mode 100644 index 0000000..2f02ad6 --- /dev/null +++ b/src/pluginmanage.h @@ -0,0 +1,50 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include "plugin-iface.h" +#include "sidebarSmallPluginInterface.h" +class PluginManager : public QObject +{ + Q_OBJECT +public: + static void init(); + static PluginManager *getInstance(); + void close(); + QHash m_PluginInterfaceHash; + + +Q_SIGNALS: + void pluginStateChanged(const QString &pluginName, bool enable); + +private: + explicit PluginManager(QObject *parent = nullptr); + ~PluginManager(); + + +public Q_SLOTS: + void setPluginEnableByName(const QString &pluginName, bool enable); + + +}; + +#endif // PLUGINMANAGE_H diff --git a/src/plugins/ukui-sidebar-clipboard/cleanpromptbox.cpp b/src/plugins/ukui-sidebar-clipboard/cleanpromptbox.cpp new file mode 100644 index 0000000..c437453 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/cleanpromptbox.cpp @@ -0,0 +1,199 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +CleanPromptBox::CleanPromptBox() +{ + this->setFixedSize(400, 218); + this->setObjectName("CleanPromptBoxWidget"); + this->setProperty("useSystemStyleBlur", true); + m_pHintInformationWidget = new QWidget(); + m_pCheckBoxWidget = new QWidget(); + m_pButtonWidget = new QWidget(); + m_pButtonWidget->setObjectName("ButtonWidget"); + + m_pHintInformationWidget->setContentsMargins(0, 0, 0, 0); + m_pCheckBoxWidget->setContentsMargins(0, 0, 0, 0); + m_pButtonWidget->setContentsMargins(0, 0, 0, 0); + initGsettingTransparency(); // 初始化获取透明度的gsetting值 + creatorHintInfomationWidget(); // 创建提示信息 + creatorCheckBoxWidget(); // 创建checkBox + creatorButtonWidget(); // 创建QPushbutton + creatorCleanPromptBoxWidget(); + + + this->setLayout(m_pHintWidgetVLaout); + this->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); + this->setAttribute(Qt::WA_TranslucentBackground); + return; +} + +void CleanPromptBox::initGsettingTransparency() +{ + if (QGSettings::isSchemaInstalled(UKUI_TRANSPARENCY_SETTING)) { + // qDebug() << "分配gsetting值"; + m_pTransparency = new QGSettings(UKUI_TRANSPARENCY_SETTING); + m_dTranSparency = m_pTransparency->get("transparency").toDouble(); + connect(m_pTransparency, &QGSettings::changed, this, [=](QString value) { + if (value == "transparency") { + m_dTranSparency = m_pTransparency->get("transparency").toDouble(); + this->update(); + } + }); + } +} + +void CleanPromptBox::creatorHintInfomationWidget() +{ + m_pIconLableHLaout = new QHBoxLayout; + m_pIconLableHLaout->setContentsMargins(0, 0, 0, 0); + + QIcon tipIcon = QIcon::fromTheme("user-trash", QIcon(CLEAN_PNG_PATH)); + m_pIconButton = new QPushButton(); + m_pIconButton->setObjectName("IconButton"); + /* 设置按钮背景颜色 */ + QPalette palette = m_pIconButton->palette(); + QColor ColorPlaceholderText(255,255,255,0); + QBrush brush; + brush.setColor(ColorPlaceholderText); + palette.setBrush(QPalette::Button, brush); + palette.setBrush(QPalette::ButtonText, brush); + palette.setColor(QPalette::Highlight, Qt::transparent); /* 取消按钮高亮 */ + m_pIconButton->setPalette(palette); + + m_pIconButton->setFixedSize(48, 48); + m_pIconButton->setIcon(tipIcon); + m_pIconButton->setIconSize(QSize(48,48)); + + + m_pHintInformation = new QLabel(QObject::tr("Are you sure empty your clipboard history?")); + m_pHintInformation->setToolTip(m_pHintInformation->text()); + QFont Informationfont; + m_pHintInformation->setFont(Informationfont); + QFontMetrics fontMetrics1(m_pHintInformation->font()); + QString formatAppName = fontMetrics1.elidedText(m_pHintInformation->text(), Qt::ElideRight, m_pHintInformation->width()/3); + m_pHintInformation->setText(formatAppName); + m_pHintInformation->setFixedHeight(Informationfont.pointSize()*4); + m_pHintInformation->setGeometry(QRect(328, 240, 329, 27*4)); //四倍行距 + m_pHintInformation->setWordWrap(true); + m_pHintInformation->setAlignment(Qt::AlignVCenter); + +// m_pHintInformation->setFixedSize(250, 100); + m_pIconLableHLaout->addItem(new QSpacerItem(31,20)); + m_pIconLableHLaout->addWidget(m_pIconButton); + m_pIconLableHLaout->addItem(new QSpacerItem(16, 20)); + m_pIconLableHLaout->addWidget(m_pHintInformation); + m_pIconLableHLaout->addItem(new QSpacerItem(55, 20)); + m_pIconLableHLaout->setSpacing(0); + m_pHintInformationWidget->setLayout(m_pIconLableHLaout); + m_pHintInformationWidget->setFixedHeight(m_pHintInformation->height()); + return; +} + +void CleanPromptBox::creatorCheckBoxWidget() +{ + m_pCheckBoxNoHint = new QCheckBox; + m_pCheckBoxNoHint->setText(QObject::tr("Don't ask")); + m_pCheckBoxNoHint->setFixedHeight(30); + m_pCheckBoxNoHint->setFixedWidth(150); + m_pChechBoxHLaout = new QHBoxLayout; + m_pChechBoxHLaout->setContentsMargins(0,0,0,0); + m_pChechBoxHLaout->setSpacing(0); + m_pChechBoxHLaout->addItem(new QSpacerItem(95, 20)); + m_pChechBoxHLaout->addWidget(m_pCheckBoxNoHint); + m_pChechBoxHLaout->addItem(new QSpacerItem(220, 20, QSizePolicy::Expanding)); + m_pCheckBoxWidget->setLayout(m_pChechBoxHLaout); + return; +} + +void CleanPromptBox::creatorButtonWidget() +{ + m_pConfirmButton = new QPushButton(QObject::tr("Confirm")); + m_pConfirmButton->setObjectName("ConfirmButton"); + m_pCancelButton = new QPushButton(QObject::tr("Cancel")); + m_pCancelButton->setObjectName("CancelButton"); + + connect(m_pConfirmButton, &QPushButton::clicked, globalClipboardSignal, &ClipboardSignal::CLipBoardEditConfirmButtonSignal); + connect(m_pCancelButton, &QPushButton::clicked, globalClipboardSignal, &ClipboardSignal::CLipBoardEditConfirmButtonSignal); + connect(m_pConfirmButton, &QPushButton::clicked, this, &CleanPromptBox::ConfirmButtonSlots); + connect(m_pConfirmButton, &QPushButton::clicked, this, &CleanPromptBox::accept); + connect(m_pCancelButton, &QPushButton::clicked, this, &CleanPromptBox::reject); + + /* 设置按钮字体\背景颜色 */ + m_pCancelButton->setStyle(new CustomStyle_pushbutton_2("ukui-default")); + + /* 设置按钮字体\背景颜色 */ + m_pConfirmButton->setStyle(new CustomStyle("ukui-default")); + + m_pConfirmButton->setFixedSize(120, 34); + m_pCancelButton->setFixedSize(120, 34); + m_pButtonHLaout = new QHBoxLayout; + m_pButtonHLaout->setContentsMargins(0, 0, 0, 0); + m_pButtonHLaout->setSpacing(0); + m_pButtonHLaout->addItem(new QSpacerItem(124, 20)); + m_pButtonHLaout->addWidget(m_pCancelButton); + m_pButtonHLaout->addItem(new QSpacerItem(16, 20)); + m_pButtonHLaout->addWidget(m_pConfirmButton); + m_pButtonHLaout->addItem(new QSpacerItem(20, 10)); + m_pButtonWidget->setLayout(m_pButtonHLaout); + return; +} + + +void CleanPromptBox::creatorCleanPromptBoxWidget() +{ + m_pHintWidgetVLaout = new QVBoxLayout; + m_pHintWidgetVLaout->setContentsMargins(0, 0, 0, 0); + m_pHintWidgetVLaout->setSpacing(0); + m_pHintWidgetVLaout->addItem(new QSpacerItem(20, 48)); + m_pHintWidgetVLaout->addWidget(m_pHintInformationWidget); + m_pHintWidgetVLaout->addItem(new QSpacerItem(15, 10)); + m_pHintWidgetVLaout->addWidget(m_pCheckBoxWidget); + m_pHintWidgetVLaout->addItem(new QSpacerItem(10, 41)); + m_pHintWidgetVLaout->addWidget(m_pButtonWidget); + m_pHintWidgetVLaout->addItem(new QSpacerItem(10, 18)); + return; +} + +void CleanPromptBox::paintEvent(QPaintEvent *) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + +// p.setBrush(QBrush(QColor("#131314"))); + p.setBrush(opt.palette.color(QPalette::Base)); + p.setOpacity(m_dTranSparency); + p.setPen(Qt::NoPen); + + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.drawRoundedRect(opt.rect,6,6); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + return; +} + +void CleanPromptBox::ConfirmButtonSlots() +{ + if (m_pCheckBoxNoHint->isChecked()) { + emit ClipBoardInternalSignal::getGlobalInternalSignal()->CheckBoxSelectedSignal(); + qDebug() << "是选中状态"; + } + return; +} diff --git a/src/plugins/ukui-sidebar-clipboard/cleanpromptbox.h b/src/plugins/ukui-sidebar-clipboard/cleanpromptbox.h new file mode 100644 index 0000000..76d16f5 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/cleanpromptbox.h @@ -0,0 +1,75 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clipboardsignal.h" +#include "clipBoardInternalSignal.h" +#define CLEAN_PNG_PATH ":/image/user-trash.png" +#define SIDEBAR_HINT_QSS_PATH ":/qss/HintBoxWidget.css" +#define UKUI_TRANSPARENCY_SETTING "org.ukui.control-center.personalise" +extern ClipboardSignal *globalClipboardSignal; +class CleanPromptBox : public QDialog +{ +public: + CleanPromptBox(); + QWidget *m_pHintInformationWidget; + QWidget *m_pCheckBoxWidget; + QWidget *m_pButtonWidget; + + QPushButton *m_pConfirmButton; + QPushButton *m_pCancelButton; + QPushButton *m_pIconButton; + QLabel *m_pHintInformation; + QLabel *m_PIconLabel; + + QCheckBox *m_pCheckBoxNoHint; + + QVBoxLayout *m_pHintWidgetVLaout; + QHBoxLayout *m_pIconLableHLaout; + QHBoxLayout *m_pButtonHLaout; + QHBoxLayout *m_pChechBoxHLaout; + + QGSettings *m_pTransparency; + double m_dTranSparency = 0.7; + + void initGsettingTransparency(); + void creatorHintInfomationWidget(); + void creatorCheckBoxWidget(); + void creatorButtonWidget(); + void creatorCleanPromptBoxWidget(); +protected: + void paintEvent(QPaintEvent *); +private slots: + void ConfirmButtonSlots(); +}; + +#endif // CLEANPROMPTBOX_H diff --git a/src/plugins/ukui-sidebar-clipboard/clipBoardInternalSignal.cpp b/src/plugins/ukui-sidebar-clipboard/clipBoardInternalSignal.cpp new file mode 100644 index 0000000..7e7fe8e --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipBoardInternalSignal.cpp @@ -0,0 +1,31 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +class ClipBoardInternalSignal : public QObject +{ + Q_OBJECT +public: + explicit ClipBoardInternalSignal() {} + static void initInternalSignal(); + static ClipBoardInternalSignal* getGlobalInternalSignal(); + +signals: + void CheckBoxSelectedSignal(); +public slots: +}; +#endif // CLIPBOARDINTERNALSIGNAL_H diff --git a/src/plugins/ukui-sidebar-clipboard/clipbaordstructoriginaldata.h b/src/plugins/ukui-sidebar-clipboard/clipbaordstructoriginaldata.h new file mode 100644 index 0000000..847ecc8 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipbaordstructoriginaldata.h @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include "clipboardwidgetentry.h" +enum DataType { + Unknown, + Text, + Image, + File +}; + +typedef struct clipboardOriginalDataHash { + ClipboardWidgetEntry* WidgetEntry; + const QMimeData* MimeData; + QPixmap *p_pixmap; + QString text; + QString Clipbaordformat; + QList urls; + int Sequence; +} OriginalDataHashValue; +#endif // CLIPBAORDSTRUCTORIGINALDATA_H diff --git a/src/plugins/ukui-sidebar-clipboard/clipboardPlugin.json b/src/plugins/ukui-sidebar-clipboard/clipboardPlugin.json new file mode 100644 index 0000000..1e81138 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipboardPlugin.json @@ -0,0 +1,3 @@ +{ + "Keys" : [ ] +} diff --git a/src/plugins/ukui-sidebar-clipboard/clipboardPlugin.qrc b/src/plugins/ukui-sidebar-clipboard/clipboardPlugin.qrc new file mode 100644 index 0000000..fbac7eb --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipboardPlugin.qrc @@ -0,0 +1,19 @@ + + + image/editor.svg + image/copy.svg + image/delete.svg + image/button-close-hover-click-two.svg + image/button-close-hover-click-add-background-one.svg + image/button-close-default-add-background-three.svg + image/user-trash.png + qss/sidebarClipboard.css + qss/sideBarEditArea.css + qss/sideBarSearchArea.css + image/kylin-feedback.png + image/kylin-alarm-clock.svg + image/lock.png + image/cancel-lock.png + fileIcon.json + + diff --git a/src/plugins/ukui-sidebar-clipboard/clipboarddb.cpp b/src/plugins/ukui-sidebar-clipboard/clipboarddb.cpp new file mode 100644 index 0000000..ce2946b --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipboarddb.cpp @@ -0,0 +1,119 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +class clipboardDb : public QObject +{ +public: + clipboardDb(QObject *parent = nullptr); + bool connectClipboardDb(QString DbName); + bool creatClipboardDbTable(QString DbName); + void insertSqlClipbarodDb(QString content, QString format, int Sequence); + void deleteSqlClipboardDb(QString content); + void updateSqlClipboardDb(QString content, QString format, int Sequence, QString oldcontent); + int SelectSqlClipbaordDbId(); +}; + +#endif // CLIPBOARDDB_H diff --git a/src/plugins/ukui-sidebar-clipboard/clipboardlisetwidget.cpp b/src/plugins/ukui-sidebar-clipboard/clipboardlisetwidget.cpp new file mode 100644 index 0000000..778139e --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipboardlisetwidget.cpp @@ -0,0 +1,37 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +#include +ClipBoardLisetWidget::ClipBoardLisetWidget() +{ + installEventFilter(this); +} + +void ClipBoardLisetWidget::mousePressEvent(QMouseEvent *event) +{ +// if (event->buttons() == Qt::LeftButton) { +// auto pos = event->pos(); +// if (!this->indexAt(pos).isValid()) +// //发送信号 +// emit globalClipboardSignal->ClipboardHideSignal(); +// } +} diff --git a/src/plugins/ukui-sidebar-clipboard/clipboardlisetwidget.h b/src/plugins/ukui-sidebar-clipboard/clipboardlisetwidget.h new file mode 100644 index 0000000..342e867 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipboardlisetwidget.h @@ -0,0 +1,33 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include "clipboardsignal.h" + +extern ClipboardSignal *globalClipboardSignal; +class ClipBoardLisetWidget :public QListWidget +{ +public: + ClipBoardLisetWidget(); +protected: + void mousePressEvent(QMouseEvent *event); +}; + +#endif // CLIPBOARDLISETWIDGET_H diff --git a/src/plugins/ukui-sidebar-clipboard/clipboardsignal.h b/src/plugins/ukui-sidebar-clipboard/clipboardsignal.h new file mode 100644 index 0000000..4163e35 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipboardsignal.h @@ -0,0 +1,34 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include + +ClipboardWidgetEntry::ClipboardWidgetEntry(QString dataFormat, QWidget *parent) +{ + Q_UNUSED(parent); + m_dataFormat = dataFormat; + status=NORMAL; + this->setObjectName("WidgetEntry"); + this->setContentsMargins(0,0,0,0); + + /* 初始化三个按钮 */ + initPushbutton(); + /* 初始化Lable */ + initLable(); + + if (dataFormat == ENTRYURL || dataFormat == ENTRYTEXT) { + m_pCopyDataLabal->setFixedSize(386, 34); + } else if (dataFormat == ENTRYIMAGE) { + m_pCopyDataLabal->setFixedSize(110, 75); + } + + m_pHLayout = new QHBoxLayout(); + m_pHLayout->setContentsMargins(0,0,0,0); + m_pHLayout->addItem(new QSpacerItem(10,20)); + + if (dataFormat == ENTRYURL) { + m_pCopyFileIcon = new pixmapLabel(); //用来放置文件的图标 + m_pCopyFileIcon->setContentsMargins(0, 0, 0, 0); + m_pCopyFileIcon->setFixedSize(25, 25); + m_pCopyDataLabal->setFixedSize(380, 34); + m_pHLayout->addWidget(m_pCopyFileIcon); + } + + m_pHLayout->addWidget(m_pCopyDataLabal); + + if (dataFormat == ENTRYIMAGE) + m_pHLayout->addItem(new QSpacerItem(276, 34)); + + m_pHLayout->addWidget(m_pPopButton); + m_pHLayout->addWidget(m_pCancelLockButton); + m_pCancelLockButton->setVisible(false); + if (!(m_dataFormat == ENTRYURL + || m_dataFormat == ENTRYIMAGE)) + m_pHLayout->addWidget(m_pEditButon); + + + m_pHLayout->addWidget(m_pRemoveButton); + m_pHLayout->addItem(new QSpacerItem(15,20)); + m_pHLayout->setSpacing(5); + m_pPopButton->setVisible(false); + m_pEditButon->setVisible(false); + m_pRemoveButton->setVisible(false); + this->setLayout(m_pHLayout); +} + +void ClipboardWidgetEntry::initPushbutton() +{ + QIcon EditIcon; + EditIcon.addFile(EDIT_SVG_PATH); + QIcon PopIcon; + PopIcon.addFile(LOCK_SVG_PATH); + QIcon RemoveIcon; + RemoveIcon.addFile(REMOVE_SVG_PATH); + QIcon CancelIcon; + CancelIcon.addFile(CANCEL_LOCK_PNG_PATH); + m_pPopButton = new QPushButton(); + m_pPopButton->setStyle(new customstyle_clean_pushbutton("ukui-default")); + m_pPopButton->setToolTip(QObject::tr("Pop")); + m_pPopButton->setFixedSize(34, 34); + m_pPopButton->setIcon(PopIcon); + m_pPopButton->setObjectName("PopButton"); + + m_pEditButon = new QPushButton(); + m_pEditButon->setStyle(new customstyle_clean_pushbutton("ukui-default")); + connect(m_pEditButon, &QPushButton::clicked, globalClipboardSignal, &ClipboardSignal::ClipBoardWidgetEntryEditButtonSignal); + m_pEditButon->setToolTip(QObject::tr("EditButton")); + m_pEditButon->setFixedSize(34, 34); + m_pEditButon->setIcon(EditIcon); + m_pEditButon->setObjectName("EditButon"); + + m_pRemoveButton = new QPushButton(); + m_pRemoveButton->setStyle(new customstyle_clean_pushbutton("ukui-default")); + m_pRemoveButton->setToolTip(QObject::tr("Remove")); + m_pRemoveButton->setFixedSize(34, 34); + m_pRemoveButton->setIcon(RemoveIcon); + m_pRemoveButton->setObjectName("RemoveButton"); + + m_pCancelLockButton = new QPushButton(); + m_pCancelLockButton->setStyle(new customstyle_clean_pushbutton("ukui-default")); + m_pCancelLockButton->setToolTip(QObject::tr("Cancel the fixed")); + m_pCancelLockButton->setFixedSize(34,34); + m_pCancelLockButton->setIcon(CancelIcon); + m_pCancelLockButton->setObjectName("cancel fixed the button"); + return; +} + +void ClipboardWidgetEntry::initLable() +{ + m_pCopyDataLabal = new QLabel(); + QTimer::singleShot(1, m_pCopyDataLabal, [=](){ + QFont font = m_pCopyDataLabal->font(); +// font.setPixelSize(14); +// font.setFamily("Noto Sans CJK SC"); + m_pCopyDataLabal->setFont(font); + }); + m_pCopyDataLabal->setObjectName("EntryLable"); + if (m_dataFormat == ENTRYTEXT || m_dataFormat == ENTRYIMAGE) { + m_pCopyDataLabal->setContentsMargins(3, 0, 0, 0); + } else { + m_pCopyDataLabal->setContentsMargins(0, 0, 0, 0); + } +} + +void ClipboardWidgetEntry::enterEvent(QEvent *e) +{ + if(e == nullptr) { + return; + } + + status=HOVER; + repaint(); + + m_pCopyDataLabal->setFixedSize(260, 34); + if (m_dataFormat == ENTRYURL) { + m_pCopyDataLabal->setFixedSize(278, 34); + } else if (m_dataFormat == ENTRYIMAGE) { + m_pCopyDataLabal->setFixedSize(110, 75); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) +// emit previewShowImage(this);//发送预览信号 +#endif + } else { + m_pCopyDataLabal->setFixedSize(260, 34); + m_pEditButon->setVisible(true); + } + if (m_bWhetherFix) { + m_pCancelLockButton->setVisible(true); + } else { + m_pPopButton->setVisible(true); + } + m_pRemoveButton->setVisible(true); + m_ptext = this->m_pCopyDataLabal->text(); + QString format; + if (m_dataFormat == ENTRYURL) { + format = setMiddleFormatBody(m_ptext); + } else { + format = SetFormatBody(m_ptext); + } + m_pCopyDataLabal->setText(format); + this->update(); +} + +void ClipboardWidgetEntry::leaveEvent(QEvent *e) +{ + if (e == nullptr) + return; + status=NORMAL; + if (m_bWhetherFix) { + m_pCancelLockButton->setVisible(false); + } else { + m_pPopButton->setVisible(false); + } + m_pEditButon->setVisible(false); + m_pRemoveButton->setVisible(false); + if (m_dataFormat == ENTRYURL || m_dataFormat == ENTRYTEXT) { + m_pCopyDataLabal->setFixedSize(386, 34); + } else if (m_dataFormat == ENTRYIMAGE) { + m_pCopyDataLabal->setFixedSize(110, 75); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) +// emit previewHideImage(this);//发送退出预览信号 +#endif + this->update(); + } + if (m_ptext == "") { + this->update(); + return; + } else { + this->m_pCopyDataLabal->setText(m_ptext); + } + this->update(); + return; +} + +void ClipboardWidgetEntry::mousePressEvent(QMouseEvent *event) +{ + m_ptext = this->m_pCopyDataLabal->text(); + if (event->button() == Qt::LeftButton) { + emit doubleClicksignals(this); + return; + } + return; +} + +void ClipboardWidgetEntry::mouseDoubleClickEvent(QMouseEvent *event) +{ + +} + +QString ClipboardWidgetEntry::SetFormatBody(QString text) +{ + QFontMetrics fontMetrics(this->m_pCopyDataLabal->font()); + int LableWidth = this->m_pCopyDataLabal->width(); + int fontSize = fontMetrics.width(text); + QString formatBody = text; + if(fontSize > (LableWidth - 10)) { + QStringList list = formatBody.split("\n"); + if (list.size() >= 2) { + //当有几行时,只需要截取第一行就行,在第一行后面加... + /* 判断第一行是否是空行 */ + formatBody = judgeBlankLine(list); + formatBody = formatBody + "aa"; + int oneFontSize = fontMetrics.width(formatBody); + if (oneFontSize > (LableWidth - 10)) { + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, LableWidth - 10); + return formatBody; + } else { + if (!substringSposition(formatBody, list)) { + int oneFontSize = fontMetrics.width(formatBody); + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, oneFontSize - 1); + return formatBody; + } + } + } else { + //说明只存在一行,在最后面加...就行 + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, LableWidth - 10); + return formatBody; + } + } else { + QStringList list = formatBody.split("\n"); + if (list.size() >= 2) { + //取得当前的有字符串的子串 + formatBody = judgeBlankLine(list); + formatBody = formatBody + "aa"; + if (!substringSposition(formatBody, list)) { + int oneFontSize = fontMetrics.width(formatBody); + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, oneFontSize - 1); + } + } + } + return formatBody; +} + +QString ClipboardWidgetEntry::setMiddleFormatBody(QString text) +{ + QFontMetrics fontMetrics(m_pCopyDataLabal->font()); + int LableWidth = m_pCopyDataLabal->width(); + int fontSize = fontMetrics.width(text); + QString formatBody = text; + if (fontSize > (LableWidth - 20)) { + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideMiddle, LableWidth - 20); + return formatBody; + } + return formatBody; +} + +/* 去除掉空行,显示有字体的行 */ +QString ClipboardWidgetEntry::judgeBlankLine(QStringList list) +{ + int tmp = list.count(); + for (int i = 0; i < tmp; i++) { + QString dest = list.at(i); + dest = dest.trimmed(); + if (dest.size() != 0) + return list.at(i); + } + return list.at(0); +} + +/* 判断当前子串位置,后面是否还有子串 */ +bool ClipboardWidgetEntry::substringSposition(QString formatBody, QStringList list) +{ + int tmp = list.count(); + for (int i = 0; i < tmp; i++) { + QString dest = list.at(i); + if (dest == formatBody && i == tmp - 1) + return true; + } + return false; +} + +void ClipboardWidgetEntry::paintEvent(QPaintEvent *e) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + switch (status) { + case NORMAL: { + p.setBrush(QBrush(QColor(255, 255, 255, 0))); + p.setPen(Qt::NoPen); + break; + } + case HOVER: { + QColor color(opt.palette.color(QPalette::WindowText)); + p.setBrush(QBrush(color)); + p.setOpacity(0.08); + p.setPen(Qt::NoPen); + break; + } + case PRESS: { + break; + } + } + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.drawRoundedRect(opt.rect,0,0); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} diff --git a/src/plugins/ukui-sidebar-clipboard/clipboardwidgetentry.h b/src/plugins/ukui-sidebar-clipboard/clipboardwidgetentry.h new file mode 100644 index 0000000..e56403e --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/clipboardwidgetentry.h @@ -0,0 +1,91 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clipboardsignal.h" +#include "clipBoardInternalSignal.h" +#include "pixmaplabel.h" + +#define EDIT_SVG_PATH ":/image/editor.svg" +#define COPY_SVG_PATH ":/image/copy.svg" +#define REMOVE_SVG_PATH ":/image/delete.svg" +#define SEARCH_SVG_CLEAN ":/image/button-close-hover-click-two.svg" +#define SEARCH_SVG_CLEAN_BACK ":/image/button-close-hover-click-add-background-one.svg" +#define LOCK_SVG_PATH ":/image/lock.png" +#define CANCEL_LOCK_PNG_PATH ":/image/cancel-lock.png" + +#define ENTRYURL "Url" +#define ENTRYIMAGE "Image" +#define ENTRYTEXT "Text" + +extern ClipboardSignal *globalClipboardSignal; +class ClipboardWidgetEntry : public QWidget +{ + Q_OBJECT +public: + ClipboardWidgetEntry(QString dataFormat, QWidget *parent = nullptr); + QPushButton *m_pPopButton; + QPushButton *m_pEditButon; + QPushButton *m_pRemoveButton; + QPushButton *m_pCancelLockButton; + QLabel *m_pCopyDataLabal = nullptr; + pixmapLabel *m_pCopyFileIcon; + QHBoxLayout *m_pHLayout; + QString m_ptext; + QString m_dataFormat; + bool m_bWhetherFix = false; + QString SetFormatBody(QString text); + QString setMiddleFormatBody(QString text); + QString judgeBlankLine(QStringList list); /* 去除掉空行,显示有字体的行 */ + void initPushbutton(); /* 初始化三个按钮 */ + void initLable(); /* 初始化Lable */ + bool substringSposition(QString formatBody, QStringList list); /* 判断后面是否还有子串 */ + + + enum TaskWidgetStatus{NORMAL, HOVER, PRESS}; + TaskWidgetStatus status; + +protected: + void enterEvent(QEvent *); //进入QWidget瞬间事件 + void leaveEvent(QEvent *); //离开QWidget瞬间事件 + void mouseDoubleClickEvent(QMouseEvent *event); //双击事件 + void mousePressEvent(QMouseEvent *event); //单击事件 + void paintEvent(QPaintEvent *e); //重绘事件 + +signals: + void doubleClicksignals(QWidget *w); + void previewShowImage(QWidget *w); + void previewHideImage(QWidget *w); +}; + +#endif // CLIPBOARDWIDGETENTRY_H diff --git a/src/plugins/ukui-sidebar-clipboard/customstyle.cpp b/src/plugins/ukui-sidebar-clipboard/customstyle.cpp new file mode 100644 index 0000000..49edc81 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstyle.cpp @@ -0,0 +1,219 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +#include +#include + +#include + +CustomStyle::CustomStyle(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) +{ + Q_UNUSED(parent); +} + +void CustomStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + return QProxyStyle::drawComplexControl(control, option, painter, widget); +} + +void CustomStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case QStyle::CE_PushButton: { + QStyleOptionButton button = *qstyleoption_cast(option); + button.palette.setColor(QPalette::HighlightedText, button.palette.buttonText().color()); + return QProxyStyle::drawControl(element, &button, painter, widget); + break; + } + default: + break; + } + return QProxyStyle::drawControl(element, option, painter, widget); +} + +void CustomStyle::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +} + +void CustomStyle::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +} + +/// 我们重写button的绘制方法,通过state和当前动画的状态以及value值改变相关的绘制条件 +/// 这里通过判断hover与否,动态的调整painter的透明度然后绘制背景 +/// 需要注意的是,默认控件的绘制流程只会触发一次,而动画需要我们在一段时间内不停绘制才行, +/// 要使得动画能够持续,我们需要使用QWidget::update()在动画未完成时, +/// 手动更新一次,这样button将在一段时间后再次调用draw方法,从而达到更新动画的效果 +/// +/// 需要注意绘制背景的流程会因主题不同而产生差异,所以这一部分代码在一些主题中未必正常, +/// 如果你需要自己实现一个主题,这同样是你需要注意和考虑的点 +void CustomStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case PE_PanelButtonCommand: { + if (option->state & State_MouseOver) { + if (option->state & State_Sunken) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(50,87,202,255); + painter->setBrush(color); + painter->drawRoundedRect(option->rect,4,4); + painter->restore(); + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(107,142,235,255); + painter->setBrush(color); + painter->drawRoundedRect(option->rect,4, 4); + painter->restore(); + } + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(61, 107, 229, 255); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + return; + } break; + case PE_PanelLineEdit://UKUI Line edit style + { + // Conflict with qspinbox and so on, The widget text cannot use this style + painter->save(); + if (const QStyleOptionFrame *panel = qstyleoption_cast(option)) { + painter->setRenderHint(QPainter::Antialiasing,true); + //Setpen is set to avoid a bug that collides with a white background + painter->setPen(Qt::NoPen); + QColor color(0,0,0,51); + painter->setBrush(color); + QFont font; + font.setFamily("Noto Sans CJK SC"); + font.setPixelSize(14); + font.setWeight(400); + painter->setFont(font); + if (widget->isEnabled()) { + if (option->state &State_MouseOver) { + QColor ColotPen(61,107,229,255); + painter->setPen(ColotPen); + painter->setBrush(color); + } + if(option->state &State_HasFocus) { + QColor ColotPen(28, 47, 146, 255); + painter->setPen(ColotPen); + painter->setBrush(color); + } + } + painter->drawRoundedRect(panel->rect,4,4); + } + painter->restore(); + return; + }break; + } + return QProxyStyle::drawPrimitive(element, option, painter, widget); +} + +QPixmap CustomStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl CustomStyle::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +{ + return QProxyStyle::hitTestComplexControl(control, option, position, widget); +} + +QRect CustomStyle::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +} + +QRect CustomStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +{ + return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +} + +int CustomStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::pixelMetric(metric, option, widget); +} + +/// 我们需要将动画与widget一一对应起来, +/// 在一个style的生命周期里,widget只会进行polish和unpolish各一次, +/// 所以我们可以在polish时将widget与一个新的动画绑定,并且对应的在unpolish中解绑定 +void CustomStyle::polish(QWidget *widget) +{ + return QProxyStyle::polish(widget); +} + +void CustomStyle::polish(QApplication *application) +{ + return QProxyStyle::polish(application); +} + +void CustomStyle::polish(QPalette &palette) +{ + return QProxyStyle::polish(palette); +} + +void CustomStyle::unpolish(QWidget *widget) +{ + return QProxyStyle::unpolish(widget); +} + +void CustomStyle::unpolish(QApplication *application) +{ + return QProxyStyle::unpolish(application); +} + +QSize CustomStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} + +QIcon CustomStyle::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::standardIcon(standardIcon, option, widget); +} + +QPalette CustomStyle::standardPalette() const +{ + return QProxyStyle::standardPalette(); +} + +int CustomStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +QRect CustomStyle::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +{ + return QProxyStyle::subControlRect(control, option, subControl, widget); +} + +QRect CustomStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::subElementRect(element, option, widget); +} diff --git a/src/plugins/ukui-sidebar-clipboard/customstyle.h b/src/plugins/ukui-sidebar-clipboard/customstyle.h new file mode 100644 index 0000000..89a7aea --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstyle.h @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +class CustomStyle : public QProxyStyle +{ + Q_OBJECT +public: + explicit CustomStyle(const QString &proxyStyleName = "windows", QObject *parent = nullptr); + virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + /*! + * \brief drawPrimitive + * \param element 背景绘制,对应PE枚举类型 + * \param option + * \param painter + * \param widget + * \details + * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, + * 我们一般需要判断控件的状态来绘制不同的背景, + * 比如按钮的hover和点击效果。 + */ + virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; + virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; + virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; + //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); + virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + + virtual void polish(QWidget *widget); + virtual void polish(QApplication *application); + virtual void polish(QPalette &palette); + virtual void unpolish(QWidget *widget); + virtual void unpolish(QApplication *application); + + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + virtual QPalette standardPalette() const; + virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; + + virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; + + virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; + +signals: + +public slots: + +private: +}; + +#endif // CUSTOMSTYLE_H diff --git a/src/plugins/ukui-sidebar-clipboard/customstyleCleanPushbutton.cpp b/src/plugins/ukui-sidebar-clipboard/customstyleCleanPushbutton.cpp new file mode 100644 index 0000000..25b160f --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstyleCleanPushbutton.cpp @@ -0,0 +1,193 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +#include +#include + +#include + +customstyle_clean_pushbutton::customstyle_clean_pushbutton(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) +{ + Q_UNUSED(parent); +} + +void customstyle_clean_pushbutton::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + return QProxyStyle::drawComplexControl(control, option, painter, widget); +} + +void customstyle_clean_pushbutton::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case QStyle::CE_PushButton: { + QStyleOptionButton button = *qstyleoption_cast(option); + button.palette.setColor(QPalette::HighlightedText, button.palette.buttonText().color()); + return QProxyStyle::drawControl(element, &button, painter, widget); + break; + } + default: + break; + } + return QProxyStyle::drawControl(element, option, painter, widget); +} + +void customstyle_clean_pushbutton::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +} + +void customstyle_clean_pushbutton::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +} + +/// 我们重写button的绘制方法,通过state和当前动画的状态以及value值改变相关的绘制条件 +/// 这里通过判断hover与否,动态的调整painter的透明度然后绘制背景 +/// 需要注意的是,默认控件的绘制流程只会触发一次,而动画需要我们在一段时间内不停绘制才行, +/// 要使得动画能够持续,我们需要使用QWidget::update()在动画未完成时, +/// 手动更新一次,这样button将在一段时间后再次调用draw方法,从而达到更新动画的效果 +/// +/// 需要注意绘制背景的流程会因主题不同而产生差异,所以这一部分代码在一些主题中未必正常, +/// 如果你需要自己实现一个主题,这同样是你需要注意和考虑的点 +void customstyle_clean_pushbutton::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + if (element == PE_PanelButtonCommand) { + if (widget) { + if (option->state & State_MouseOver) { + if (option->state & State_Sunken) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); +// QColor color(255,255,255,21); +// painter->setBrush(color); + painter->setBrush(option->palette.color(QPalette::WindowText)); + painter->setOpacity(0.08); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); +// QColor color(255,255,255,51); +// painter->setBrush(color); + painter->setBrush(option->palette.color(QPalette::WindowText)); + painter->setOpacity(0.2); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); +// QColor color(255,255,255,31); +// painter->setBrush(color); + painter->setBrush(option->palette.color(QPalette::WindowText)); + painter->setOpacity(0.12); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + return; + } + } + return QProxyStyle::drawPrimitive(element, option, painter, widget); +} + +QPixmap customstyle_clean_pushbutton::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl customstyle_clean_pushbutton::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +{ + return QProxyStyle::hitTestComplexControl(control, option, position, widget); +} + +QRect customstyle_clean_pushbutton::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +} + +QRect customstyle_clean_pushbutton::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +{ + return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +} + +int customstyle_clean_pushbutton::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::pixelMetric(metric, option, widget); +} + +/// 我们需要将动画与widget一一对应起来, +/// 在一个style的生命周期里,widget只会进行polish和unpolish各一次, +/// 所以我们可以在polish时将widget与一个新的动画绑定,并且对应的在unpolish中解绑定 +void customstyle_clean_pushbutton::polish(QWidget *widget) +{ + return QProxyStyle::polish(widget); +} + +void customstyle_clean_pushbutton::polish(QApplication *application) +{ + return QProxyStyle::polish(application); +} + +void customstyle_clean_pushbutton::polish(QPalette &palette) +{ + return QProxyStyle::polish(palette); +} + +void customstyle_clean_pushbutton::unpolish(QWidget *widget) +{ + return QProxyStyle::unpolish(widget); +} + +void customstyle_clean_pushbutton::unpolish(QApplication *application) +{ + return QProxyStyle::unpolish(application); +} + +QSize customstyle_clean_pushbutton::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} + +QIcon customstyle_clean_pushbutton::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::standardIcon(standardIcon, option, widget); +} + +QPalette customstyle_clean_pushbutton::standardPalette() const +{ + return QProxyStyle::standardPalette(); +} + +int customstyle_clean_pushbutton::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +QRect customstyle_clean_pushbutton::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +{ + return QProxyStyle::subControlRect(control, option, subControl, widget); +} + +QRect customstyle_clean_pushbutton::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::subElementRect(element, option, widget); +} diff --git a/src/plugins/ukui-sidebar-clipboard/customstyleCleanPushbutton.h b/src/plugins/ukui-sidebar-clipboard/customstyleCleanPushbutton.h new file mode 100644 index 0000000..9aa4a8f --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstyleCleanPushbutton.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +class customstyle_clean_pushbutton : public QProxyStyle +{ + Q_OBJECT +public: + explicit customstyle_clean_pushbutton(const QString &proxyStyleName = "windows", QObject *parent = nullptr); + virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + /*! + * \brief drawPrimitive + * \param element 背景绘制,对应PE枚举类型 + * \param option + * \param painter + * \param widget + * \details + * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, + * 我们一般需要判断控件的状态来绘制不同的背景, + * 比如按钮的hover和点击效果。 + */ + virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; + virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; + virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; + //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); + virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + + virtual void polish(QWidget *widget); + virtual void polish(QApplication *application); + virtual void polish(QPalette &palette); + virtual void unpolish(QWidget *widget); + virtual void unpolish(QApplication *application); + + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + virtual QPalette standardPalette() const; + virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; + + virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; + + virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; + +signals: + +public slots: + +private: +}; + +#endif // CUSTOMSTYLE_CLEAN_PUSHBUTTON_H diff --git a/src/plugins/ukui-sidebar-clipboard/customstylePushbutton2.cpp b/src/plugins/ukui-sidebar-clipboard/customstylePushbutton2.cpp new file mode 100644 index 0000000..fd4887c --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstylePushbutton2.cpp @@ -0,0 +1,218 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +#include +#include + +#include + +CustomStyle_pushbutton_2::CustomStyle_pushbutton_2(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) +{ + Q_UNUSED(parent); +} + +void CustomStyle_pushbutton_2::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + return QProxyStyle::drawComplexControl(control, option, painter, widget); +} + +void CustomStyle_pushbutton_2::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case QStyle::CE_PushButton: { + QStyleOptionButton button = *qstyleoption_cast(option); + button.palette.setColor(QPalette::HighlightedText, button.palette.buttonText().color()); + return QProxyStyle::drawControl(element, &button, painter, widget); + break; + } + default: + break; + } + return QProxyStyle::drawControl(element, option, painter, widget); +} + +void CustomStyle_pushbutton_2::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +} + +void CustomStyle_pushbutton_2::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +} + +/// 我们重写button的绘制方法,通过state和当前动画的状态以及value值改变相关的绘制条件 +/// 这里通过判断hover与否,动态的调整painter的透明度然后绘制背景 +/// 需要注意的是,默认控件的绘制流程只会触发一次,而动画需要我们在一段时间内不停绘制才行, +/// 要使得动画能够持续,我们需要使用QWidget::update()在动画未完成时, +/// 手动更新一次,这样button将在一段时间后再次调用draw方法,从而达到更新动画的效果 +/// +/// 需要注意绘制背景的流程会因主题不同而产生差异,所以这一部分代码在一些主题中未必正常, +/// 如果你需要自己实现一个主题,这同样是你需要注意和考虑的点 +void CustomStyle_pushbutton_2::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ +// if (element == PE_PanelButtonCommand) { +// qDebug()<<"draw pe button"; +// if (widget) { +// bool isPressed = false; +// bool isHover = false; +// if (!option->state.testFlag(State_Sunken)) { +// if (option->state.testFlag(State_MouseOver)) { +// isHover = true; +// } +// } else { +// isPressed = true; +// } + +// QStyleOption opt = *option; +// if (isHover) { +// QColor color(255,255,255,51); +// opt.palette.setColor(QPalette::Highlight, color); + +// } +// if (isPressed) { +// QColor color(255,255,255,21); +// opt.palette.setColor(QPalette::Highlight, color); +// } +// if (!isHover && !isPressed) { +// QColor color(255,255,255,31); +// opt.palette.setColor(QPalette::Button,color); +// } +// return QProxyStyle::drawPrimitive(element, &opt, painter, widget); +// } +// } +// return QProxyStyle::drawPrimitive(element, option, painter, widget); + if (element == PE_PanelButtonCommand) { + if (widget) { + if (option->state & State_MouseOver) { + if (option->state & State_Sunken) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,21); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,51); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,31); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + return; + } + } + return QProxyStyle::drawPrimitive(element, option, painter, widget); +} + +QPixmap CustomStyle_pushbutton_2::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl CustomStyle_pushbutton_2::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +{ + return QProxyStyle::hitTestComplexControl(control, option, position, widget); +} + +QRect CustomStyle_pushbutton_2::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +} + +QRect CustomStyle_pushbutton_2::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +{ + return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +} + +int CustomStyle_pushbutton_2::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::pixelMetric(metric, option, widget); +} + +/// 我们需要将动画与widget一一对应起来, +/// 在一个style的生命周期里,widget只会进行polish和unpolish各一次, +/// 所以我们可以在polish时将widget与一个新的动画绑定,并且对应的在unpolish中解绑定 +void CustomStyle_pushbutton_2::polish(QWidget *widget) +{ + return QProxyStyle::polish(widget); +} + +void CustomStyle_pushbutton_2::polish(QApplication *application) +{ + return QProxyStyle::polish(application); +} + +void CustomStyle_pushbutton_2::polish(QPalette &palette) +{ + return QProxyStyle::polish(palette); +} + +void CustomStyle_pushbutton_2::unpolish(QWidget *widget) +{ + return QProxyStyle::unpolish(widget); +} + +void CustomStyle_pushbutton_2::unpolish(QApplication *application) +{ + return QProxyStyle::unpolish(application); +} + +QSize CustomStyle_pushbutton_2::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} + +QIcon CustomStyle_pushbutton_2::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::standardIcon(standardIcon, option, widget); +} + +QPalette CustomStyle_pushbutton_2::standardPalette() const +{ + return QProxyStyle::standardPalette(); +} + +int CustomStyle_pushbutton_2::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +QRect CustomStyle_pushbutton_2::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +{ + return QProxyStyle::subControlRect(control, option, subControl, widget); +} + +QRect CustomStyle_pushbutton_2::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::subElementRect(element, option, widget); +} diff --git a/src/plugins/ukui-sidebar-clipboard/customstylePushbutton2.h b/src/plugins/ukui-sidebar-clipboard/customstylePushbutton2.h new file mode 100644 index 0000000..abfbd93 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstylePushbutton2.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +class CustomStyle_pushbutton_2 : public QProxyStyle +{ + Q_OBJECT +public: + explicit CustomStyle_pushbutton_2(const QString &proxyStyleName = "windows", QObject *parent = nullptr); + virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + /*! + * \brief drawPrimitive + * \param element 背景绘制,对应PE枚举类型 + * \param option + * \param painter + * \param widget + * \details + * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, + * 我们一般需要判断控件的状态来绘制不同的背景, + * 比如按钮的hover和点击效果。 + */ + virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; + virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; + virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; + //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); + virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + + virtual void polish(QWidget *widget); + virtual void polish(QApplication *application); + virtual void polish(QPalette &palette); + virtual void unpolish(QWidget *widget); + virtual void unpolish(QApplication *application); + + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + virtual QPalette standardPalette() const; + virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; + + virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; + + virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; + +signals: + +public slots: + +private: +}; + +#endif // CUSTOMSTYLE_PUSHBUTTON_2_H diff --git a/src/plugins/ukui-sidebar-clipboard/customstyleSearchPushbutton.cpp b/src/plugins/ukui-sidebar-clipboard/customstyleSearchPushbutton.cpp new file mode 100644 index 0000000..0599ee4 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstyleSearchPushbutton.cpp @@ -0,0 +1,187 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +#include +#include + +#include + +customstyle_search_pushbutton::customstyle_search_pushbutton(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) +{ + Q_UNUSED(parent); +} + +void customstyle_search_pushbutton::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + return QProxyStyle::drawComplexControl(control, option, painter, widget); +} + +void customstyle_search_pushbutton::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case QStyle::CE_PushButton: { + QStyleOptionButton button = *qstyleoption_cast(option); + button.palette.setColor(QPalette::HighlightedText, button.palette.buttonText().color()); + return QProxyStyle::drawControl(element, &button, painter, widget); + break; + } + default: + break; + } + return QProxyStyle::drawControl(element, option, painter, widget); +} + +void customstyle_search_pushbutton::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +} + +void customstyle_search_pushbutton::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +} + +/// 我们重写button的绘制方法,通过state和当前动画的状态以及value值改变相关的绘制条件 +/// 这里通过判断hover与否,动态的调整painter的透明度然后绘制背景 +/// 需要注意的是,默认控件的绘制流程只会触发一次,而动画需要我们在一段时间内不停绘制才行, +/// 要使得动画能够持续,我们需要使用QWidget::update()在动画未完成时, +/// 手动更新一次,这样button将在一段时间后再次调用draw方法,从而达到更新动画的效果 +/// +/// 需要注意绘制背景的流程会因主题不同而产生差异,所以这一部分代码在一些主题中未必正常, +/// 如果你需要自己实现一个主题,这同样是你需要注意和考虑的点 +void customstyle_search_pushbutton::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + if (element == PE_PanelButtonCommand) { + if (widget) { + if (option->state & State_MouseOver) { + if (option->state & State_Sunken) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,21); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,31); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(19,19,20,0); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + return; + } + } + return QProxyStyle::drawPrimitive(element, option, painter, widget); +} + +QPixmap customstyle_search_pushbutton::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl customstyle_search_pushbutton::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +{ + return QProxyStyle::hitTestComplexControl(control, option, position, widget); +} + +QRect customstyle_search_pushbutton::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +} + +QRect customstyle_search_pushbutton::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +{ + return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +} + +int customstyle_search_pushbutton::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::pixelMetric(metric, option, widget); +} + +/// 我们需要将动画与widget一一对应起来, +/// 在一个style的生命周期里,widget只会进行polish和unpolish各一次, +/// 所以我们可以在polish时将widget与一个新的动画绑定,并且对应的在unpolish中解绑定 +void customstyle_search_pushbutton::polish(QWidget *widget) +{ + return QProxyStyle::polish(widget); +} + +void customstyle_search_pushbutton::polish(QApplication *application) +{ + return QProxyStyle::polish(application); +} + +void customstyle_search_pushbutton::polish(QPalette &palette) +{ + return QProxyStyle::polish(palette); +} + +void customstyle_search_pushbutton::unpolish(QWidget *widget) +{ + return QProxyStyle::unpolish(widget); +} + +void customstyle_search_pushbutton::unpolish(QApplication *application) +{ + return QProxyStyle::unpolish(application); +} + +QSize customstyle_search_pushbutton::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} + +QIcon customstyle_search_pushbutton::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::standardIcon(standardIcon, option, widget); +} + +QPalette customstyle_search_pushbutton::standardPalette() const +{ + return QProxyStyle::standardPalette(); +} + +int customstyle_search_pushbutton::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +QRect customstyle_search_pushbutton::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +{ + return QProxyStyle::subControlRect(control, option, subControl, widget); +} + +QRect customstyle_search_pushbutton::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::subElementRect(element, option, widget); +} diff --git a/src/plugins/ukui-sidebar-clipboard/customstyleSearchPushbutton.h b/src/plugins/ukui-sidebar-clipboard/customstyleSearchPushbutton.h new file mode 100644 index 0000000..1d55c39 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/customstyleSearchPushbutton.h @@ -0,0 +1,70 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +class customstyle_search_pushbutton : public QProxyStyle +{ + Q_OBJECT +public: + explicit customstyle_search_pushbutton(const QString &proxyStyleName = "windows", QObject *parent = nullptr); + virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + /*! + * \brief drawPrimitive + * \param element 背景绘制,对应PE枚举类型 + * \param option + * \param painter + * \param widget + * \details + * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, + * 我们一般需要判断控件的状态来绘制不同的背景, + * 比如按钮的hover和点击效果。 + */ + virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; + virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; + virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; + //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); + virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + + virtual void polish(QWidget *widget); + virtual void polish(QApplication *application); + virtual void polish(QPalette &palette); + virtual void unpolish(QWidget *widget); + virtual void unpolish(QApplication *application); + + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + virtual QPalette standardPalette() const; + virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; + + virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; + + virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; + +signals: + +public slots: + +private: +}; +#endif // CUSTOMSTYLE_SEARCH_PUSHBUTTON_H diff --git a/src/plugins/ukui-sidebar-clipboard/editorwidget.cpp b/src/plugins/ukui-sidebar-clipboard/editorwidget.cpp new file mode 100644 index 0000000..4e6fec7 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/editorwidget.cpp @@ -0,0 +1,176 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include + +EditorWidget::EditorWidget() +{ + if (QGSettings::isSchemaInstalled("org.ukui.control-center.personalise")) { + m_pTransparency = new QGSettings("org.ukui.control-center.personalise"); + m_tranSparency = m_pTransparency->get("transparency").toDouble(); + connect(m_pTransparency, &QGSettings::changed, this, [=](QString value) { + if (value == "transparency") { + m_tranSparency = m_pTransparency->get("transparency").toDouble(); + this->update(); + } + }); + } + + if (QGSettings::isSchemaInstalled("org.ukui.style")) { + m_pFont = new QGSettings("org.ukui.style"); + m_Fontsize = m_pFont->get("system-font-size").toInt(); + connect(m_pFont, &QGSettings::changed, this, [=](QString value) { + m_Fontsize = m_pFont->get("system-font-size").toInt(); + QFont font = m_ptileLable->font(); + font.setPixelSize(9 + m_Fontsize); + font.setFamily("Noto Sans CJK SC"); + m_ptileLable->setFont(font); + this->update(); + }); + } + + installEventFilter(this); + this->setFixedSize(400, 338); + this->setContentsMargins(0, 0, 0, 0); + this->setWindowTitle(QObject::tr("edit box")); + this->setWindowIcon(QIcon::fromTheme("kylin-clipboard")); + this->setWindowModality(Qt::NonModal); + this->setProperty("useSystemStyleBlur", true); + m_pMainQVBoxLayout = new QVBoxLayout(); + m_pMainQVBoxLayout->setContentsMargins(0, 0, 0, 0); + + editBox(); + operationBox(); + m_pConfirmButton->setObjectName("ConfirmButton"); + m_pCancelButton->setObjectName("CancelButton"); + connect(m_pConfirmButton, &QPushButton::clicked, this, &EditorWidget::accept); + connect(m_pCancelButton, &QPushButton::clicked, this, &EditorWidget::reject); + connect(m_pConfirmButton, &QPushButton::clicked, globalClipboardSignal, &ClipboardSignal::CLipBoardEditConfirmButtonSignal); + connect(m_pCancelButton, &QPushButton::clicked, globalClipboardSignal, &ClipboardSignal::CLipBoardEditConfirmButtonSignal); + m_pEditingArea->setObjectName("EditingArea"); + m_pEditingArea->setAcceptRichText(false); + m_pEditWidget->setObjectName("EditBox"); + m_pOperationWidget->setObjectName("OperationBox"); + this->setObjectName("EditorWidget"); + + m_pMainQVBoxLayout->setContentsMargins(18, 0, 0, 0); + m_pMainQVBoxLayout->addItem(new QSpacerItem(20, 24)); + m_pMainQVBoxLayout->addWidget(m_pEditWidget); + m_pMainQVBoxLayout->addItem(new QSpacerItem(20, 15)); + m_pMainQVBoxLayout->addWidget(m_pOperationWidget); + m_pMainQVBoxLayout->addItem(new QSpacerItem(20, 18)); + m_pMainQVBoxLayout->setSpacing(0); + this->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); + QScreen* pScreen = QGuiApplication::primaryScreen(); + QRect ScreenSize = pScreen->availableGeometry(); + int m_nScreenWidth = ScreenSize.width(); //屏幕分辨率的宽 + int m_nScreenHeight = ScreenSize.height(); //屏幕分辨率的高 + move(m_nScreenWidth/2-130, m_nScreenHeight/2-180); + setLayout(m_pMainQVBoxLayout); + setAttribute(Qt::WA_TranslucentBackground); +} + +/* 标题和编辑框界面 */ +void EditorWidget::editBox() +{ + m_pEditingArea = new QTextEdit(); + m_pEditingArea->setFixedSize(362, 200); + m_pEditingArea->setFrameShape(QFrame::NoFrame); + QColor color(255,255,255,16); + QPalette paletteTextEdit = m_pEditingArea->palette(); + paletteTextEdit.setBrush(QPalette::Base, color); + m_pEditingArea->setPalette(paletteTextEdit); + + m_ptileLable = new QLabel(QObject::tr("Edit")); + m_ptileLable->setFixedHeight(25); + QTimer::singleShot(1, m_ptileLable, [=](){ + QFont font = m_ptileLable->font(); + font.setPixelSize(9 + m_Fontsize); + font.setFamily("Noto Sans CJK SC"); + m_ptileLable->setFont(font); + }); + + m_pEditLaout = new QVBoxLayout; + m_pEditLaout->addWidget(m_ptileLable); + m_pEditLaout->addItem(new QSpacerItem(12, 22)); + m_pEditLaout->addWidget(m_pEditingArea); + m_pEditLaout->setSpacing(0); + m_pEditWidget = new QWidget(); + m_pEditWidget->setAttribute(Qt::WA_TranslucentBackground); + m_pEditWidget->setLayout(m_pEditLaout); + m_pEditLaout->setContentsMargins(0, 0, 0, 0); + return; +} + +/* 确认和取消按钮 */ +void EditorWidget::operationBox() +{ + m_pConfirmButton = new QPushButton(QObject::tr("Confirm")); + m_pConfirmButton->setFixedSize(120, 34); + m_pConfirmButton->setStyle(new CustomStyle("ukui-default")); + + m_pCancelButton = new QPushButton(QObject::tr("Cancel")); + m_pCancelButton->setFixedSize(120, 34); + m_pCancelButton->setStyle(new CustomStyle_pushbutton_2("ukui-default") ); + + m_pOperationLayout = new QHBoxLayout; + + m_pOperationLayout->setContentsMargins(0, 0, 0, 0); + m_pOperationLayout->addItem(new QSpacerItem(106, 20, QSizePolicy::Expanding)); + m_pOperationLayout->addWidget(m_pCancelButton); + m_pOperationLayout->addItem(new QSpacerItem(16, 20)); + m_pOperationLayout->addWidget(m_pConfirmButton); + m_pOperationLayout->addItem(new QSpacerItem(20, 20)); + m_pOperationLayout->setSpacing(0); + m_pOperationWidget = new QWidget(); + m_pOperationWidget->setContentsMargins(0, 0, 0, 0); + m_pOperationWidget->setLayout(m_pOperationLayout); + return; +} + +/* 重绘时间 */ +void EditorWidget::paintEvent(QPaintEvent *) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + p.setBrush(opt.palette.color(QPalette::Base)); + p.setOpacity(m_tranSparency); + p.setPen(Qt::NoPen); + + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.drawRoundedRect(opt.rect,6,6); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + +void EditorWidget::enterEvent(QEvent *event) +{ + Q_UNUSED(event); + if (!isActiveWindow()) { + activateWindow(); + } +} + +void EditorWidget::closeEvent(QCloseEvent *event) +{ + Q_UNUSED(event); +} diff --git a/src/plugins/ukui-sidebar-clipboard/editorwidget.h b/src/plugins/ukui-sidebar-clipboard/editorwidget.h new file mode 100644 index 0000000..3bc104a --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/editorwidget.h @@ -0,0 +1,77 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "customstyle.h" +#include "customstylePushbutton2.h" +#include "clipboardsignal.h" +#define SIDEBAR_EDITAREA_QSS_PATH ":/qss/sideBarEditArea.css" + +extern ClipboardSignal *globalClipboardSignal; +class EditorWidget :public QDialog +{ +public: + explicit EditorWidget(); + QPushButton *m_pConfirmButton; + QPushButton *m_pCancelButton; + QTextEdit *m_pEditingArea; + QLabel *m_ptileLable; + QGroupBox *m_pEditBox; + QWidget *m_pEditWidget; + QGroupBox *m_pOperationBox; + QWidget *m_pOperationWidget; + QVBoxLayout *m_pMainQVBoxLayout; //主界面垂直布局器 + QHBoxLayout *m_ptileLayout; + QVBoxLayout *m_pEditLaout; + QHBoxLayout *m_pOperationLayout; + QGSettings *m_pTransparency; // 插件的界面的透明度 + QGSettings *m_pFont; // 插件的界面的透明度 + double m_tranSparency = 1.0; + int m_Fontsize; + + void titleBox(); + void editBox(); + void operationBox(); + +protected: + void paintEvent(QPaintEvent *); + void enterEvent(QEvent *event); + void closeEvent(QCloseEvent *event); +}; + +#endif // EDITORWIDGET_H diff --git a/src/plugins/ukui-sidebar-clipboard/fileIcon.json b/src/plugins/ukui-sidebar-clipboard/fileIcon.json new file mode 100644 index 0000000..fc2e59b --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/fileIcon.json @@ -0,0 +1,25 @@ +{ + "txt": "text-x-generic", + "svg": "image-svg+xml", + "png": "image-x-generic", + "jpg": "image-x-generic", + "jpeg": "image-x-generic", + "bmp": "image-x-generic", + "gif": "image-x-generic", + "psd": "image-x-generic", + "xml": "text-xml", + "docx": "document", + "pptx": "application-mspowerpoint", + "xlsx": "application-msexcel", + "pdf": "application-pdf", + "zip": "application-zip", + "tar": "application-x-compressed-tar", + "7z": "application-x-compressed-tar", + "bz": "application-x-compressed-tar", + "car": "application-x-compressed-tar", + "cpgz": "application-x-compressed-tar", + "hbc": "application-x-compressed-tar", + "gz": "application-x-compressed-tar", + "xz": "application-x-compressed-tar" + +} diff --git a/src/plugins/ukui-sidebar-clipboard/image/button-close-default-add-background-three.svg b/src/plugins/ukui-sidebar-clipboard/image/button-close-default-add-background-three.svg new file mode 100644 index 0000000..d86ef7b --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/image/button-close-default-add-background-three.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-clipboard/image/button-close-hover-click-add-background-one.svg b/src/plugins/ukui-sidebar-clipboard/image/button-close-hover-click-add-background-one.svg new file mode 100644 index 0000000..7968eb6 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/image/button-close-hover-click-add-background-one.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/plugins/ukui-sidebar-clipboard/image/button-close-hover-click-two.svg b/src/plugins/ukui-sidebar-clipboard/image/button-close-hover-click-two.svg new file mode 100644 index 0000000..4a66e28 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/image/button-close-hover-click-two.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-clipboard/image/cancel-lock.png b/src/plugins/ukui-sidebar-clipboard/image/cancel-lock.png new file mode 100644 index 0000000..156817a Binary files /dev/null and b/src/plugins/ukui-sidebar-clipboard/image/cancel-lock.png differ diff --git a/src/plugins/ukui-sidebar-clipboard/image/copy.svg b/src/plugins/ukui-sidebar-clipboard/image/copy.svg new file mode 100644 index 0000000..273beed --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/image/copy.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/src/plugins/ukui-sidebar-clipboard/image/delete.svg b/src/plugins/ukui-sidebar-clipboard/image/delete.svg new file mode 100644 index 0000000..0bb446c --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/image/delete.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/src/plugins/ukui-sidebar-clipboard/image/editor.svg b/src/plugins/ukui-sidebar-clipboard/image/editor.svg new file mode 100644 index 0000000..881b3ce --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/image/editor.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/src/plugins/ukui-sidebar-clipboard/image/kylin-alarm-clock.svg b/src/plugins/ukui-sidebar-clipboard/image/kylin-alarm-clock.svg new file mode 100644 index 0000000..db3a197 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/image/kylin-alarm-clock.svg @@ -0,0 +1,57 @@ + + + +画板 18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/plugins/ukui-sidebar-clipboard/image/kylin-feedback.png b/src/plugins/ukui-sidebar-clipboard/image/kylin-feedback.png new file mode 100644 index 0000000..24eeda8 Binary files /dev/null and b/src/plugins/ukui-sidebar-clipboard/image/kylin-feedback.png differ diff --git a/src/plugins/ukui-sidebar-clipboard/image/lock.png b/src/plugins/ukui-sidebar-clipboard/image/lock.png new file mode 100644 index 0000000..79e5813 Binary files /dev/null and b/src/plugins/ukui-sidebar-clipboard/image/lock.png differ diff --git a/src/plugins/ukui-sidebar-clipboard/image/user-trash.png b/src/plugins/ukui-sidebar-clipboard/image/user-trash.png new file mode 100644 index 0000000..640abbc Binary files /dev/null and b/src/plugins/ukui-sidebar-clipboard/image/user-trash.png differ diff --git a/src/plugins/ukui-sidebar-clipboard/pixmaplabel.cpp b/src/plugins/ukui-sidebar-clipboard/pixmaplabel.cpp new file mode 100644 index 0000000..1c99e51 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/pixmaplabel.cpp @@ -0,0 +1,65 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see &list) +{ + m_pixmapList = list; + update(); +} + +void pixmapLabel::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(Qt::transparent); + + QStyle *style = QWidget::style(); + QStyleOption opt; + opt.initFrom(this); + int x = 4; + int y = 4; + //drawPixmaps + if (m_pixmapList.size() == 1) { + QPixmap pix = m_pixmapList[0]; + if (!isEnabled()) + pix = style->generatedIconPixmap(QIcon::Disabled, pix, &opt); + QPixmap newPix = pix.scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + style->drawItemPixmap(&painter, QRect(QPoint(4, 4), newPix.size()), Qt::AlignCenter, newPix); + } else { + for (int i = 0 ; i < m_pixmapList.size(); ++i) { + QPixmap pix = m_pixmapList[m_pixmapList.size() - i - 1]; + if (pix.size() == QSize(0, 0)) + continue; + if (!isEnabled()) + pix = style->generatedIconPixmap(QIcon::Disabled, pix, &opt); + QPixmap newPix = pix.scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + style->drawItemPixmap(&painter, QRect(QPoint(x, y), newPix.size()), Qt::AlignCenter, newPix); + x += 2; + y += 2; + } + } + return; +} diff --git a/src/plugins/ukui-sidebar-clipboard/pixmaplabel.h b/src/plugins/ukui-sidebar-clipboard/pixmaplabel.h new file mode 100644 index 0000000..6fcef54 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/pixmaplabel.h @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include + +class pixmapLabel : public QLabel +{ + Q_OBJECT +public: + pixmapLabel(); + QList m_pixmapList; + void setPixmapList(const QList &list); +protected: + void paintEvent(QPaintEvent *event); +}; + +#endif // PIXMAPLABEL_H diff --git a/src/plugins/ukui-sidebar-clipboard/previewimagewidget.cpp b/src/plugins/ukui-sidebar-clipboard/previewimagewidget.cpp new file mode 100644 index 0000000..28b16da --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/previewimagewidget.cpp @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see setFixedSize(260, 130); + int width = m_pLabel->width(); + int height = m_pLabel->height(); + QPixmap fitpixmap = (*pixmap).scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // 饱满填充 + m_pLabel->setPixmap(fitpixmap); + m_pVlaout = new QVBoxLayout(); + this->setContentsMargins(0, 0, 0, 0); + m_pVlaout->setContentsMargins(0, 0, 0, 0); + m_pVlaout->addWidget(m_pLabel); + this->setLayout(m_pVlaout); + this->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); +} diff --git a/src/plugins/ukui-sidebar-clipboard/previewimagewidget.h b/src/plugins/ukui-sidebar-clipboard/previewimagewidget.h new file mode 100644 index 0000000..5b90e11 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/previewimagewidget.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +class previewImageWidget : public QWidget +{ + Q_OBJECT +public: + previewImageWidget(QPixmap *pixmap, QWidget *parent = nullptr); + QLabel *m_pLabel; + QVBoxLayout *m_pVlaout; +}; + +#endif // PREVIEWIMAGEWIDGET_H diff --git a/src/plugins/ukui-sidebar-clipboard/qss/sideBarEditArea.css b/src/plugins/ukui-sidebar-clipboard/qss/sideBarEditArea.css new file mode 100644 index 0000000..829de5e --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/qss/sideBarEditArea.css @@ -0,0 +1,55 @@ +/* 编辑区域 */ +QGroupBox#EditBox { + width:362px; + height:200px; + margin-right: 20px; + margin-bottom: 5px; + margin-left: 3px; + margin-top: 45px; + padding-top:0px; + padding-bottom:0px; + padding-left:0px; + padding-right:0px; + background:rgba(255,255,255,0.06); + opacity:0.06; + border-radius:3px; + border: 0px solid rgba(255,255,0,1); + + font-size:20px; + font-family:Noto Sans CJK SC; + font-weight:400; + color:rgba(255,255,255,1); + line-height:40px; + opacity:0.91; +} + +/* 操作区域,确认取消 */ +QGroupBox#OperationBox { + width:362px; + height:40px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 20px; + margin-top: 0px; + border-radius:0px; + padding-top:0px; + padding-bottom:0px; + color:rgba(255,255,255,1); + border: 0px; +} + +/* 编辑WIdget的编辑区域 */ +QGroupBox#EditBox>QTextEdit#EditingArea { + font-size:14px; + font-weight:400; + font-family:Noto Sans CJK SC; + color:rgba(255,255,255,1); + width:340px; + height:180px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + margin-top: 0px; + background-color:rgba(255,255,255,0.01); + border: 0px solid rgba(255,0,0,1); +} diff --git a/src/plugins/ukui-sidebar-clipboard/qss/sideBarSearchArea.css b/src/plugins/ukui-sidebar-clipboard/qss/sideBarSearchArea.css new file mode 100644 index 0000000..54d4110 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/qss/sideBarSearchArea.css @@ -0,0 +1,58 @@ +/* 搜索栏的Widget */ +QWidget#SearhWidget{ + width:380px; + height:40; + margin-top: 0px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:0px; + background:rgba(19, 19, 20, 1); + opacity:0; + border: 0px solid rgba(255,255,0,1); +} + +/* 清空所有的WidgetItem按扭 */ +QWidget#SearhWidget>QPushButton#CleanList { + width:80px; + height:34px; + margin-top:0px; + margin-left:5px; + margin-bottom:0px; + margin-right:10px; + + font-size:11px; + font-family:Noto Sans CJK SC; + font-weight:400; + color:rgba(255,255,255,1); + line-height:24px; + opacity:0.91; + border:0px solid rgba(255,0,0,1); +} + +/* 清空所有的WidgetItem按扭悬浮时的效果 */ +QWidget#SearhWidget>QPushButton#CleanList:hover{ + background-color:rgba(255,255,255,36); /*改变背景色*/ + border-style:inset; /*改变边框风格*/ + + border: 0px solid rgba(255,0,0,1); +} + +/* 清空所有的WidgetItem按扭按下时的效果 */ +QWidget#SearhWidget>QPushButton#CleanList:pressed{ + background-color:rgba(255,255,255,25); /*改变背景色*/ + border-style:inset;/*改变边框风格*/ + + border: 0px solid rgba(255,0,0,1); +} + +/* 清空所有的QlineEdit按扭 */ +QLineEdit#SearchLabel>QPushButton#ClearTextButton { + width:9px; + height:9px; + border-radius:9px; + border:0px solid rgba(255,255,0,1); +} diff --git a/src/plugins/ukui-sidebar-clipboard/qss/sidebarClipboard.css b/src/plugins/ukui-sidebar-clipboard/qss/sidebarClipboard.css new file mode 100644 index 0000000..447a75e --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/qss/sidebarClipboard.css @@ -0,0 +1,315 @@ +QPalette{background:#131314;} + +/* 搜索栏的Widget */ +/*QWidget#SearhWidget { + margin-top: 0px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:0px; + width:380px; + height:40; + background:rgba(19, 19, 20, 0); + opacity:0; + border: 1px solid rgba(255,255,0,1); +}*/ + +/* listWidget的中的widgetitem */ +QWidget#WidgetEntry { + width:400px; + height:42px; + + margin-top: 0px; + margin-bottom: 0px; + margin-right: 0px; + margin-left: 0px; + + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:0px; + background:rgba(255, 255, 255, 0); + border: 0px solid rgba(255,0,0,1); + opacity:0.08; + border-bottom: 1px solid rgba(255,255,255,0.08); +} + +/* 设置listWidget的中的widgetitem悬乎状态 */ +/*QWidget#WidgetEntry:hover { + background:rgba(255, 255, 255, 0.08); +}*/ + +/* 显示内容条目Widget中的置顶按钮 */ +/*QWidget#WidgetEntry>QPushButton#PopButton { + width:34px; + height:34px; + margin-bottom: 0px; + margin-top: 0px; + margin-right: 0px; + margin-left: 0px; + border: 0px solid rgba(255,0,0,1); + background:rgba(255,255,255,30); + opacity:0.12; + border-radius:3px; +} + + +QWidget#WidgetEntry>QPushButton#PopButton:hover { + background-color:rgba(255,255,255,36); + opacity:0.2; + border: 0px solid rgba(255,0,0,1); +} + + +QWidget#WidgetEntry>QPushButton#PopButton:pressed { + background-color:rgba(255,255,255,0.08); + opacity:0.08; + border: 0px solid rgba(255,0,0,1); +}*/ + +/* 显示内容条目Widget中的编辑按钮 */ +/*QWidget#WidgetEntry>QPushButton#EditButon { + width:34px; + height:34px; + margin-bottom: 0px; + margin-top: 0px; + margin-right: 0px; + margin-left: 0px; + border: 0px solid rgba(255,0,0,1); + background:rgba(255,255,255,30); + opacity:0.12; + border-radius:3px; +}*/ + +/* 显示内容条目Widget中的置编辑钮悬乎 */ +/*QWidget#WidgetEntry>QPushButton#EditButon:hover { + background-color:rgba(255,255,255,36); + border-radius:3px; + opacity:0.2; + border: 0px solid rgba(255,0,0,1); +}*/ + +/* 显示内容条目Widget中的编辑按钮按下 */ +/*QWidget#WidgetEntry>QPushButton#EditButon:pressed { + background-color:rgba(255,255,255,25); + border-radius:3px; + opacity:0.08; + border: 0px solid rgba(255,0,0,1); +}*/ + +/* 显示内容条目Widget中的删除按钮 */ +/*QWidget#WidgetEntry>QPushButton#RemoveButton { + width: 34px; + height: 34px; + margin-bottom: 0px; + margin-top: 0px; + margin-right: 0px; + margin-left: 0px; + border: 0px solid rgba(255,0,0,1); + background:rgba(255,255,255,30); + opacity: 0.12; + border-radius: 3px; +}*/ + +/* 显示内容条目Widget中的删除按钮悬乎 */ +/*QWidget#WidgetEntry>QPushButton#RemoveButton:hover { + background-color:rgba(255,255,255,36); + opacity:0.2; + border-radius:3px; + border: 0px solid rgba(255,0,0,1); +}*/ + +/* 显示内容条目Widget中的删除按钮按下 */ +/*QWidget#WidgetEntry>QPushButton#RemoveButton:pressed { + background-color:rgba(255,255,255,0.08); + opacity:0.08; + border: 0px solid rgba(255,0,0,1); +}*/ + +/* 清空所有的WidgetItem按扭 */ +/*QWidget#SearhWidget>QPushButton#CleanList { + width:80px; + height:34px; + margin-top:0px; + margin-left:0px; + margin-bottom:0px; + margin-right:0px; + + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:0px; + border-radius:4px; + font-size:14px; + font-family:Noto Sans CJK SC; + font-weight:400; + color:rgba(255,255,255,1); + line-height:24px; + opacity:0.91; + border:0px solid rgba(255,0,0,1); +}*/ + +/* 清空所有的WidgetItem按扭悬浮时的效果 */ +/*QWidget#SearhWidget>QPushButton#CleanList:hover{ + background-color:rgba(255,255,255,36); + border-style:inset; + + border: 0px solid rgba(255,0,0,1); +}*/ + +/* 清空所有的WidgetItem按扭按下时的效果 */ +/*QWidget#SearhWidget>QPushButton#CleanList:pressed{ + background-color:rgba(255,255,255,25); + border-style:inset; + + border: 0px solid rgba(255,0,0,1); +}*/ + +/* 清空所有的QlineEdit按扭 */ +QLineEdit#SearchLabel>QPushButton#ClearTextButton { + margin-top:0px; + margin-left:0px; + margin-bottom:2px; + margin-right:0px; + + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:0px; + border-radius:0.5px; + border:0px solid rgba(255,255,0,1); +} + +/* 查找栏的Lable */ +/*QWidget#SearhWidget>QLineEdit#SearchLabel { + width:280px; + height:30px; + margin-top: 0px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:3px; + background:rgba(0,0,0,0.2); + border:0px solid rgba(61,107,229,1); + border-radius:4px; + + font-size:14px; + font-family:Noto Sans CJK SC; + font-weight:400; + color:rgba(255,255,255,1); + line-height:24px; + opacity:0.91; + +}*/ + +/* 查找栏的Lable悬乎状态 */ +/*QWidget#SearhWidget>QLineEdit#SearchLabel:hover { + border-style:inset; + border: 1px solid rgba(61,107,229,1); + border-radius:4px; +}*/ + +/* 查找栏的Lable焦点状态 */ +/*QWidget#SearhWidget>QLineEdit#SearchLabel:focus { + border-style:inset; + border: 1px solid rgba(28, 47, 146, 1); + border-radius:4px; +}*/ + +/* 显示所有剪贴内容的WidgetList大小 */ +QListWidget#ShortcutOperationList { + width:400px; + height:760px; + + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + margin-top: 0px; + + padding-top:0px; + padding-bottom:0px; + padding-left:0px; + padding-right:0px; + background:rgba(19, 19, 20, 0); + opacity:0; + border:0px; +} + +QListWidget#SearchWidgetListWidget { + width:400px; + height:34px; + + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + margin-top: 2px; + + padding-top:0px; + padding-bottom:0px; + padding-left:0px; + padding-right:0px; + background:rgba(19, 19, 20, 0); + opacity:0; + border: 0px solid rgba(255,0,255,0); + border:0px; +} + +/* widget条目的Lable */ +/*QWidget#WidgetEntry>QLabel#EntryLable { + width:200px; + height:34px; + font-size:15px; + font-weight:400; + + margin-top: 0px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:3px; + font-size:14px; + font-family:Noto Sans CJK SC; + font-weight:400; + color:rgba(255,255,255,1); + line-height:40px; + opacity:0.91; +}*/ + +QListWidget:Item{ + margin-top: 0px; + margin-right: 0px; + margin-bottom: 0px; + margin-left: 0px; + + padding-right: 0px; + padding-top: 0px; + padding-bottom:0px; + padding-left:0px; + background:rgba(19, 19, 20, 0); + border: 0px solid rgba(255,255,0,1); +} + +/* 无剪贴板内容字样 */ +/*QLabel#SideBarClipboardLable{ + width:70px; + height:14px; + margin-top:50px; + margin-left:165px; + margin-bottom:100px; + margin-right:132px; + font-size:14px; + font-family:Noto Sans CJK SC; + font-weight:400; + color:rgba(255,255,255,1); + line-height:28px; + opacity:0.57; +}*/ diff --git a/src/plugins/ukui-sidebar-clipboard/searchwidgetitemcontent.cpp b/src/plugins/ukui-sidebar-clipboard/searchwidgetitemcontent.cpp new file mode 100644 index 0000000..51cd247 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/searchwidgetitemcontent.cpp @@ -0,0 +1,99 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include + +SearchWidgetItemContent::SearchWidgetItemContent(QWidget *parent) +{ + Q_UNUSED(parent); + + this->setObjectName("SearhWidget"); + this->setContentsMargins(0,0,0,0); + m_pClearListWidgetButton = new QPushButton(tr("Clear")); + m_pClearListWidgetButton->setFixedSize(80, 34); + m_pClearListWidgetButton->setStyle(new customstyle_search_pushbutton("ukui-default")); + m_pClearListWidgetButton->setObjectName("CleanList"); + + m_pClearTextButton = new QPushButton; + m_pClearTextButton->setFixedSize(19, 21); + m_pClearTextButton->setIconSize(QSize(9, 9)); + m_pClearTextButton->setObjectName("ClearTextButton"); + m_pClearTextButton->setStyleSheet("QPushButton:pressed{border-image:url(:/image/button-close-hover-click-add-background-one.svg)}"); + m_pClearTextButton->setStyleSheet("QPushButton:hover{border-image:url(:/image/button-close-hover-click-add-background-one.svg)}"); + + QIcon ClearTextEditIcon; + ClearTextEditIcon.addFile(SEARCH_SVG_CLEAN); + m_pClearTextButton->setIcon(ClearTextEditIcon); + m_pClearTextButton->setCursor(Qt::ArrowCursor); + + m_pHBoxLayout = new QHBoxLayout; + m_pHBoxLayout->setContentsMargins(0,0,0,0); + m_pLineEditArea = new QLineEdit; + m_pLineEditArea->setAttribute(Qt::WA_Hover, true); + m_pLineEditArea->setStyle(new CustomStyle("")); + m_pLineEditArea->setFixedSize(264, 40); + m_pLineEditArea->setObjectName("SearchLabel"); + m_pLineEditArea->setTextMargins(8, 0, 0, 0); + m_pLineEditArea->setPlaceholderText(tr("search...")); + + connect(m_pLineEditArea, &QLineEdit::textChanged, this, &SearchWidgetItemContent::textChageSlots); + /* Sets the font color of the placeholder */ + QFont SearchLine; + SearchLine = m_pLineEditArea->font(); + SearchLine.setPixelSize(14); +// SearchLine.setFamily("Noto Sans CJK SC"); + m_pLineEditArea->setFont(SearchLine); + +#if QT_VERSION >= 0x050c00 + QBrush LineEditBrush; + QPalette paletteLineEdit; + QColor ColorPlaceholderText(255,255,255,89); + LineEditBrush = paletteLineEdit.placeholderText(); + LineEditBrush.setColor(ColorPlaceholderText); + paletteLineEdit.setBrush(QPalette::PlaceholderText, LineEditBrush); + m_pLineEditArea->setPalette(paletteLineEdit); +#endif + QWidgetAction* action = new QWidgetAction(m_pLineEditArea); + action->setDefaultWidget(m_pClearTextButton); + + m_pLineEditArea->addAction(action, QLineEdit::TrailingPosition); + m_pClearTextButton->setVisible(false); + connect(m_pClearTextButton, &QPushButton::clicked, this, [=](){ + m_pLineEditArea->setText(""); + }); + m_pHBoxLayout->addItem(new QSpacerItem(10,20)); + m_pHBoxLayout->addWidget(m_pLineEditArea); + m_pHBoxLayout->addItem(new QSpacerItem(36,20)); + m_pHBoxLayout->addWidget(m_pClearListWidgetButton); + m_pHBoxLayout->addItem(new QSpacerItem(10,20)); + m_pHBoxLayout->setSpacing(0); + this->setLayout(m_pHBoxLayout); +} + +void SearchWidgetItemContent::textChageSlots(const QString &text) +{ + if (text != "") { + m_pClearTextButton->setVisible(true); + } else { + m_pClearTextButton->setVisible(false); + } +} diff --git a/src/plugins/ukui-sidebar-clipboard/searchwidgetitemcontent.h b/src/plugins/ukui-sidebar-clipboard/searchwidgetitemcontent.h new file mode 100644 index 0000000..4fb32f6 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/searchwidgetitemcontent.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include "customstyle.h" +#include "customstyleSearchPushbutton.h" +#include "clipboardwidgetentry.h" +#include "clipboardsignal.h" +extern ClipboardSignal *globalClipboardSignal; +#define SIDEBAR_SEARCH_QSS_PATH ":/qss/sideBarSearchArea.css" +class SearchWidgetItemContent:public QWidget +{ + Q_OBJECT +public: + SearchWidgetItemContent(QWidget *parent = nullptr); + QPushButton *m_pClearTextButton; + QPushButton *m_pClearListWidgetButton; + QLineEdit *m_pLineEditArea; + QHBoxLayout *m_pHBoxLayout; + QTranslator *translator; +private slots: + void textChageSlots(const QString &text); +}; + +#endif // SEARCHWIDGETITEMCONTENT_H diff --git a/src/plugins/ukui-sidebar-clipboard/sidebarclipboardplugin.cpp b/src/plugins/ukui-sidebar-clipboard/sidebarclipboardplugin.cpp new file mode 100644 index 0000000..361b391 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/sidebarclipboardplugin.cpp @@ -0,0 +1,1419 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include + +ClipboardSignal *globalClipboardSignal; +SidebarClipboardPlugin::SidebarClipboardPlugin(QObject *parent) +{ + Q_UNUSED(parent); + translator = new QTranslator; + QTranslator *translator_qt = new QTranslator; + //获取系统语言环境 选择翻译文件 + if (translator->load(QLocale(), QLatin1String("ukui-sidebar-clipboard"), QLatin1String("_"), QLatin1String("/usr/share/ukui-sidebar/ukui-sidebar-clipboard"))) + QApplication::installTranslator(translator); + else + qDebug() << "cannot load translator ukui-clipboard_" << QLocale::system().name() << ".qm!"; + if (translator_qt->load("/usr/share/qt5/translations/qt_"+QLocale::system().name())) + QApplication::installTranslator(translator_qt); + else + qDebug() << "cannot load translator ukui-feedback_" << QLocale::system().name() << ".qm!"; + + installEventFilter(this); + initFileIconJson(); + + m_bPromptBoxBool = true; + m_pClipboardDb = new clipboardDb(); + + /* 创建剪贴板主Widget和搜索栏与条目的ListWidget界面 */ + createWidget(); + + /* 创建无剪贴板板字样 */ + createTipLable(); + + /* 创建查找条目 */ + createFindClipboardWidgetItem(); + + /* 插件内部通信的信号类 */ + ClipBoardInternalSignal::initInternalSignal(); + ClipBoardInternalSignal *InternalSignal = ClipBoardInternalSignal::getGlobalInternalSignal(); + + /* 在点击确认键后判断是否有勾选不再提示这一功能 */ + connect(InternalSignal, &ClipBoardInternalSignal::CheckBoxSelectedSignal, this, [=]() { + m_bPromptBoxBool = false; + }); + + /* 当剪贴板条目发生变化的时候执行该槽函数 */ + connect(this, &SidebarClipboardPlugin::Itemchange, this, &SidebarClipboardPlugin::ItemNumchagedSlots); + + /* 将控件加入到剪贴板界面中 */ + m_pClipboardLaout = new QVBoxLayout; + m_pClipboardLaout->setContentsMargins(0,0,0,0); + m_pClipboardLaout->addWidget(m_pSearchWidgetListWidget); + m_pClipboardLaout->addWidget(m_pShortcutOperationListWidget); + m_pClipboardLaout->addWidget(m_pSideBarClipboardLable); +// m_pClipboardLaout->addItem(new QSpacerItem(1, 100, QSizePolicy::Expanding, QSizePolicy::Fixed)); + + m_pSidebarClipboardWidget->setLayout(m_pClipboardLaout); + m_pShortcutOperationListWidget->setVisible(false); + + m_pShortcutOperationListWidget->setObjectName("ShortcutOperationList"); + m_pSearchWidgetListWidget->setObjectName("SearchWidgetListWidget"); + m_pSideBarClipboardLable->setObjectName("SideBarClipboardLable"); + + /* 监听系统剪贴板 */ + m_pSidebarClipboard = QApplication::clipboard(); + connect(m_pSidebarClipboard, &QClipboard::dataChanged, this, &SidebarClipboardPlugin::createWidgetEntry); + + /* 加载数据中中保存的数据,使用线程去加载 */ + m_pThread = new QThread; + connect(m_pThread, &QThread::started,this, &SidebarClipboardPlugin::loadClipboardDb); + m_pThread->start(); + +// resetWidgetLabelText(); + + /* 加载样式表 */ + QFile file(SIDEBAR_CLIPBOARD_QSS_PATH); + if (file.open(QFile::ReadOnly)) { + QString strQss = QLatin1String(file.readAll()); + m_pSidebarClipboardWidget->setStyleSheet(strQss); + file.close(); + } +} + +void SidebarClipboardPlugin::initFileIconJson() +{ + /*解析json文件*/ + QFile file(":/fileIcon.json"); + file.open(QIODevice::ReadOnly | QIODevice::Text); + QString value = file.readAll(); + file.close(); + + m_pDocument = QJsonDocument::fromJson(value.toUtf8(), &m_pErr_rpt); //字符串格式化为JSON + if(m_pErr_rpt.error != QJsonParseError::NoError) + { + qWarning() << "JSON格式错误"; + return; + } + m_pJsonObject = m_pDocument.object(); + +} + +/* 创建剪贴板主Widget和搜索栏与条目的ListWidget界面 */ +void SidebarClipboardPlugin::createWidget() +{ + m_pSidebarClipboardWidget = new QWidget(); + m_pSidebarClipboardWidget->setObjectName("ClipboardWidget"); + m_pSidebarClipboardWidget->setContentsMargins(0,0,0,0); + + m_pShortcutOperationListWidget = new ClipBoardLisetWidget; + m_pShortcutOperationListWidget->verticalScrollBar()->setProperty("drawScrollBarGroove", false); + m_pShortcutOperationListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); //隐藏横向滚动条 + m_pShortcutOperationListWidget->setContentsMargins(0,0,0,0); + m_pShortcutOperationListWidget->setFixedWidth(400); + + m_pSearchWidgetListWidget = new QListWidget; + m_pSearchWidgetListWidget->setFixedSize(400, 50); + m_pSearchWidgetListWidget->setContentsMargins(0,0,0,0); +} + +/* 创建无剪贴板板字样 */ +void SidebarClipboardPlugin::createTipLable() +{ + m_pSideBarClipboardLable = new QLabel(tr("No clip content")); + m_pSideBarClipboardLable->setContentsMargins(165, 0, 0, 50); +// QTimer::singleShot(1, m_pSideBarClipboardLable, [=](){ +// QFont font = m_pSideBarClipboardLable->font(); +// font.setPixelSize(14); +// font.setFamily("Noto Sans CJK SC"); +// m_pSideBarClipboardLable->setFont(font); +// }); +} + +/* 构造原型的QMimeData数据类型 */ +QMimeData * SidebarClipboardPlugin::copyMinedata(const QMimeData* mimeReference) +{ + QMimeData *mimecopy = new QMimeData(); + foreach (QString format, mimeReference->formats()) { + + QByteArray data = mimeReference->data(format); +// if (format.startsWith("x-special/ukui-copied-files")) { +// int indexBegin = format.indexOf('""') + 1; +// int indexEnd = format.indexOf('""', indexBegin); +// format = format.mid(indexBegin, indexEnd - indexBegin); +// } + mimecopy->setData(format, data); +// qDebug() << "剪贴板数据的格式" << format; + } + + return mimecopy; +} + +/* 获取剪贴板的中widgetItem这一条目 */ +QListWidget* SidebarClipboardPlugin::getClipbaordListWidget() +{ + if (m_pShortcutOperationListWidget != nullptr) + return m_pShortcutOperationListWidget; + return nullptr; +} + +/* 创建与侧边栏主app通信类 */ +SidebarClipBoardSignal* SidebarClipboardPlugin :: createClipSignal() +{ + m_pClipSignal = new ClipboardSignal; + globalClipboardSignal = m_pClipSignal; + connect(m_pClipSignal, &ClipboardSignal::ClipboardPreviewSignal, this, [=](int width, int height, int x, int y, int taskHeight){ + m_nScreenWidth = width; + m_nScreenHeight = height; + m_nclipboardsite_x = x; + m_nclipboardsite_y = y; + m_taskHeight = taskHeight; + m_pSideBarClipboardLable->setFixedSize(400, m_pSidebarClipboardWidget->height() - m_pSearchWidgetListWidget->height()); + }); + return m_pClipSignal; +} + +/* 侧边栏接口,将整个剪贴板界面set进入侧边栏 */ +QWidget* SidebarClipboardPlugin::getClipbaordGroupBox() +{ + if (m_pSidebarClipboardWidget != nullptr) + return m_pSidebarClipboardWidget; + return nullptr; +} + +/* 创建查找条目 */ +void SidebarClipboardPlugin::createFindClipboardWidgetItem() +{ + QListWidgetItem *pListWidgetItem = new QListWidgetItem; + pListWidgetItem->setFlags(Qt::NoItemFlags); + m_pSearchArea = new SearchWidgetItemContent; + m_pSearchArea->setFixedHeight(50); + connect(m_pSearchArea->m_pClearListWidgetButton, &QPushButton::clicked, this, &SidebarClipboardPlugin::removeAllWidgetItem); + + connect(m_pSearchArea->m_pLineEditArea, SIGNAL(textChanged(QString)), this, SLOT(searchClipboardLableTextSlots(QString))); + pListWidgetItem->setSizeHint(QSize(400,38)); + m_pSearchWidgetListWidget->insertItem(0,pListWidgetItem); + m_pSearchWidgetListWidget->setItemWidget(pListWidgetItem, m_pSearchArea); +} + +/*创建Widgetitem条目*/ +void SidebarClipboardPlugin::createWidgetEntry() +{ + const QMimeData *mimeData = m_pSidebarClipboard->mimeData(); + if (nullptr == mimeData) { + qWarning() << "createWidgetEntry形参mimeData为空, 不创建"; + return; + } + QString text; + QString format; + QList fileUrls; + QListWidgetItem *pListWidgetItem = new QListWidgetItem; + OriginalDataHashValue *s_pDataHashValue = new OriginalDataHashValue; + bool DeleteFlag = false; + + if (mimeData->hasImage()) { + s_pDataHashValue->p_pixmap = new QPixmap((qvariant_cast(mimeData->imageData()))); + format = IMAGE; + if(mimeData->hasText()){ + text = mimeData->text(); + format = TEXT; + } + if (nullptr == s_pDataHashValue->p_pixmap) { + qWarning() << "构造数据类型有错误-->p_pixmap == nullptr"; + return; + } + } else if (nullptr == mimeData->urls().value(0).toString()) { + s_pDataHashValue->p_pixmap = nullptr; + text = mimeData->text(); + format = TEXT; + } else if(mimeData->urls().value(0).toString() != "") { + s_pDataHashValue->p_pixmap = nullptr; + fileUrls = mimeData->urls(); + format = URL; + for (int i = 0; i < fileUrls.size(); ++i) { + if (i == 0) { + text += fileUrls.value(i).toString(); + } else { + text += "\n" + fileUrls.value(i).toString(); + } + } + } else if(mimeData->hasHtml()) { + qDebug() << "文本为Html"; + } else { + qWarning() << "剪贴板数据为空"; + return; + } + + if (text == "" && s_pDataHashValue->p_pixmap == nullptr) { + qWarning() << "text文本为空 或者 s_pDataHashValue->p_pixmap == nullptr"; + return ; + } + if (format == TEXT || format == URL) { + /* 过滤重复文本 */ + if(booleanExistWidgetItem(text)) { + DeleteFlag = true; + } + } else if (format == IMAGE) { + /* 过滤重复图片 */ + if (booleanExistWidgetImagin(*s_pDataHashValue->p_pixmap)) { + DeleteFlag = true; + } + } + + ClipboardWidgetEntry *w = new ClipboardWidgetEntry(format); + + + if (DeleteFlag) { + qDebug() << "此数据已存在,就是当前置顶的条数"; + delete pListWidgetItem; + delete w; + delete s_pDataHashValue; + return; + } + + /* hash插入QMimeData,保留原数据 */ + s_pDataHashValue->WidgetEntry = w; + s_pDataHashValue->MimeData = nullptr; + s_pDataHashValue->Clipbaordformat = format; + s_pDataHashValue->associatedDb = ""; + if (s_pDataHashValue->Clipbaordformat == TEXT) { + s_pDataHashValue->text = text; + } else if (s_pDataHashValue->Clipbaordformat == URL) { + s_pDataHashValue->urls = fileUrls; + s_pDataHashValue->text = text; + } + + setOriginalDataSequence(s_pDataHashValue); //设置Sequence; + qDebug() << "hash表中的Sequence" << s_pDataHashValue->Sequence; + + registerWidgetOriginalDataHash(pListWidgetItem, s_pDataHashValue); + /* 当超过一定数目的WidgetItem数目时,删除最后一条消息 */ + if (m_pShortcutOperationListWidget->count() >= WIDGET_ENTRY_COUNT) { + removeLastWidgetItem(); + } + setEntryItemSize(s_pDataHashValue, w, pListWidgetItem); + pListWidgetItem->setFlags(Qt::NoItemFlags); + + /* 将text和图片写入到Widget */ + AddWidgetEntry(s_pDataHashValue, w, text); + /* 将按钮与槽对应上 */ + connectWidgetEntryButton(w); + + /* 插入剪贴板条目 */ + m_pShortcutOperationListWidget->insertItem(0, pListWidgetItem); + m_pShortcutOperationListWidget->setItemWidget(pListWidgetItem, w); + emit Itemchange(); +} + +/* 根据剪贴板内容格式,写入到Label中 */ +void SidebarClipboardPlugin::AddWidgetEntry(OriginalDataHashValue *s_pDataHashValue, ClipboardWidgetEntry *w, QString text) +{ + if (s_pDataHashValue->Clipbaordformat == TEXT) { + // 设置...字样 + w->m_pCopyDataLabal->setTextFormat(Qt::PlainText); + w->m_pCopyDataLabal->setText(SetFormatBody(text, w)); + } else if (s_pDataHashValue->Clipbaordformat == IMAGE) { + int width = w->m_pCopyDataLabal->width(); + int height = w->m_pCopyDataLabal->height(); + QPixmap fitpixmap = (*s_pDataHashValue->p_pixmap).scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // 饱满填充 + w->m_pCopyDataLabal->setPixmap(fitpixmap); + } else if (s_pDataHashValue->Clipbaordformat == URL) { + w->m_pCopyDataLabal->setTextFormat(Qt::PlainText); + if (s_pDataHashValue->urls.size() == 1) { + //判断文件类型,根据文件类型去读取主题图标 +// QString filename = catUrlFileName(text); + QUrl texturl(text); + QString filename=texturl.fileName(); + filename = setMiddleFormatBody(filename, w); + w->m_pCopyDataLabal->setText(filename); + getPixmapListFileIcon(text, w->m_pCopyFileIcon); + } else { + //当有多个文件时,显示特定图标,和特定的字符串显示 + QString specificText = setSpecificString(text); + specificText = setMiddleFormatBody(specificText, w); + w->m_pCopyDataLabal->setText(specificText); + /* 获取QPixmap链表 */ + getPixmapListFileIcon(text, w->m_pCopyFileIcon); + } + } + if (s_pDataHashValue->associatedDb == DBDATA) { + w->m_bWhetherFix = true; //数据库加载的都需要置为已经固定 + w->m_pPopButton->setVisible(false); + w->m_pCancelLockButton->setVisible(false); + } + return; +} + +/* 设置...字样 */ +QString SidebarClipboardPlugin::SetFormatBody(QString text, ClipboardWidgetEntry *w) +{ + if (w->m_pCopyDataLabal == nullptr) { + qDebug()<<"未实例化"; + } + + QFontMetrics fontMetrics(w->m_pCopyDataLabal->font()); + int LableWidth = w->m_pCopyDataLabal->width(); + int fontSize = fontMetrics.width(text); + QString formatBody = text; + if(fontSize > (LableWidth - 10)) { + QStringList list = formatBody.split("\n"); + if (list.size() >= 2) { + //当有几行时,只需要截取第一行就行,在第一行后面加... + // 判断第一行是否是空行 + formatBody = judgeBlankLine(list); + formatBody = formatBody + "aa"; + int oneFontSize = fontMetrics.width(formatBody); + if (oneFontSize > (LableWidth - 10)) { + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, LableWidth - 10); + return formatBody; + } else { + if (!substringSposition(formatBody, list)) { + int oneFontSize = fontMetrics.width(formatBody); + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, oneFontSize - 1); + return formatBody; + } + } + } else { + //说明只存在一行,在最后面加...就行 + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, LableWidth - 10); + return formatBody; + } + } else { + QStringList list = formatBody.split("\n"); + if (list.size() >= 2) { + //取得当前的有字符串的子串 + formatBody = judgeBlankLine(list); + formatBody = formatBody + "aa"; + if (!substringSposition(formatBody, list)) { + int oneFontSize = fontMetrics.width(formatBody); + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, oneFontSize - 1); + } + } + } + + return formatBody; +} + +void SidebarClipboardPlugin::getPixmapListFileIcon(QString UrlText, pixmapLabel *pixmapListclass) +{ + QStringList FileNameList = UrlText.split("\n"); + QList pixmapList; + int tmp = FileNameList.count(); + int cnt = 1; + for (int i = 0; i < tmp; i++) { + QIcon icon = fileSuffixGetsIcon(FileNameList[i]); + QPixmap pixmap = icon.pixmap(QSize(16, 16)); + pixmapList.append(pixmap); + if (cnt >= 3) { + break; + } + cnt++; + } + pixmapListclass->setPixmapList(pixmapList); + return; +} + +/* 复制多文件文件的时候, 从文本中间插入...字样 */ +QString SidebarClipboardPlugin::setMiddleFormatBody(QString text, ClipboardWidgetEntry *w) +{ + QFontMetrics fontMetrics(w->m_pCopyDataLabal->font()); + int LableWidth = w->m_pCopyDataLabal->width(); + int fontSize = fontMetrics.width(text); + QString formatBody = text; + if (fontSize > (LableWidth - 20)) { + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideMiddle, LableWidth - 20); + return formatBody; + } + return formatBody; +} + +/* 复制多个文件时设置特定的字符串 */ +QString SidebarClipboardPlugin::setSpecificString(QString text) +{ + //对字符串进行截取 + QStringList UrlList = text.split("\n"); + int tmp = UrlList.count(); //记录文件个数 + QString UrlOne = catUrlFileName(UrlList[0]); + QString specificText = UrlOne + QStringLiteral(" 等%1个文件").arg(tmp); + return specificText; +} + +QString SidebarClipboardPlugin::catUrlFileName(QString Url) +{ + QStringList UrlList = Url.split("/"); + int tmp = UrlList.count(); + return UrlList[tmp - 1]; +} + +/* 设置每一个条目中的Sequence */ +void SidebarClipboardPlugin::setOriginalDataSequence(OriginalDataHashValue *value) +{ + if (m_pClipboardDataHash.count() == 0) { + value->Sequence = 0; + } else { + value->Sequence = iterationDataHashSearchSequence(m_pClipboardDataHash.count()); + } + return; +} + +/* 去除掉空行,显示有字体的行 */ +QString SidebarClipboardPlugin::judgeBlankLine(QStringList list) +{ + int tmp = list.count(); + for (int i = 0; i < tmp; i++) { + QString dest = list.at(i); + dest = dest.trimmed(); + if (dest.size() != 0) { + return list.at(i); + } + } + return list.at(0); +} + +/* 判断当前子串位置,后面是否还有子串 */ +bool SidebarClipboardPlugin::substringSposition(QString formatBody, QStringList list) +{ + int tmp = list.count(); + for (int i = 0; i < tmp; i++) { + QString dest = list.at(i); + if (dest == formatBody && i == tmp - 1) { + qDebug() << "后面没有字串,返回true"; + return true; + } + } + return false; +} + +/* 判断Url中当前后缀名,根据后缀名读取图标 */ +QIcon SidebarClipboardPlugin::fileSuffixGetsIcon(QString Url) +{ + QUrl texturl(Url); + QString filePath; + if (Url == nullptr) { + qWarning() << "传入后缀名有错误, 为空"; + return QIcon::fromTheme("unknown"); + } + QStringList UrlList = Url.split("."); + //判别是是否为无后缀的文件 + if (UrlList.size() <= 1) { +// QString filePath = Url.mid(7); + filePath=texturl.toLocalFile(); + QFileInfo fileinfo(filePath); + if (fileinfo.isFile()) { + return QIcon::fromTheme("unknown");//返回其余文本图标 + } else if (fileinfo.isDir()) { + return QIcon::fromTheme("folder");//返回文件夹的图标 + } + return QIcon::fromTheme("unknown"); + } else if (UrlList.size() == 2) { + return fileSuffixeMatchIcon(UrlList[1]); + } else if (UrlList.size() > 2) { + return fileSuffixeMatchIcon(UrlList[2]); + } +} + +/* 根据文件后缀找对应的图标 */ +QIcon SidebarClipboardPlugin::fileSuffixeMatchIcon(QString cnt) +{ + if (!(m_pErr_rpt.error != QJsonParseError::NoError) && !m_pJsonObject[cnt].toString().isEmpty()) { + return QIcon::fromTheme(m_pJsonObject[cnt].toString()); + } + return QIcon::fromTheme("unknown"); +} + +void SidebarClipboardPlugin::connectWidgetEntryButton(ClipboardWidgetEntry *w) +{ + /* 固定按钮 */ + connect(w->m_pPopButton, &QPushButton::clicked, this, [=](){ + this->fixedWidgetEntrySlots(w); + }); + + /* 取消固定按钮 */ + connect(w->m_pCancelLockButton, &QPushButton::clicked, this, [=]() { + cancelFixedWidgetEntrySLots(w); + }); + + /* 编辑按钮 */ + connect(w->m_pEditButon, &QPushButton::clicked, this, [=](){ + this->editButtonSlots(w); + }); + + /* 删除按钮 */ + connect(w->m_pRemoveButton, &QPushButton::clicked, this, [=](){ + this->removeButtonSlots(w); + }); + + /* 单击剪贴板条目,自动置顶 */ + connect(w, &ClipboardWidgetEntry::doubleClicksignals, this, &SidebarClipboardPlugin::popButtonSlots); + + /* 进入图片条目,预览图片 */ + connect(w, &ClipboardWidgetEntry::previewShowImage, this, &SidebarClipboardPlugin::previewShowImageSlots); + + /* 移出图片条目时, 关闭预览窗口 */ + connect(w, &ClipboardWidgetEntry::previewHideImage, this, &SidebarClipboardPlugin::previewHideImageSlots); +} + +/* 将数据保存到Hash表中 */ +void SidebarClipboardPlugin::registerWidgetOriginalDataHash(QListWidgetItem *key, OriginalDataHashValue *value) +{ + if (nullptr == key || nullptr == value) { + qDebug() << "注册:ClipboardWidgetEntry *key," << key << "OriginalDataHashValue *value值有问题" << value; + return; + } + if (m_pClipboardDataHash.value(key)) { + qDebug() << "注册:value已存在"; + return; + } + m_pClipboardDataHash.insert(key, value); +} + +/* 从hash表中获取OriginalDataHashValue */ +OriginalDataHashValue *SidebarClipboardPlugin::GetOriginalDataValue(QListWidgetItem *key) +{ + if (key == nullptr) { + qWarning() << "GetOriginalDataValue -->获取:ClipboardWidgetEntry *key为空"; + return nullptr; + } + + if (m_pClipboardDataHash.contains(key)) { + return m_pClipboardDataHash.value(key); + } else { + return nullptr; + } +} + +/* 将剪贴板中的数据从Hash表中移除 */ +void SidebarClipboardPlugin::removeOriginalDataHash(QListWidgetItem *key) +{ + if (key == nullptr) { + qWarning() << "removeOriginalDataHash ----> 获取:ClipboardWidgetEntry *key为空"; + return; + } + if (m_pClipboardDataHash.contains(key)) + m_pClipboardDataHash.remove(key); + return; +} + +/* 将数据有顺序的加入到链表中 */ +void SidebarClipboardPlugin::inserOriginalDataList(OriginalDataHashValue *value) +{ + if (m_ListClipboardData.contains(value)) { + qDebug() << "链表中存在"; + return; + } + m_ListClipboardData.insert(0, value); + return; +} + +/* 删除链表中某一个数据 */ +void SidebarClipboardPlugin::removeOriginalDataList(OriginalDataHashValue *value) +{ + if (!m_ListClipboardData.contains(value)) { + qDebug() << "链表中不存在此节点"; + return; + } + /* 迭代链表 */ + int tmp = ItertionOriginalDataList(value); + if (tmp == -1) { + qWarning() << "在list未此值"; + return; + } + m_ListClipboardData.removeAt(tmp); + return; +} + +/* 迭代链表 */ +int SidebarClipboardPlugin::ItertionOriginalDataList(OriginalDataHashValue *value) +{ + //stl类型的迭代器 + int length = m_ListClipboardData.count(); + for (int i = 0; i < length; i++) { + if (m_ListClipboardData.at(i) == value) + return i; + } + return -1; +} + +/* 移动链表中某一个数据到最前面 */ +void SidebarClipboardPlugin::moveOriginalDataFirstList(OriginalDataHashValue *value) +{ + /* 从链表中先移除改数据, 然后再重新插入链表的最前面 */ + removeOriginalDataList(value); + inserOriginalDataList(value); + return; +} + +/* 将新置顶widget写入到剪贴板中去 */ +void SidebarClipboardPlugin::WhetherTopFirst() +{ + // 获取第一个条目 当删除为第一项时,则自动将第二项置顶 + QListWidgetItem *PopWidgetItem = m_pShortcutOperationListWidget->item(0); + qDebug() << "QListWidgetItem *PopWidgetItem" << PopWidgetItem; + if (PopWidgetItem == nullptr) { + qWarning() << "从剪贴板获取的PopWidgetItem指针为空"; + return; + } + + OriginalDataHashValue *pOriginalData = GetOriginalDataValue(PopWidgetItem); + auto data = structureQmimeDate(pOriginalData); + if (data == nullptr) { + qWarning() << "构造Qmimedata数据有问题"; + return; + } + m_pSidebarClipboard->setMimeData(data); + return; +} + +/* 迭代Hash表m_pClipboardDataHash*/ +QListWidgetItem* SidebarClipboardPlugin::iterationClipboardDataHash(ClipboardWidgetEntry *w) +{ + QHash::const_iterator iter2 = m_pClipboardDataHash.constBegin(); + while (iter2 != m_pClipboardDataHash.constEnd()) { + if (iter2.value()->WidgetEntry == w) + return iter2.key(); + ++iter2; + } + qDebug() << "没有找到Widget所对应的Item"; + return nullptr; +} + +/* 迭代Hash表查找其中的当前下标是否存在 */ +int SidebarClipboardPlugin::iterationDataHashSearchSequence(int Index) +{ + QHash::const_iterator iter2 = m_pClipboardDataHash.constBegin(); + int max = iter2.value()->Sequence; + while (iter2 != m_pClipboardDataHash.constEnd()) { + if (iter2.value()->Sequence > max) + max = iter2.value()->Sequence; + ++iter2; + } + return max + 1; +} + +/* 构造QMimeData数据 */ +QMimeData *SidebarClipboardPlugin::structureQmimeDate(OriginalDataHashValue *value) +{ + if (value == nullptr) { + qWarning() << "OriginalDataHashValue 为空"; + return nullptr; + } + auto data = new QMimeData; + bool isCut = false; + QVariant isCutData = QVariant(isCut); + if (value->Clipbaordformat == TEXT) { + data->setData("text/plain", isCutData.toByteArray()); + data->setText(value->text); + } else if (value->Clipbaordformat == URL) { + data->setData("peony-qt/is-cut", isCutData.toByteArray()); + QList urls; + QStringList uris = value->text.split("\n"); + qDebug() << "分解后Url的个数" << uris.count(); + for (auto uri : uris) { + urls << uri; + } + value->urls = urls; + data->setUrls(value->urls); + } else if (value->Clipbaordformat == IMAGE) { + QVariant ImageDate = QVariant(*(value->p_pixmap)); + data->setData("application/x-qt-image", isCutData.toByteArray()); + data->setImageData(ImageDate); + } + return data; +} + +OriginalDataHashValue *SidebarClipboardPlugin::saveOriginalData(OriginalDataHashValue *value) +{ + if (value == nullptr) { + qWarning() << "保存原有剪贴板数据 ---> 传入参数有误"; + return nullptr; + } + OriginalDataHashValue *p_saveOriginalData= new OriginalDataHashValue; + if (value->Clipbaordformat == TEXT) { + p_saveOriginalData->text = value->text; + p_saveOriginalData->Clipbaordformat = TEXT; + p_saveOriginalData->associatedDb = DBDATA; + p_saveOriginalData->p_pixmap = nullptr; + setOriginalDataSequence(p_saveOriginalData); + p_saveOriginalData->MimeData = nullptr; + p_saveOriginalData->WidgetEntry = nullptr; + } else if (value->Clipbaordformat == URL) { + p_saveOriginalData->text = value->text; + p_saveOriginalData->Clipbaordformat = URL; + p_saveOriginalData->MimeData = nullptr; + p_saveOriginalData->p_pixmap = nullptr; + setOriginalDataSequence(p_saveOriginalData); + p_saveOriginalData->urls = value->urls; + p_saveOriginalData->WidgetEntry = nullptr; + p_saveOriginalData->associatedDb = DBDATA; + } else if (value->Clipbaordformat == IMAGE) { + p_saveOriginalData->text = value->text; + p_saveOriginalData->Clipbaordformat = IMAGE; + p_saveOriginalData->MimeData = nullptr; + p_saveOriginalData->p_pixmap = new QPixmap(*(value->p_pixmap)); + setOriginalDataSequence(p_saveOriginalData); + p_saveOriginalData->WidgetEntry = nullptr; + p_saveOriginalData->associatedDb = DBDATA; + } + return p_saveOriginalData; +} + +/* 置顶槽函数 */ +void SidebarClipboardPlugin::popButtonSlots(QWidget *w) +{ + if (w == nullptr) { + qWarning() << "置顶槽函数ClipboardWidgetEntry *w 为空"; + return; + } + if (m_pPreviewImage != nullptr) { + delete m_pPreviewImage; + m_pPreviewImage = nullptr; + } + ClipboardWidgetEntry *widget = dynamic_cast(w); + QListWidgetItem *Item = iterationClipboardDataHash(widget); + OriginalDataHashValue *value = GetOriginalDataValue(Item); + qDebug() << value->associatedDb << value->text; + auto data= structureQmimeDate(value); //构造QMimeData数据 + if (value->associatedDb == DBDATA) { + OriginalDataHashValue *p = saveOriginalData(value); //保存原有的数据类型 + removeOriginalDataHash(Item); //移除Hash表中的原始数据 + QListWidgetItem *deleteItem = m_pShortcutOperationListWidget->takeItem(m_pShortcutOperationListWidget->row(Item)); //删除Item; + delete deleteItem; + deleteItem = nullptr; + popCreatorDbHaveDate(p); + m_pSidebarClipboard->setMimeData(data); //将新的数据set剪贴板中 + return; + } + removeOriginalDataHash(Item); //移除Hash表中的原始数据 + QListWidgetItem *deleteItem = m_pShortcutOperationListWidget->takeItem(m_pShortcutOperationListWidget->row(Item)); //删除Item; + delete deleteItem; + deleteItem = nullptr; + m_pSidebarClipboard->setMimeData(data); //将新的数据set剪贴板中 + return; +} + +/* 删除槽函数 */ +void SidebarClipboardPlugin::removeButtonSlots(ClipboardWidgetEntry *w) +{ + if (w == nullptr) { + qWarning() << "删除槽函数ClipboardWidgetEntry *w 为空"; + return; + } + QListWidgetItem *Item = iterationClipboardDataHash(w); + OriginalDataHashValue *s_deleteDataHashValue = GetOriginalDataValue(Item); + if (s_deleteDataHashValue->Clipbaordformat ==IMAGE && s_deleteDataHashValue->associatedDb == DBDATA) { + QString DeleteFile = QStringLiteral("rm %1").arg(s_deleteDataHashValue->text.mid(7)); + QProcess::execute(DeleteFile);//删除保存在本地的文件 + } + int tmp = m_pShortcutOperationListWidget->row(Item); //记录删除时哪一行 + m_pClipboardDb->deleteSqlClipboardDb(s_deleteDataHashValue->text); + removeOriginalDataHash(Item); + QListWidgetItem *item = m_pShortcutOperationListWidget->takeItem(tmp); //删除Item; + delete item; + // 判断当前删除的是不是第一个条目 + if (0 == tmp) { + qDebug() << "删除当前的条目为第一个条目"; + WhetherTopFirst(); + } + emit Itemchange(); + return; +} + +/* 编辑槽函数 */ +void SidebarClipboardPlugin::editButtonSlots(ClipboardWidgetEntry *w) +{ + /* 防止重复创建 */ + if (w == nullptr) { + qWarning() << "传入值为空"; + return; + } + qDebug() << "当前label中的文本数据" << w->m_pCopyDataLabal->text(); + EditorWidget EditWidget; + /* 获取保存在hash表中的数据,改变之前保存的数据 */ + QListWidgetItem *Item = iterationClipboardDataHash(w); + OriginalDataHashValue* pOriginalData = GetOriginalDataValue(Item); + QString text = pOriginalData->text; + EditWidget.m_pEditingArea->setPlainText(text); + + /* 设置左右填充 */ + QTextDocument *document = EditWidget.m_pEditingArea->document(); + QTextFrame *rootFrame=document->rootFrame(); + QTextFrameFormat format; + format.setPadding(10); + format.setBorderStyle(QTextFrameFormat::BorderStyle_Dotted); + rootFrame->setFrameFormat(format); + + int nRet = EditWidget.exec(); + if (nRet == QDialog::Accepted) { + //此句有问题 +// QString formatBody = SetFormatBody(EditWidget.m_pEditingArea->toPlainText(), w); // 设置...字样 + QString formatBody = EditWidget.m_pEditingArea->toPlainText(); + if(formatBody == "") { + qDebug()<<"空字符串,返回"; + return ; + } + if (EditWidget.m_pEditingArea->toPlainText() != text) { + //当编辑后数据改变时,就需要将m_pLabelText中的value改变 + w->m_pCopyDataLabal->setText(formatBody); + pOriginalData->text = EditWidget.m_pEditingArea->toPlainText(); + structureQmimeDate(pOriginalData); + if (pOriginalData->associatedDb == DBDATA) { + m_pClipboardDb->updateSqlClipboardDb(pOriginalData->text, pOriginalData->Clipbaordformat, pOriginalData->Sequence, text); //更新数据库表中的数据 + } + } + //获取当前条目所在位置,是不是在第一 + int row_num = m_pShortcutOperationListWidget->row(Item); + if (row_num == 0) { + QMimeData *data = structureQmimeDate(pOriginalData); + m_pSidebarClipboard->setMimeData(data); //将新的数据set剪贴板中去 + } + qDebug() << "当前所在的条木" << row_num; + } else if (nRet == QDialog::Rejected) { + qDebug() << "编辑框取消操作"; + } + return; +} + +/* 固定条目槽函数 */ +void SidebarClipboardPlugin::fixedWidgetEntrySlots(ClipboardWidgetEntry *w) +{ + if (w == nullptr) { + qWarning() << "删除槽函数fixedWidgetEntrySlots *w 为空"; + return; + } + QListWidgetItem *Item = iterationClipboardDataHash(w); + OriginalDataHashValue *s_pDataHashValue = GetOriginalDataValue(Item); + s_pDataHashValue->associatedDb = DBDATA; + qDebug() << "s_pDataHashValue->Clipbaordformat" << s_pDataHashValue->Clipbaordformat; + if (s_pDataHashValue->Clipbaordformat == TEXT || s_pDataHashValue->Clipbaordformat == URL) { + m_pClipboardDb->insertSqlClipbarodDb(s_pDataHashValue->text, s_pDataHashValue->Clipbaordformat, s_pDataHashValue->Sequence); + } else if (s_pDataHashValue->Clipbaordformat == IMAGE) { + int seq = m_pClipboardDb->SelectSqlClipbaordDbId(); + QString url_filepath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config" + QStringLiteral("/%1.bmp").arg(seq + 1); + qDebug() << "------------------------------->" << url_filepath; + s_pDataHashValue->text = "file://" + url_filepath; //将文件路径已Url的方式保存 + m_pClipboardDb->insertSqlClipbarodDb(s_pDataHashValue->text, s_pDataHashValue->Clipbaordformat, s_pDataHashValue->Sequence); + s_pDataHashValue->p_pixmap->save(url_filepath, "bmp", 100); + } + w->m_pPopButton->setVisible(false); + w->m_pCancelLockButton->setVisible(true); + w->m_bWhetherFix = true; + return; +} + +/* 取消固定槽函数 */ +void SidebarClipboardPlugin::cancelFixedWidgetEntrySLots(ClipboardWidgetEntry *w) +{ + if (w == nullptr) { + qWarning() << "删除槽函数fixedWidgetEntrySlots *w 为空"; + return; + } + QListWidgetItem *Item = iterationClipboardDataHash(w); + OriginalDataHashValue *s_pDataHashValue = GetOriginalDataValue(Item); + if (s_pDataHashValue->Clipbaordformat ==IMAGE && s_pDataHashValue->associatedDb == DBDATA) { + QString DeleteFile = QStringLiteral("rm %1").arg(s_pDataHashValue->text.mid(7)); + QProcess::execute(DeleteFile);//删除保存在本地的文件 + } + m_pClipboardDb->deleteSqlClipboardDb(s_pDataHashValue->text); //删除数据库中此条数据 + s_pDataHashValue->associatedDb = ""; + w->m_pPopButton->setVisible(true); + w->m_pCancelLockButton->setVisible(false); + w->m_bWhetherFix = false; + return; +} + +/* 当超过限制条数时删除最后一条消息 */ +void SidebarClipboardPlugin::removeLastWidgetItem() +{ + ClipboardWidgetEntry *w = nullptr; + QListWidgetItem *Item = nullptr; + OriginalDataHashValue *value = nullptr; + int tmp = m_pShortcutOperationListWidget->count()-1; + int i; + for (i = tmp; i >= 0; i--) { + w = (ClipboardWidgetEntry*)m_pShortcutOperationListWidget->itemWidget(m_pShortcutOperationListWidget->item(i)); + Item = iterationClipboardDataHash(w); + OriginalDataHashValue *value = GetOriginalDataValue(Item); + if (value->associatedDb != DBDATA) { + break; + } + } + if (i == -1) { + /* 说明全部都是固定的条目,删除最后一条固定条目 */ + w = (ClipboardWidgetEntry*)m_pShortcutOperationListWidget->itemWidget(m_pShortcutOperationListWidget->item(tmp)); + Item = iterationClipboardDataHash(w); + value = GetOriginalDataValue(Item); + m_pClipboardDb->deleteSqlClipboardDb(value->text); + i = tmp; + } + removeOriginalDataHash(Item); + QListWidgetItem *tmpItem = m_pShortcutOperationListWidget->takeItem(i); + delete tmpItem; + return; +} + +/* 判断在ListWidget是否存在,如果不存在则返回fasle,创建,返回true,不创建 */ +bool SidebarClipboardPlugin::booleanExistWidgetItem(QString Text) +{ + int tmp = m_pShortcutOperationListWidget->count(); + for (int i = 0; i < tmp; i++) { + OriginalDataHashValue *p = GetOriginalDataValue(m_pShortcutOperationListWidget->item(i)); + if (p->Clipbaordformat == TEXT || p->Clipbaordformat == URL) { + QString WidgetText = p->text; + if (WidgetText == Text) { + if(i == 0) { + qDebug() << "当前的数据就是置顶数据------>booleanExistWidgetItem"; + return true; + } + if (p->associatedDb == DBDATA) { + popButtonSlots(p->WidgetEntry); + return true; + } + removeButtonSlots(GetOriginalDataValue(m_pShortcutOperationListWidget->item(i))->WidgetEntry); + return false; + } + } + } + return false; +} + +/* 判断图片是否在hash表中,如果存在,则删除,然后将图片重新写入到剪贴板中去 */ +bool SidebarClipboardPlugin::booleanExistWidgetImagin(QPixmap Pixmap) +{ + //将从剪贴板拿到的数据转换成Bit位进行比较 + QImage clipboardImage = Pixmap.toImage(); + int Clipboard_hight = clipboardImage.height(); + int Clipboard_width = clipboardImage.width(); + unsigned char *clipboard_data = clipboardImage.bits(); + int tmp = m_pShortcutOperationListWidget->count(); + if (tmp == 0) { + qDebug() << "当前hash表中不存在数据, 直接返回即可"; + return false; + } + unsigned char r1, g1, b1, r2, g2, b2; + int j; + for (int i = 0; i < tmp; i++) { + OriginalDataHashValue *p = GetOriginalDataValue(m_pShortcutOperationListWidget->item(i)); + if (p->Clipbaordformat == IMAGE) { + //hash表中的Pixmap和刚从剪贴板中拿到的数据进行比较 + QPixmap Hash_Pixmap = *(p->p_pixmap); + QImage Hash_Image = Hash_Pixmap.toImage(); + if (Clipboard_hight == Hash_Image.height() && Clipboard_width == Hash_Image.width()) { + unsigned char *Hash_data = Hash_Image.bits(); + for (j = 0; j < Clipboard_hight; j++) { + for (int k = 0; k < Clipboard_width; k++) { + r1 = *(Hash_data + 2); + b1 = *(Hash_data + 1); + g1 = *(Hash_data); + r2 = *(clipboard_data + 2); + b2 = *(clipboard_data + 1); + g2 = *(clipboard_data); + if (r1 == r2 && b1 == b2 && g1 == g2) { + clipboard_data += 4; + Hash_data += 4; + } else { + return false; //比对图片像素点不相等直接返回false + } + } + } + if (j == Clipboard_hight) { + //说明图片已经对比完成,且图片存在 + if (i == 0) + return true; //当前数据就是第一条数据, 不需要做其余处理,直接清理内存,退出; + /* 说明已存在此图片但是需要将该放置在第一个位置上去,同时写入剪贴板当中 */ + removeButtonSlots(GetOriginalDataValue(m_pShortcutOperationListWidget->item(i))->WidgetEntry); + return false; + } + } + } + } + return false; +} + +/* 删除所有的WidgetItem */ +void SidebarClipboardPlugin::removeAllWidgetItem() +{ + int tmp = m_pShortcutOperationListWidget->count(); + qDebug() << "m_pShortcutOperationListWidget->count()" << tmp; + if (tmp <= 0) { + qDebug() << "条目为零,不需要清空"; + return; + } + /* 判断用户是否勾选了不再提醒这一功能 */ + if (m_bPromptBoxBool) { + emit globalClipboardSignal->ClipBoardWidgetEntryEditButtonSignal(); // 当点击清楚时,将侧边栏置为不Hide状态 + CleanPromptBox PromptBoxWidget; + int nRet = PromptBoxWidget.exec(); + if (nRet == QDialog::Accepted) { + qDebug() << "nRet == QDialog::Accepted"; + } else if (nRet == QDialog::Rejected) { + qDebug() << "nRet == QDialog::Rejected"; + return; + } + } + for (int i = 0; i < tmp; i++) { + OriginalDataHashValue *p_deleteDataHashValue = GetOriginalDataValue(m_pShortcutOperationListWidget->item(0)); + removeOriginalDataHash(m_pShortcutOperationListWidget->item(0)); + QListWidgetItem *tmp = m_pShortcutOperationListWidget->takeItem(0); + //删除保存在数据库的中的数据 + if (p_deleteDataHashValue->associatedDb == DBDATA) { + m_pClipboardDb->deleteSqlClipboardDb(p_deleteDataHashValue->text); //删除数据库中的数据 + } + //图片且保存到数据库中,需要删除保存在本地的文件 + if (p_deleteDataHashValue->Clipbaordformat == IMAGE && p_deleteDataHashValue->associatedDb == DBDATA) { + QString DeleteFile = QStringLiteral("rm %1").arg(p_deleteDataHashValue->text.mid(7)); + QProcess::execute(DeleteFile);//删除保存在本地的文件 + } + delete tmp; + } + emit Itemchange(); +} + +/* 搜索 槽函数 */ +void SidebarClipboardPlugin::searchClipboardLableTextSlots(QString Text) +{ + /* 在清除条目前,先记住每一个当前的位置 */ + if (m_bsortEntryBool) + sortingEntrySequence(); + + /* 清空之前listWidget中的條目 */ + int tmp = m_pShortcutOperationListWidget->count(); + for (int i = 0; i < tmp; i++) { + ClipboardWidgetEntry *w = (ClipboardWidgetEntry*)m_pShortcutOperationListWidget->itemWidget(m_pShortcutOperationListWidget->item(0)); + m_pShortcutOperationListWidget->item(0); + m_pShortcutOperationListWidget->takeItem(0); + } + + /* 当搜索栏中内容为空,还原之前的数据 */ + if (Text == "") { + sortingEntryShow(); + return; + } + + /* 将包含有关键字的条目显示出来 */ + QHash::const_iterator iter2 = m_pClipboardDataHash.constBegin(); + while (iter2 != m_pClipboardDataHash.constEnd()) { + if (iter2.value()->text.contains(Text, Qt::CaseSensitive) && iter2.value()->Clipbaordformat != IMAGE) { + m_pShortcutOperationListWidget->insertItem(0, iter2.key()); + ClipboardWidgetEntry *w = new ClipboardWidgetEntry(iter2.value()->Clipbaordformat); + iter2.value()->WidgetEntry = w; + setEntryItemSize(iter2.value(), w, iter2.key()); + AddWidgetEntry(iter2.value(), w, iter2.value()->text); + connectWidgetEntryButton(w); + m_pShortcutOperationListWidget->setItemWidget(iter2.key(), w); + } + ++iter2; + } + WhetherTopFirst(); + return; +} + +/* Item数目发生变化 */ +void SidebarClipboardPlugin::ItemNumchagedSlots() +{ + int num = m_pClipboardDataHash.size(); + if (num > 0) { + m_pSideBarClipboardLable->setVisible(false); + m_pShortcutOperationListWidget->setVisible(true); + } else { + m_pSideBarClipboardLable->setVisible(true); + m_pShortcutOperationListWidget->setVisible(false); + } + return; +} + +/* 加载数据Text线程槽函数 */ +void SidebarClipboardPlugin::loadClipboardDb() +{ + QString url_filepath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) +"/.config/Clipboard.db"; + QSqlQuery query(QSqlDatabase::database(url_filepath)); + QString SelectSql = QStringLiteral("SELECT * FROM Clipboard_table"); + if (!query.exec(SelectSql)) { + qWarning() << "数据Select失败"; + return; + } + while (query.next()) { + OriginalDataHashValue *p_DataHashValueDb = new OriginalDataHashValue(); + p_DataHashValueDb->text = query.value(1).toString(); + p_DataHashValueDb->Clipbaordformat = query.value(2).toString(); + p_DataHashValueDb->associatedDb = DBDATA; + creatLoadClipboardDbData(p_DataHashValueDb); + } + return; +} + +/* 加载从数据库中拿到的数据,加入到剪贴板 */ +void SidebarClipboardPlugin::creatLoadClipboardDbData(OriginalDataHashValue *value) +{ + if (value == nullptr) { + qWarning() << "参数错误 ---> 参数类型 --->OriginalDataHashValue"; + return; + } + //第一次加载不需要管剪贴板条目是否存在 + bool DeleteFlag = false; + QListWidgetItem *pListWidgetItem = new QListWidgetItem; + ClipboardWidgetEntry *w = new ClipboardWidgetEntry(value->Clipbaordformat); + + /* 判断文件是否存在 */ + if (value->Clipbaordformat == TEXT) { + DeleteFlag = true; + } else if (value->Clipbaordformat == URL && judgeFileExit(value->text)) { + DeleteFlag = true; //修改 文件是否存在标志位 + QList urls; + QStringList uris = value->text.split("\n"); + for (auto uri : uris) { + urls << uri; + } + value->urls = urls; + } else if (value->Clipbaordformat == IMAGE && judgeFileExit(value->text)) { + DeleteFlag = true; + value->p_pixmap = new QPixmap(value->text.mid(7)); + } + + if (!DeleteFlag) { + qDebug() << "此文件不存在"; + m_pClipboardDb->deleteSqlClipboardDb(value->text); + delete pListWidgetItem; + delete w; + delete value; + return; + } + + if (m_pClipboardDataHash.count() == 0) { + value->Sequence = 0; + } else { + value->Sequence = iterationDataHashSearchSequence(m_pClipboardDataHash.count()); + } + + AddWidgetEntry(value, w, value->text); + + value->WidgetEntry = w; + + setEntryItemSize(value, w, pListWidgetItem); + pListWidgetItem->setFlags(Qt::NoItemFlags); + + registerWidgetOriginalDataHash(pListWidgetItem, value); + + //将按钮与槽对应上 + connectWidgetEntryButton(w); + //插入剪贴板条目 + m_pShortcutOperationListWidget->insertItem(0, pListWidgetItem); + m_pShortcutOperationListWidget->setItemWidget(pListWidgetItem, w); + emit Itemchange(); +} + +void SidebarClipboardPlugin::popCreatorDbHaveDate(OriginalDataHashValue *value) +{ + if (value == nullptr) { + qWarning() << "popCreatorDbHaveDate ---> 传入形参错误"; + return; + } + QListWidgetItem *pListWidgetItem = new QListWidgetItem; + ClipboardWidgetEntry *w = new ClipboardWidgetEntry(value->Clipbaordformat); + + value->WidgetEntry = w; + AddWidgetEntry(value, w, value->text); + + if (value->Clipbaordformat == TEXT || value->Clipbaordformat == URL) { + w->setFixedSize(397, 42); + pListWidgetItem->setSizeHint(QSize(397,42)); + } else if (value->Clipbaordformat == IMAGE) { + w->setFixedSize(397, 84); + pListWidgetItem->setSizeHint(QSize(397,84)); + } + pListWidgetItem->setFlags(Qt::NoItemFlags); + + registerWidgetOriginalDataHash(pListWidgetItem, value); + + //将按钮与槽对应上 + connectWidgetEntryButton(w); + //插入剪贴板条目 + m_pShortcutOperationListWidget->insertItem(0, pListWidgetItem); + m_pShortcutOperationListWidget->setItemWidget(pListWidgetItem, w); + emit Itemchange(); + return; +} + +/* 判断此路径下文件是否存在 */ +bool SidebarClipboardPlugin::judgeFileExit(QString fullFilePath) +{ + if (fullFilePath == "") { + qWarning() << "参数错误 ---> 参数类型 Qstring" << fullFilePath; + return false; + } + + QStringList filePath = fullFilePath.split('\n'); +// qDebug() << "当前文件路径" << filePath; + if (filePath.count() == 1) { + QFileInfo fileInfo(fullFilePath.mid(7)); + if (fileInfo.exists()) { + return true; + } + } else { + int tmp = filePath.count(); + for(int i = 0; i < tmp; i++) { + QFileInfo fileInfo(filePath[i].mid(7)); + if (fileInfo.exists() && i == tmp - 1) { + return true; + } + } + } + return false; +} + +/* 设定预览窗口位置 */ +int SidebarClipboardPlugin::setClipBoardWidgetScaleFactor() +{ + /* 获取当前屏幕分辨率 */ + QScreen* pScreen = QGuiApplication::primaryScreen(); + QRect DeskSize = pScreen->geometry(); + m_nScreenWidth = DeskSize.width(); //桌面分辨率的宽 + m_nScreenHeight = DeskSize.height(); //桌面分辨率的高 + if (m_nScreenHeight >= 600 && m_nScreenHeight <= 768) { + return m_nScreenHeight - m_nScreenHeight/2 - 60 - m_taskHeight + m_nclipboardsite_y; + } else if (m_nScreenHeight >= 900 && m_nScreenHeight <= 1080) { + return m_nScreenHeight - m_nScreenHeight/3 - m_taskHeight + m_nclipboardsite_y; + } else if (m_nScreenHeight >= 1200 && m_nScreenHeight <= 2160) { + return m_nScreenHeight - m_nScreenHeight/4 - m_taskHeight + m_nclipboardsite_y; + } else { + return m_nScreenHeight/2 - m_nScreenHeight + m_nclipboardsite_y; + } +} + +/* 加载预览图片窗口槽函数 */ +void SidebarClipboardPlugin::previewShowImageSlots(QWidget *w) +{ + if (w == nullptr) { + qWarning() << "置顶槽函数ClipboardWidgetEntry *w 为空"; + return; + } + if (m_pPreviewImage != nullptr) { + delete m_pPreviewImage; + m_pPreviewImage = nullptr; + } +// int PreviewWidgetHeight = setClipBoardWidgetScaleFactor(); + ClipboardWidgetEntry *widget = dynamic_cast(w); + QListWidgetItem *Item = iterationClipboardDataHash(widget); + OriginalDataHashValue* pOriginalData = GetOriginalDataValue(Item); + m_pPreviewImage = new previewImageWidget(pOriginalData->p_pixmap); + + m_pPreviewImage->move(m_nclipboardsite_x - 260, CLIPBOARD_HEIGHT); + qDebug() << m_nclipboardsite_x - 260 << CLIPBOARD_HEIGHT; + m_pPreviewImage->show(); +} + +/* 退出预览图片窗口槽函数 */ +void SidebarClipboardPlugin::previewHideImageSlots(QWidget *w) +{ + if (w == nullptr) { + qWarning() << "置顶槽函数ClipboardWidgetEntry *w 为空"; + return; + } + if (m_pPreviewImage == nullptr) { + return; + } + m_pPreviewImage->hide(); + delete m_pPreviewImage; + m_pPreviewImage = nullptr; + return; +} + +void SidebarClipboardPlugin::sortingEntrySequence() +{ + int tmp = m_pShortcutOperationListWidget->count(); + for (int i = 0; i < tmp; i++) { + GetOriginalDataValue(m_pShortcutOperationListWidget->item(i))->Sequence = tmp - i - 1; + } + m_bsortEntryBool = false; +} + +void SidebarClipboardPlugin::setEntryItemSize(OriginalDataHashValue* value, ClipboardWidgetEntry *w, QListWidgetItem *item) +{ + if (value == nullptr || w == nullptr || item == nullptr) { + qWarning() << "setEntryItemSize ------> 设置条目大小和Item大小传入参数失败"; + return; + } + if (value->Clipbaordformat == TEXT || value->Clipbaordformat == URL) { + w->setFixedSize(397, 42); + item->setSizeHint(QSize(397,42)); + } else if (value->Clipbaordformat == IMAGE) { + w->setFixedSize(397, 84); + item->setSizeHint(QSize(397,84)); + } + return; +} + +/* 当监听到主题字体发生变化时,则重新设置label条目的text */ +void SidebarClipboardPlugin::resetWidgetLabelText() +{ + const QByteArray id("org.ukui.style"); + QGSettings * fontSetting = new QGSettings(id); + connect(fontSetting, &QGSettings::changed,[=](QString key){ + if ("systemFont" == key || "systemFontSize" ==key) { + searchClipboardLableTextSlots(""); + } + }); +} + +void SidebarClipboardPlugin::sortingEntryShow() +{ + int index = 0; + int count = m_pClipboardDataHash.size(); + bool IndexFlag = true; + while(index != count) { + IndexFlag = true; + qDebug() << "当前条目的下标" << index; + QHash::const_iterator iter1 = m_pClipboardDataHash.constBegin(); + while (iter1 != m_pClipboardDataHash.constEnd()) { + qDebug() << "当前条目所处位置的位置-->Sequence -->" << iter1.value()->Sequence; + if (index == iter1.value()->Sequence) { + m_pShortcutOperationListWidget->insertItem(0, iter1.key()); + ClipboardWidgetEntry *w = new ClipboardWidgetEntry(iter1.value()->Clipbaordformat); + iter1.value()->WidgetEntry = w; + setEntryItemSize(iter1.value(), w, iter1.key()); + connectWidgetEntryButton(w); + iter1.value()->WidgetEntry = w; + AddWidgetEntry(iter1.value(), w, iter1.value()->text); + m_pShortcutOperationListWidget->setItemWidget(iter1.key(), w); + IndexFlag = false; + index++; + qDebug() << "进入循环当前条目的下标" << index; + } + ++iter1; + } + /* 如果没有进入上面的While循环,说明此Index不存在,继续往后面走 */ + if (IndexFlag) { + index++; + count++; + } + if (index > 1000 || count > 1000) { + qDebug() << "查找机制已经进入死循环"; + return; + } + } + m_bsortEntryBool = true; +} diff --git a/src/plugins/ukui-sidebar-clipboard/sidebarclipboardplugin.h b/src/plugins/ukui-sidebar-clipboard/sidebarclipboardplugin.h new file mode 100644 index 0000000..dae621c --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/sidebarclipboardplugin.h @@ -0,0 +1,205 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clipboardpluginiface.h" +#include "clipboardwidgetentry.h" +#include "sidebarclipboardsignal.h" +#include "searchwidgetitemcontent.h" +#include "editorwidget.h" +#include "clipboardsignal.h" +#include "clipboardlisetwidget.h" +#include "cleanpromptbox.h" +#include "clipBoardInternalSignal.h" +#include "clipboarddb.h" +#include "previewimagewidget.h" + +#include +#include +#include + +//#include "clipbaordstructoriginaldata.h" +#define WIDGET_ENTRY_COUNT 10 +#define SIDEBAR_CLIPBOARD_QSS_PATH ":/qss/sidebarClipboard.css" +#define TEXT "Text" +#define URL "Url" +#define IMAGE "Image" +#define DBDATA "Dbdata" + +#define CLIPBOARD_HEIGHT 385 + +typedef struct clipboardOriginalDataHash { + ClipboardWidgetEntry* WidgetEntry; + const QMimeData* MimeData; + QPixmap *p_pixmap; + QString text; + QString Clipbaordformat; + QList urls; + int Sequence; + QString associatedDb; +} OriginalDataHashValue; + +//static SidebarClipboardPlugin *global_instance = nullptr; +class SidebarClipboardPlugin:public QObject, public ClipboardInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.ukui.sidebar-qt.plugin-iface.ClipboardInterface" FILE "clipboardPlugin.json") + Q_INTERFACES(ClipboardInterface) + +public: + SidebarClipboardPlugin(QObject *parent = 0); + //plugin implement 统一接口 + const QString name() override {return QObject::tr("ClipBoard");} + PluginType pluginType() override {return PluginType::ClipBoard;} + const QString description() override {return QObject::tr("Show the folder children as icons.");} + const QIcon icon() override {return QIcon::fromTheme("view-grid-symbolic", QIcon::fromTheme("folder"));} + void setEnable(bool enable) override {Q_UNUSED(enable)} + bool isEnable() override {return true;} + + /* 剪贴板接口 */ + virtual QListWidget* getClipbaordListWidget() override; + virtual SidebarClipBoardSignal* createClipSignal() override; + virtual QWidget* getClipbaordGroupBox() override; + // static SidebarClipboardPlugin *getInstance(); + + /* 剪贴板成员和成员函数 */ + QHash m_pClipboardDataHash; + QList m_ListClipboardData; + QListWidget *m_pShortcutOperationListWidget; + QListWidget *m_pSearchWidgetListWidget; + QGroupBox *m_pSidebarClipboardBox; + QWidget *m_pSidebarClipboardWidget; + QLabel *m_pSideBarClipboardLable; + bool m_bPromptBoxBool; + bool m_bsortEntryBool = true; + + QVBoxLayout *m_pClipboardLaout; + QClipboard *m_pSidebarClipboard; + ClipboardSignal *m_pClipSignal; + SearchWidgetItemContent *m_pSearchArea; + QMimeData mineData; + + QTranslator *translator; + + clipboardDb *m_pClipboardDb; + + QThread *m_pThread; + + previewImageWidget *m_pPreviewImage = nullptr; + + int m_nScreenWidth; + int m_nScreenHeight; + int m_nclipboardsite_x = 1200; + int m_nclipboardsite_y = 0; + int m_taskHeight = 46; + + /* 注册Widget界面和Item/lable/剪贴板数据/的关系 */ + void registerWidgetOriginalDataHash(QListWidgetItem *key, OriginalDataHashValue *value); + OriginalDataHashValue *GetOriginalDataValue(QListWidgetItem *key); + void removeOriginalDataHash(QListWidgetItem *key); + void sortingEntrySequence(); + + /* 对m_ListClipboardData链表的操作 */ + void inserOriginalDataList(OriginalDataHashValue *value); + void removeOriginalDataList(OriginalDataHashValue *value); + int ItertionOriginalDataList(OriginalDataHashValue *value); + void moveOriginalDataFirstList(OriginalDataHashValue *value); + + //void FixOriginalDataFirstList(OriginalDataHashValue *value, QString text, const QMimeData mimedata); + + void initFileIconJson(); + void removeLastWidgetItem(); /* 限制复制条数 */ + bool booleanExistWidgetItem(QString Text); /* 判断在ListWidget是否存在,如果不存在则返回fasle,创建,返回true,不创建 */ + void createFindClipboardWidgetItem(); /* 创建查找条目 */ + void WhetherTopFirst(); /* 设置新置顶的条目写入到剪贴版中去 */ + void connectWidgetEntryButton(ClipboardWidgetEntry * w); /* 连接WIdgetEntry条目中三个按钮的槽函数 */ + void createTipLable(); /* 创建无剪贴板板字样 */ + void createWidget(); /* 创建剪贴板主Widget和搜索栏与条目的ListWidget界面 */ + void sortingEntryShow(); /* 將條目有序的展現出來 */ + bool booleanExistWidgetImagin(QPixmap Pixmap); /* 判断图片是否在hash表中,如果存在,则删除,然后将图片重新写入到剪贴板中去 */ + void creatLoadClipboardDbData(OriginalDataHashValue *value); /* 加载从数据库中拿到的数据,加入到剪贴板 */ + bool judgeFileExit(QString fullFilePath); /* 判断此路径下该文件是否存在 */ + OriginalDataHashValue *saveOriginalData(OriginalDataHashValue *value); /* 保存OriginalData数据 */ + void setOriginalDataSequence(OriginalDataHashValue *value); /* 设置条目的sequence */ + void popCreatorDbHaveDate(OriginalDataHashValue *value); /* 加入关联数据库的置顶条目 */ + QIcon fileSuffixGetsIcon(QString Url); /* 判断Url中当前后缀名,根据后缀名读取图标 */ + QIcon fileSuffixeMatchIcon(QString cnt); /* 根据文件名后缀匹配对应的图标 */ + void getPixmapListFileIcon(QString UrlText, pixmapLabel *pixmapListclass); /* 多文件时,将图标加入到链表中 */ + QString SetFormatBody(QString text, ClipboardWidgetEntry *w); /* 设置... */ + QString setMiddleFormatBody(QString text, ClipboardWidgetEntry *w); /* 从文本中间设置... */ + QString setSpecificString(QString text); /* 复制多文件时,设置特殊的字符串 */ + QString catUrlFileName(QString Url); /* 截取Url中的文件名 */ + QString judgeBlankLine(QStringList list); /* 去除掉空行,显示有字体的行 */ + bool substringSposition(QString formatBody, QStringList list); /* 判断后面是否还有子串 */ + QListWidgetItem* iterationClipboardDataHash(ClipboardWidgetEntry *w); /* 迭代Hash表m_pClipboardDataHash */ + int iterationDataHashSearchSequence(int Index); /* 迭代Hash表查找其中的当前下标是否存在 */ + int setClipBoardWidgetScaleFactor(); /* 设置剪贴板的高度,用来作为预览窗体的显示位置 */ + QMimeData *copyMinedata(const QMimeData* mimeReference); /* 拷贝QMimeData拷贝数据类型 */ + QMimeData *structureQmimeDate(OriginalDataHashValue *value); /* 构造一个QMimeDate类型数据 */ + void AddWidgetEntry(OriginalDataHashValue *s_pDataHashValue, ClipboardWidgetEntry *w, QString text); /* 将信息写入到WidgetEntry条目中去 */ + void setEntryItemSize(OriginalDataHashValue* value, ClipboardWidgetEntry *w, QListWidgetItem *item); /* 设置条目大小 */ + void resetWidgetLabelText(); + QJsonParseError m_pErr_rpt; + QJsonDocument m_pDocument; + QJsonObject m_pJsonObject; + +signals: + void Itemchange(); + void EditConfirmButtonSignal(ClipboardWidgetEntry *, EditorWidget*); + +public slots: + void createWidgetEntry(); + void popButtonSlots(QWidget *w); /* 置顶槽函数 */ + void editButtonSlots(ClipboardWidgetEntry *w); /* 编辑槽函数 */ + void removeButtonSlots(ClipboardWidgetEntry *w); /* 编辑槽函数 */ + void fixedWidgetEntrySlots(ClipboardWidgetEntry *w); /* 固定槽函数 */ + void cancelFixedWidgetEntrySLots(ClipboardWidgetEntry *w); /* 取消固定槽函数 */ + void removeAllWidgetItem(); /* 移除所有条目槽函数 */ + void searchClipboardLableTextSlots(QString Text); /* 查找槽函数 */ + void ItemNumchagedSlots(); /* Item条目发生改变槽函数 */ + void loadClipboardDb(); /* 加载数据Text线程槽函数 */ + void previewShowImageSlots(QWidget *w); /* 加载预览图片窗口槽函数 */ + void previewHideImageSlots(QWidget *w); /* 退出预览图片窗口槽函数 */ +}; + +#endif // SIDEBARCLIPBOARDPLUGIN_H diff --git a/src/plugins/ukui-sidebar-clipboard/ukui-sidebar-clipboard.pro b/src/plugins/ukui-sidebar-clipboard/ukui-sidebar-clipboard.pro new file mode 100644 index 0000000..1650b09 --- /dev/null +++ b/src/plugins/ukui-sidebar-clipboard/ukui-sidebar-clipboard.pro @@ -0,0 +1,71 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2020-01-08T10:30:22 +# +#------------------------------------------------- + +QT += core gui sql +QT += widgets + +TARGET = clipboardPlugin +TEMPLATE = lib +CONFIG += plugin c++11 link_pkgconfig +PKGCONFIG += gsettings-qt +include(../../env.pri) + +QMAKE_CFLAGS += -D_FORTIFY_SOURCE=2 -O2 + +DEFINES += QT_DEPRECATED_WARNINGS + +RESOURCES += clipboardPlugin.qrc +SOURCES += \ + cleanpromptbox.cpp \ + clipBoardInternalSignal.cpp \ + customstyle.cpp \ + customstyleCleanPushbutton.cpp \ + customstylePushbutton2.cpp \ + customstyleSearchPushbutton.cpp \ + pixmaplabel.cpp \ + sidebarclipboardplugin.cpp \ + clipboardwidgetentry.cpp \ + editorwidget.cpp \ + searchwidgetitemcontent.cpp \ + clipboardlisetwidget.cpp \ + clipboarddb.cpp \ + previewimagewidget.cpp + +INCLUDEPATH += ../../plugin-interface ../../plugin-signals + +HEADERS += \ + cleanpromptbox.h \ + clipBoardInternalSignal.h \ + customstyle.h \ + customstyleCleanPushbutton.h \ + customstylePushbutton2.h \ + customstyleSearchPushbutton.h \ + pixmaplabel.h \ + sidebarclipboardplugin.h \ + clipboardwidgetentry.h \ + clipboardsignal.h \ + editorwidget.h \ + searchwidgetitemcontent.h \ + ../../plugin-signals/sidebarclipboardsignal.h \ + clipboardlisetwidget.h \ + clipbaordstructoriginaldata.h \ + clipboarddb.h \ + previewimagewidget.h +DISTFILES += clipboardPlugin.json + +TRANSLATIONS += ../../../translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_zh_CN.ts \ + ../../../translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo.ts \ + ../../../translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo_CN.ts \ + ../../../translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_tr.ts + +unix { + translation.path = /usr/share/ukui-sidebar/ukui-sidebar-clipboard + translation.files += ../../../translations/ukui-sidebar-clipboard/*.qm + INSTALLS += translation + + target.path = $${PLUGIN_INSTALL_DIRS} + INSTALLS += target +} diff --git a/src/plugins/ukui-sidebar-notification/appmsg.cpp b/src/plugins/ukui-sidebar-notification/appmsg.cpp new file mode 100644 index 0000000..dc430b2 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/appmsg.cpp @@ -0,0 +1,733 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see setFixedWidth(380); + m_nMaxCount = 3; + + //--> + //折叠按钮和删除按钮部分 + m_pFoldBtnWid = new QWidget(this); + QHBoxLayout *m_pFoldBtnHLaout = new QHBoxLayout(); + m_pFoldBtnHLaout->setContentsMargins(0,0,0,0); + m_foldBtn = new QPushButton(m_pFoldBtnWid); + + m_foldBtn->setStyleSheet("QPushButton{background:rgba(255,255,255,31); border:0px; border-radius:6px;}" + "QPushButton:hover{background:rgba(255,255,255,71); border:0px; border-radius:6px;}" + "QPushButton:pressed{background:rgba(255,255,255,41); border:0px; border-radius:6px;}"); + QPainter p(m_foldBtn); + QRect rect = m_foldBtn->rect(); + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.setBrush(QBrush(QColor(0, 0, 255, 255))); + p.setPen(Qt::transparent); + p.drawRoundedRect(rect,6,6); + + m_foldBtn->setObjectName("fold"); + m_foldBtn->setLayoutDirection(Qt::LeftToRight); + m_foldBtn->setIcon(QIcon::fromTheme("kylin-fold-hover").pixmap(17,17)); + m_foldBtn->setText(QObject::tr(" fold")); + m_foldBtn->setFixedSize(88,36); + connect(m_foldBtn,&QPushButton::clicked,this,&AppMsg::onFoldAppWidget); + + m_delBtn = new QPushButton(); + m_delBtn->setStyleSheet("QPushButton{background:rgba(255,255,255,31); border:0px; border-radius:12px;}" + "QPushButton:hover{background:rgba(255,255,255,71); border:0px; border-radius:12px;}" + "QPushButton:pressed{background:rgba(255,255,255,41); border:0px; border-radius:12px;}"); + m_delBtn->setIcon(QIcon(":/images/hover.svg")); + m_delBtn->setIcon(QIcon::fromTheme("edit-clear-symbolic").pixmap(12,12)); + m_delBtn->setFixedSize(24,24); + connect(m_delBtn,&QPushButton::clicked,this,&AppMsg::onDelAppMsg); + m_pFoldBtnHLaout->addWidget(m_foldBtn); + m_pFoldBtnHLaout->addItem(new QSpacerItem(256, 10, QSizePolicy::Expanding)); + m_pFoldBtnHLaout->addWidget(m_delBtn); + m_pFoldBtnHLaout->addItem(new QSpacerItem(6, 10, QSizePolicy::Fixed)); + + QVBoxLayout *m_pFoldBtnVLaout = new QVBoxLayout(); + m_pFoldBtnVLaout->setContentsMargins(0,0,0,0); + m_pFoldBtnVLaout->addLayout(m_pFoldBtnHLaout); + m_pFoldBtnVLaout->addItem(new QSpacerItem(10, 6, QSizePolicy::Fixed)); + + + m_pFoldBtnWid->setContentsMargins(0,0,0,0); + m_pFoldBtnWid->setLayout(m_pFoldBtnVLaout); + m_pFoldBtnWid->setFixedSize(380,42); + //当消息小于等于1时,隐藏 + if(m_bFold || (m_listSingleMsg.count()<=1)) + m_pFoldBtnWid->setVisible(false); + else + m_pFoldBtnWid->setVisible(true); + //--< + + //App信息中的总的垂直布局器 + m_pMainVLaout = new QVBoxLayout(); + m_pMainVLaout->setContentsMargins(0,0,0,0); + m_pMainVLaout->setSpacing(6); + + //如果只有m_pMainVLaout一个管理所有消息列表,当应用消息动态展开时,0号消息会出现闪屏的情况 + //为了规避上述情况,m_pMainVLaout中只防止0号消息,1号消息起全部放置m_pIndexFromOneVLaout中 + m_pIndexFromOneVLaout = new QVBoxLayout(); + m_pIndexFromOneVLaout->setContentsMargins(0,0,0,0); + m_pIndexFromOneVLaout->setSpacing(6); + m_pMainVLaout->addLayout(m_pIndexFromOneVLaout); + + //当出现多条消息时,增加底图 + m_pAppBaseMapWidget = new QWidget; + QVBoxLayout* pBaseMapVLaout = new QVBoxLayout(); + pBaseMapVLaout->setContentsMargins(0,0,0,0); + pBaseMapVLaout->setSpacing(0); + + m_pBaseMapWidget = new QWidget; + m_pBaseMapWidget->setObjectName("BaseMap"); + m_pBaseMapWidget->setFixedWidth(360); + m_pBaseMapWidget->setFixedHeight(0); + m_pAppBaseMapWidget->setAttribute(Qt::WA_TranslucentBackground); + m_pAppBaseMapWidget->setLayout(pBaseMapVLaout); + m_pMainVLaout->addWidget(m_pAppBaseMapWidget, 0 , Qt::AlignHCenter); + m_pAppBaseMapWidget->setVisible(false); + + m_pMainWid = new QWidget(this); + m_pMainWid->setContentsMargins(0,0,0,0); + m_pMainWid->setLayout(m_pMainVLaout); + + m_pMainBaseVLaout = new QVBoxLayout(); + m_pMainBaseVLaout->setContentsMargins(0,0,0,0); + //m_pMainBaseVLaout->addWidget(m_pFoldBtnWid); + m_pMainBaseVLaout->addWidget(m_pMainWid); + this->setLayout(m_pMainBaseVLaout); + + //发个信号通知插件删除该通知应用消息 + connect(this, SIGNAL(Sig_onDeleteAppMsg(AppMsg*)), parent, SLOT(onClearAppMsg(AppMsg*))); + //发个信号通知插件删除该收纳应用消息 + connect(this, SIGNAL(Sig_onDeleteTakeInAppMsg(AppMsg*)), parent, SLOT(onClearTakeInAppMsg(AppMsg*))); + + //发个信号通知插件收纳单条应用消息 + connect(this, SIGNAL(Sig_SendTakeInSingleMsg(QString, QString, QString, QString, QString, QString, QDateTime,int, bool)), + parent, SLOT(onTakeInSingleNotify(QString, QString, QString, QString, QString, QString, QDateTime,int, bool))); + //发个信号通知插件恢复单条应用消息 + connect(this, SIGNAL(Sig_SendAddSingleMsg(QString, QString, QString, QString, QString, QString, QDateTime, int, bool)), + parent, SLOT(onAddSingleNotify(QString, QString, QString, QString, QString, QString, QDateTime, int, bool))); + + //发个统计收纳数更新信号 + connect(this, SIGNAL(Sig_countTakeInBitAndUpate()), parent, SLOT(onCountTakeInBitAndUpate())); + + return; +} + +void AppMsg::paintEvent(QPaintEvent *) +{ + QPainter p(this); + QRect rect = this->rect(); + if(!m_pFoldBtnWid->isVisible()){ + rect.setWidth(rect.width() - 1); + rect.setHeight(rect.height() - 1); + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.setBrush(QBrush(QColor(255, 255, 255, 10))); + p.setPen(Qt::transparent); + p.drawRoundedRect(rect,6,6); + }else{ + rect.setY(rect.y() + 50); + rect.setWidth(rect.width() - 1); + rect.setHeight(rect.height() - 1); + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.setBrush(QBrush(QColor(255, 255, 255, 10))); + p.setPen(Qt::transparent); + p.drawRoundedRect(rect,6,6); + } + + return; +} +//统计应用剩余显示条数 +void AppMsg::statisticLeftItem() +{ + //小于1时,表示列表为空,直接返回 + if(m_listSingleMsg.count() < 1) + { + return; + } + + int nShowLeftCount = m_listSingleMsg.count() - 1; + //当应用处于折叠状态,且剩余条数大于0时,应用底图部件显示 + if ((true == m_bFold) && (nShowLeftCount > 0)) { + m_pAppBaseMapWidget->setVisible(true); + } else { + m_pAppBaseMapWidget->setVisible(false); + } + + SingleMsg* pTopSingleMsg = m_listSingleMsg.at(0); + pTopSingleMsg->setLeftItem(nShowLeftCount); + return; +} + +//当显示的最大消息大于设置的消息数目时删除最早的消息 +void AppMsg::deleteExceedingMsg() +{ + int nIndex = -1; + while (m_listSingleMsg.count() > m_nMaxCount) + { + nIndex = m_listSingleMsg.count() - 1; + if (-1 == nIndex) + { + return; + } + + SingleMsg* pSingleMsg = m_listSingleMsg.at(nIndex); + onDeleSingleMsg(pSingleMsg); + } +} + + +//新增单条消息至通知列表,崭新消息需要new,然后添加至列表最上面 +void AppMsg::addSingleMsg(QString strIconPath, QString strSummary, QDateTime dateTime, QString strBody, QString strUrl, QString strAction) +{ + SingleMsg* pSingleMsg = new SingleMsg(this, strIconPath, m_strAppName, strSummary, dateTime, strBody, strUrl, strAction, m_bTakeInFlag); + + pSingleMsg->setAppFold(m_bFold); + + int uIndex = m_listSingleMsg.count(); + for(int i = m_listSingleMsg.count() - 1; i >= 0; i--) + { + SingleMsg* pTmpSingleMsg = m_listSingleMsg.at(i); + if(pSingleMsg->getPushTime() < pTmpSingleMsg->getPushTime()) + { + break; + } + uIndex = i; + } + + //当新增的消息将插入最顶部时,将已有列表最顶部的老主消息正文设置一行缩略显示 + if((0 == uIndex) && (m_listSingleMsg.count() > 0)) + { + SingleMsg* pFirstMsg = m_listSingleMsg.at(0); + pFirstMsg->setMainFlag(false); + pFirstMsg->setShowLeftItemFlag(false); + + //只有已经折叠的才需要将现有的正文设置为缩略显示 + if(true == m_bFold) + { + pFirstMsg-> setBodyLabelWordWrap(false); + pFirstMsg->setVisible(false); + //将SingleMsg底部设置0px空隙,当其展开时,让他完全从0展开 + pFirstMsg->setSingleMsgContentsMargins(0, 0, 0, 0); + } + + //如果新增的消息将插入最顶部,则将老的顶部消息,先从m_pMainVLaout移除,再插入m_pIndexFromOneVLaout顶部 + m_pMainVLaout->removeWidget(pFirstMsg); + m_pIndexFromOneVLaout->insertWidget(0, pFirstMsg); + } + + //如果插入第0条,并且已展开,则将新增消息设置自动换行,并且折叠标志设为false + if((0 == uIndex) && (false == m_bFold)) + { + pSingleMsg->setBodyLabelWordWrap(true); + pSingleMsg->setFoldFlag(m_bFold); + } + + //如果插入的不是第0条,则自己不能为主 + if(0 != uIndex) + { + pSingleMsg->setMainFlag(false); + //并且已经折叠的自己不可见 + if(true == m_bFold) + { + pSingleMsg->setVisible(false); + } + } + + m_listSingleMsg.insert(uIndex, pSingleMsg); + if(0 != uIndex) + { + //假如新增消息不是插入最顶部,则直接插入m_pIndexFromOneVLaout中的uIndex - 1 + m_pIndexFromOneVLaout->insertWidget(uIndex - 1, pSingleMsg); + } + else + { + //假如新增的消息将插入最顶部,由于上面已把老的顶部消息插入m_pIndexFromOneVLaout的顶部,所以此时直接插入m_pMainVLaout顶部 + m_pMainVLaout->insertWidget(0, pSingleMsg); + } + + //当单个应用的消息达到设置的最大数目时,删除最早的消息并统计数目 + deleteExceedingMsg(); + + //将该应用中最顶上的一条消息的时间赋给应用 + SingleMsg* pTopSingleMsg = m_listSingleMsg.at(0); + m_uNotifyTime = pTopSingleMsg->getPushTime(); + m_dateTime = pTopSingleMsg->getPushDateTime(); + + //统计应用剩余显示条数 + statisticLeftItem(); + + return; +} + +void AppMsg::updateAppPushTime() +{ + for(int i = 0; i < m_listSingleMsg.count(); i++) + { + SingleMsg* pTmpSingleMsg = m_listSingleMsg.at(i); + pTmpSingleMsg->updatePushTime(); + } + + return; +} + +int AppMsg::getSingleMsgCount() +{ + return m_listSingleMsg.count(); +} + +void AppMsg::onDeleteAppMsg() +{ + if(false == m_bTakeInFlag) + { + emit Sig_onDeleteAppMsg(this); //是通知应用就通知插件删该通知应用 + } + else + { + emit Sig_onDeleteTakeInAppMsg(this); //是收纳应用就通知插件删该收纳应用 + } + return; +} + +void AppMsg::onTakeinWholeApp() +{ + while(m_listSingleMsg.count() > 0) + { + SingleMsg* pSingleMsg = m_listSingleMsg.at(0); + m_listSingleMsg.removeAt(0); + m_pMainVLaout->removeWidget(pSingleMsg); + if(m_listSingleMsg.count() > 0) + { + SingleMsg* pTopSingleMsg = m_listSingleMsg.at(0); + m_pIndexFromOneVLaout->removeWidget(pTopSingleMsg); + m_pMainVLaout->insertWidget(0, pTopSingleMsg); + } + + emit Sig_SendTakeInSingleMsg(m_strAppName, pSingleMsg->getIcon(), pSingleMsg->getSummary(), + pSingleMsg->getBody(), pSingleMsg->getUrl(), pSingleMsg->getAction(), + pSingleMsg->getPushDateTime(), 20, false); + } + + emit Sig_onDeleteAppMsg(this); + + return; +} + +void AppMsg::onRecoverWholeApp() +{ + while(m_listSingleMsg.count() > 0) + { + SingleMsg* pSingleMsg = m_listSingleMsg.at(0); + m_listSingleMsg.removeAt(0); + m_pMainVLaout->removeWidget(pSingleMsg); + if(m_listSingleMsg.count() > 0) + { + SingleMsg* pTopSingleMsg = m_listSingleMsg.at(0); + m_pIndexFromOneVLaout->removeWidget(pTopSingleMsg); + m_pMainVLaout->insertWidget(0, pTopSingleMsg); + } + + emit Sig_SendAddSingleMsg(m_strAppName, pSingleMsg->getIcon(), pSingleMsg->getSummary(), + pSingleMsg->getBody(), pSingleMsg->getUrl(), pSingleMsg->getAction(), + pSingleMsg->getPushDateTime(), 20, false); + } + + emit Sig_onDeleteTakeInAppMsg(this); + + return; +} + +void AppMsg::onDeleSingleMsg(SingleMsg* pSingleMsg) +{ + int nIndex = m_listSingleMsg.indexOf(pSingleMsg); + if(-1 == nIndex) + { + qDebug()<<"AppMsg::onDeleSingleMsg 在通知链表中未找到pSingleMsg指针"; + return; + } + + m_listSingleMsg.removeAt(nIndex); + if(0 == nIndex) + { + m_pMainVLaout->removeWidget(pSingleMsg); + if(m_listSingleMsg.count() > 0) + { + SingleMsg* pTopSingleMsg = m_listSingleMsg.at(0); + m_pIndexFromOneVLaout->removeWidget(pTopSingleMsg); + m_pMainVLaout->insertWidget(0, pTopSingleMsg); + } + } + else + { + m_pIndexFromOneVLaout->removeWidget(pSingleMsg); + } + pSingleMsg->deleteLater(); + + //当本次删除为应用首条时,且该应用不止一条,则需将新的首条设置为顶部消息状态 + if(0 == nIndex) + { + setTopWithSecondItem(); + } + + //统计剩余显示条数,看情况显示 + statisticLeftItem(); + + //当删除一条消息后,如果应用列表为空 + if(0 == m_listSingleMsg.count()) + { + if(false == m_bTakeInFlag) + { + emit Sig_onDeleteAppMsg(this); //是通知应用就通知插件删该通知应用 + } + else + { + emit Sig_onDeleteTakeInAppMsg(this); //是收纳应用就通知插件删该收纳应用 + } + } + + //只有当该应用属于收纳应用对象时,每删除一条都要更新收纳计数 + if(true == m_bTakeInFlag) + { + emit Sig_countTakeInBitAndUpate(); + } + return; +} + +//当应用最顶条被删除后,将第二条置顶 +void AppMsg::setTopWithSecondItem() +{ + if(m_listSingleMsg.count() > 0) + { + SingleMsg* pFirstMsg = m_listSingleMsg.at(0); + pFirstMsg->setMainFlag(true); + pFirstMsg->setFoldFlag(m_bFold); + + //都是在删除单挑、收纳单挑和恢复单挑的情况下调用的setTopWithSecondItem,此时App应该都是展开状态 + pFirstMsg->setBodyLabelWordWrap(true); + pFirstMsg->setVisible(true); + } + + return; +} + +//来自SingleMsg下的事件,处理收纳事件 +void AppMsg::onTakeInSingleMsg(SingleMsg* pSingleMsg) +{ + int nIndex = m_listSingleMsg.indexOf(pSingleMsg); + if(-1 == nIndex) + { + qDebug()<<"AppMsg::onTakeInSingleMsg 在通知链表中未找到pSingleMsg指针"; + return; + } + m_listSingleMsg.removeAt(nIndex); + if(0 == nIndex) + { + m_pMainVLaout->removeWidget(pSingleMsg); + if(m_listSingleMsg.count() > 0) + { + SingleMsg* pTopSingleMsg = m_listSingleMsg.at(0); + m_pIndexFromOneVLaout->removeWidget(pTopSingleMsg); + m_pMainVLaout->insertWidget(0, pTopSingleMsg); + } + } + else + { + m_pIndexFromOneVLaout->removeWidget(pSingleMsg); + } + + emit Sig_SendTakeInSingleMsg(m_strAppName, pSingleMsg->getIcon(), pSingleMsg->getSummary(), + pSingleMsg->getBody(), pSingleMsg->getUrl(), pSingleMsg->getAction(), + pSingleMsg->getPushDateTime(), 20, false); + pSingleMsg->deleteLater(); + + //当本次收纳为应用首条时,且该应用不止一条,考虑将新的首条设置为顶部消息状态 + if(0 == nIndex) + { + setTopWithSecondItem(); + } + + //统计剩余显示条数,看情况显示 + statisticLeftItem(); + + if(0 == m_listSingleMsg.count()) + { + emit Sig_onDeleteAppMsg(this); + } +} + +//来自SingleMsg下的事件,处理恢复事件 +void AppMsg::onRecoverSingleMsg(SingleMsg* pSingleMsg) +{ + int nIndex = m_listSingleMsg.indexOf(pSingleMsg); + if(-1 == nIndex) + { + qDebug()<<"AppMsg::onTakeInSingleMsg 在通知链表中未找到pSingleMsg指针"; + return; + } + + m_listSingleMsg.removeAt(nIndex); + if(0 == nIndex) + { + m_pMainVLaout->removeWidget(pSingleMsg); + if(m_listSingleMsg.count() > 0) + { + SingleMsg* pTopSingleMsg = m_listSingleMsg.at(0); + m_pIndexFromOneVLaout->removeWidget(pTopSingleMsg); + m_pMainVLaout->insertWidget(0, pTopSingleMsg); + } + } + else + { + m_pIndexFromOneVLaout->removeWidget(pSingleMsg); + } + + + emit Sig_SendAddSingleMsg(m_strAppName, pSingleMsg->getIcon(), pSingleMsg->getSummary(), + pSingleMsg->getBody(), pSingleMsg->getUrl(), pSingleMsg->getAction(), + pSingleMsg->getPushDateTime(), 20, false); + pSingleMsg->deleteLater(); + + //当本次收纳为应用首条时,且该应用不止一条,考虑将新的首条设置为顶部消息状态 + if(0 == nIndex) + { + setTopWithSecondItem(); + } + + //统计剩余显示条数,看情况显示 + statisticLeftItem(); + + if(0 == m_listSingleMsg.count()) + { + emit Sig_onDeleteTakeInAppMsg(this); + } + + //只有当该应用属于收纳应用对象时,每恢复一条都要更新收纳计数 + if(true == m_bTakeInFlag) + { + emit Sig_countTakeInBitAndUpate(); + } +} + +void AppMsg::setAppFoldFlag(bool bFlag) +{ + m_bFold = bFlag; + + //当应用处于展开状态,或者总条数小于等于1时,应用底图部件隐藏 + if((false == m_bFold) || (m_listSingleMsg.count() <= 1)) + { + m_pAppBaseMapWidget->setVisible(false); + } + + if(m_listSingleMsg.count() <= 1) + { + return; + } + + //false表示应用展开 + if(false == m_bFold) + { + //--> + //折叠按钮显示动画:App消息窗口下移,折叠按钮窗口下移 + if(m_listSingleMsg.count()>1) + m_pFoldBtnWid->setVisible(true); + int widthFoldWid = m_pFoldBtnWid->width(); + int heightFoldWid = m_pFoldBtnWid->height(); + QPropertyAnimation* pAnimation2 = new QPropertyAnimation(this, "geometryFold"); + connect(pAnimation2, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value){ + QRect Rect = value.value(); + int x1, y1, x2, y2; + Rect.getRect(&x1, &y1, &x2, &y2); + m_pFoldBtnWid->setGeometry(x1, y1, x2, y2); + }); + connect(pAnimation2, &QPropertyAnimation::finished, this,[=](){ + m_pMainBaseVLaout->insertWidget(0,m_pFoldBtnWid); + }); + pAnimation2->setDuration(30); + pAnimation2->setStartValue(QRect(0, heightFoldWid, widthFoldWid, heightFoldWid)); + pAnimation2->setEndValue(QRect(0, 0, widthFoldWid, heightFoldWid)); + pAnimation2->start(QAbstractAnimation::DeleteWhenStopped); + + int widthAppWid = m_pMainWid->width(); + int heightAppWid = m_pMainWid->height(); + QPropertyAnimation* pAnimation1 = new QPropertyAnimation(this, "geometryMain"); + connect(pAnimation1, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value){ + QRect Rect = value.value(); + int x1, y1, x2, y2; + Rect.getRect(&x1, &y1, &x2, &y2); + m_pMainWid->setGeometry(x1, y1, x2, y2); + }); + connect(pAnimation1, &QPropertyAnimation::finished, this,[=](){ + //多条消息展开动画:展开时,索引从第1条开始,消息全部可见 + SingleMsg* pFristSingleMsg = m_listSingleMsg.at(0); //展开第一条消息的正文内容 + pFristSingleMsg->setBodyLabelWordWrap(true); + pFristSingleMsg->setAppFold(false); + for(int i = 1; i < m_listSingleMsg.count(); i++) + { + SingleMsg* pTmpSingleMsg = m_listSingleMsg.at(i); + pTmpSingleMsg->setBodyLabelWordWrap(true); + pTmpSingleMsg->setFoldFlag(false); + pTmpSingleMsg->setAppFold(false); + pTmpSingleMsg->startAnimationUnfold(); + } + }); + pAnimation1->setDuration(30); + pAnimation1->setStartValue(QRect(0, 0, widthAppWid, heightAppWid)); + pAnimation1->setEndValue(QRect(0, m_pFoldBtnWid->height(), widthAppWid, heightAppWid)); + pAnimation1->start(QAbstractAnimation::DeleteWhenStopped); + //--< + + } + else + { + //折叠时,索引从第1条开始,消息全部不可见 + for(int i = 1; i < m_listSingleMsg.count(); i++) + { + SingleMsg* pTmpSingleMsg = m_listSingleMsg.at(i); + pTmpSingleMsg->startAnimationFold(); + } + m_pMainBaseVLaout->removeWidget(m_pFoldBtnWid); + m_pFoldBtnWid->setVisible(false); + } + +} + +//折叠整个应用的消息 +void AppMsg::onFoldAppWidget() +{ + //折叠按钮显示动画:折叠按钮窗口上移,App消息窗口上移 + m_bFold = true; + + int widthFoldWid = m_pFoldBtnWid->width(); + int heightFoldWid = m_pFoldBtnWid->height(); + QPropertyAnimation* pAnimation2 = new QPropertyAnimation(this, "btnWidFold"); + connect(pAnimation2, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value){ + QRect Rect = value.value(); + int x1, y1, x2, y2; + Rect.getRect(&x1, &y1, &x2, &y2); + m_pFoldBtnWid->setGeometry(x1, y1, x2, y2); + }); + connect(pAnimation2, &QPropertyAnimation::finished, this,[=](){ + m_pFoldBtnWid->setVisible(false); + m_pMainBaseVLaout->removeWidget(m_pFoldBtnWid); + emit Sig_foldAnimationFinish(); + }); + pAnimation2->setDuration(30); + pAnimation2->setStartValue(QRect(0, 0, widthFoldWid, heightFoldWid)); + pAnimation2->setEndValue(QRect(0, 0-heightFoldWid, widthFoldWid, heightFoldWid)); + pAnimation2->start(QAbstractAnimation::DeleteWhenStopped); + + int widthAppWid = m_pMainWid->width(); + int heightAppWid = m_pMainWid->height(); + QPropertyAnimation* pAnimation1 = new QPropertyAnimation(this, "appMainFold"); + connect(pAnimation1, &QPropertyAnimation::valueChanged, this, [=](const QVariant &value){ + QRect Rect = value.value(); + int x1, y1, x2, y2; + Rect.getRect(&x1, &y1, &x2, &y2); + m_pMainWid->setGeometry(x1, y1, x2, y2); + }); + connect(pAnimation1, &QPropertyAnimation::finished, this,[=](){ + //折叠时,索引从第1条开始,消息全部不可见 + SingleMsg* pFristSingleMsg = m_listSingleMsg.at(0); //折叠第一条消息的正文内容 + pFristSingleMsg->setBodyLabelWordWrap(false); + pFristSingleMsg->setAppFold(true); + pFristSingleMsg->setFoldFlag(true); + for(int i = 1; i < m_listSingleMsg.count(); i++) + { + SingleMsg* pTmpSingleMsg = m_listSingleMsg.at(i); + pTmpSingleMsg->setBodyLabelWordWrap(false); + pTmpSingleMsg->setAppFold(true); + pTmpSingleMsg->setFoldFlag(true); + pTmpSingleMsg->startAnimationFold(); + } + m_pMainBaseVLaout->removeWidget(m_pFoldBtnWid); + m_pFoldBtnWid->setVisible(false); + }); + pAnimation1->setDuration(30); + pAnimation1->setStartValue(QRect(0, m_pFoldBtnWid->height(), widthAppWid, heightAppWid)); + pAnimation1->setEndValue(QRect(0, 0, widthAppWid, heightAppWid)); + pAnimation1->start(QAbstractAnimation::DeleteWhenStopped); + //--< +} + +void AppMsg::onDelAppMsg() +{ + //删除整个应用消息动画:先折叠,再左移动画,最后上移动画 + SingleMsg* pFristSingleMsg = m_listSingleMsg.at(0); + connect(this,&AppMsg::Sig_foldAnimationFinish,this,[=](){ + QTimer *timer = new QTimer(); + timer->setSingleShot(true); //设置一个单次定时器,只为延迟200毫秒,等待折叠动画完成 + connect(timer, &QTimer::timeout, this, [=](){ + pFristSingleMsg->onDele(); //开启左移动画,上移动画 + }); + timer->start(200); + }); + onFoldAppWidget(); +} + +//当app展开时,将app设置折叠 +void AppMsg::setAppFold() +{ + if(false == m_bFold) + { + //假如应用展开,则将应用主消息设置折叠 + SingleMsg* pFirstSingleMsg = m_listSingleMsg.at(0); + pFirstSingleMsg->mainMsgSetFold(); + + } + m_pFoldBtnWid->setVisible(false); //单条消息不显示折叠按钮 +} + +//应用主消息进入 +void AppMsg::onMainMsgEnter() +{ + //m_pBaseMapWidget->setStyleSheet("QWidget{background:rgba(255,255,255,0.1);border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-left-radius:6px;border-bottom-right-radius:6px;}"); +} + +//应用主消息离开 +void AppMsg::onMainMsgLeave() +{ + //m_pBaseMapWidget->setStyleSheet("QWidget{background:rgba(255,255,255,0.04);border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-left-radius:6px;border-bottom-right-radius:6px;}"); +} + +void AppMsg::onShowBaseMap() +{ + //当应用处于折叠状态,且总条数大于1时,应用底图部件显示 + if((true == m_bFold) && (m_listSingleMsg.count() > 1)) + { + SingleMsg* pTmpSingleMsg = m_listSingleMsg.at(0); + pTmpSingleMsg->setSingleMsgContentsMargins(0, 0, 0, 0); //假如折叠,剩余条目显示将可见,则SingleMsg的内容均无空隙 + pTmpSingleMsg->setShowLeftItemFlag(true); + m_pAppBaseMapWidget->setVisible(true); + } +} + +//隐藏底图部件 +void AppMsg::onHideBaseMap() +{ + m_pAppBaseMapWidget->setVisible(false); +} + diff --git a/src/plugins/ukui-sidebar-notification/appmsg.h b/src/plugins/ukui-sidebar-notification/appmsg.h new file mode 100644 index 0000000..d9bc418 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/appmsg.h @@ -0,0 +1,103 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include + +class NotificationPlugin; +class SingleMsg; + +class AppMsg : public QWidget +{ + Q_OBJECT +public: + AppMsg(NotificationPlugin *parent, QString strAppName, bool bTakeInFlag = false); + uint getAppPushTime() {return m_uNotifyTime;} + QString getAppName() {return m_strAppName;} + void addSingleMsg(QString strIconPath, QString strSummary, QDateTime dateTime, QString strBody, QString strUrl, QString strAction); + void deleteExceedingMsg(); //删除超出最大数的消息 + void updateAppPushTime(); //更新应用最新的推送时间 + int getSingleMsgCount(); //获取应用消息数 + void statisticLeftItem(); //统计应用剩余显示条数 + void setTopWithSecondItem(); //当应用最顶条被删除后,将第二条置顶 + void setAppFold(); //当app展开时,将app设置折叠 + void setMaxNumMsg(int nMaxNum) {m_nMaxCount = nMaxNum;} + bool getFoldFlag() {return m_bFold;} + void setFoldFlag(bool bFlag) {m_bFold = bFlag;} + + void paintEvent(QPaintEvent *); //重绘事件 + + +private: + QVBoxLayout* m_pMainBaseVLaout; //APP信息中的整体布局 + QWidget* m_pMainWid; //App信息中的总窗口 + QVBoxLayout* m_pMainVLaout; //App信息中的总的垂直布局器 + QWidget* m_pFoldBtnWid; //折叠按钮和删除按钮窗口 + QVBoxLayout* m_pIndexFromOneVLaout; + QWidget* m_pAppBaseMapWidget; //多条消息时,底图部件包括底部6个px的空白 + QWidget* m_pBaseMapWidget; //多条消息时,底图部件不包括底部6个px的空白 + QList m_listSingleMsg; //对于SingleMsg类对象用list表记录 + QString m_strAppName; //保存发送方的应用名 + QDateTime m_dateTime; //保存推送时间 + uint m_uNotifyTime; //保存推送时间的绝对时间 + bool m_bTakeInFlag; //转变为收纳消息吗,默认为false + bool m_bFold; //折叠标志 + int m_nMaxCount; //应用消息最大收录数 + QPushButton* m_foldBtn; //折叠按钮 + QPushButton* m_delBtn; //清除按钮 + + + +signals: + void Sig_onDeleteAppMsg(AppMsg* p); //该对象属于通知应用,发出删除应用的信号 + void Sig_onDeleteTakeInAppMsg(AppMsg* p); //当该对象属于收纳应用时,发出删除收纳应用的信号 + void Sig_countTakeInBitAndUpate(); //发个统计收纳数信号 + void Sig_SendTakeInSingleMsg(QString strAppName, QString strIcon, QString strSummary, QString strBody, QString urlStr, QString actions, QDateTime dateTime, int maxNum, bool bNewTakeinFlag); + void Sig_SendAddSingleMsg(QString strAppName, QString strIcon, QString strSummary, QString strBody, QString urlStr, QString actions, QDateTime dateTime, int maxNum, bool bNewNotificationFlag); + void Sig_foldAnimationFinish(); //折叠按钮窗口的消失动画完成信号 + +public slots: + void onDeleteAppMsg(); //删除一个应用消息 + void onTakeinWholeApp(); //收纳整个应用消息 + void onRecoverWholeApp(); //恢复整个应用消息 + void onDeleSingleMsg(SingleMsg* pSingleMsg); //删除单条消息 + void onTakeInSingleMsg(SingleMsg* pSingleMsg); //收纳单条消息 + void onRecoverSingleMsg(SingleMsg* pSingleMsg); //恢复单条消息 + void setAppFoldFlag(bool bFlag); //设置应用折叠标志 + void onFoldAppWidget(); //折叠整个应用消息 + void onDelAppMsg(); //删除整个应用的消息 + void onMainMsgEnter(); //应用主消息进入 + void onMainMsgLeave(); //应用主消息离开 + void onShowBaseMap(); //显示应用底图 + void onHideBaseMap(); //隐藏底图部件 + + + +}; + +#endif // APPMSG_H diff --git a/src/plugins/ukui-sidebar-notification/buttonwidget.cpp b/src/plugins/ukui-sidebar-notification/buttonwidget.cpp new file mode 100644 index 0000000..faab37f --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/buttonwidget.cpp @@ -0,0 +1,109 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include + +ButtonWidget::ButtonWidget(QString strIcon, QString strHoverIcon, QString strPressIcon,QSize normalIconSize,QSize pressIconSize) +{ + m_strIcon = strIcon; + m_strHoverIcon = strHoverIcon; + m_strPressIcon = strPressIcon; + + this->setFixedWidth(24); + this->setFixedHeight(24); + QVBoxLayout* pVBoxLayout = new QVBoxLayout; + pVBoxLayout->setContentsMargins(0,0,0,0); + pVBoxLayout->setSpacing(0); + + m_ToolButton = new QLabel; + m_pTakeinSvgRender = new QSvgRenderer(m_ToolButton); + m_pTakeinSvgRender->load(m_strIcon); + m_ToolButton->setAttribute(Qt::WA_TranslucentBackground); + m_pTakeinPixmap = new QPixmap(normalIconSize); + m_pTakeinPressPixmap = new QPixmap(pressIconSize); + m_pTakeinPixmap->fill(Qt::transparent); + QPainter takeinPainter(m_pTakeinPixmap); + m_pTakeinSvgRender->render(&takeinPainter); + m_ToolButton->setPixmap(*m_pTakeinPixmap); + + pVBoxLayout->addWidget(m_ToolButton, 0, Qt::AlignHCenter | Qt::AlignVCenter); + this->setLayout(pVBoxLayout); + + return; +} + +void ButtonWidget::enterEvent(QEvent *event) +{ + Q_UNUSED(event); + m_pTakeinSvgRender->load(m_strHoverIcon); + m_pTakeinPixmap->fill(Qt::transparent); + QPainter takeinPainter(m_pTakeinPixmap); + m_pTakeinSvgRender->render(&takeinPainter); + m_ToolButton->setPixmap(*m_pTakeinPixmap); + + return; +} + +void ButtonWidget::leaveEvent(QEvent *event) +{ + Q_UNUSED(event); + m_pTakeinSvgRender->load(m_strIcon); + m_pTakeinPixmap->fill(Qt::transparent); + QPainter takeinPainter(m_pTakeinPixmap); + m_pTakeinSvgRender->render(&takeinPainter); + m_ToolButton->setPixmap(*m_pTakeinPixmap); + + return; +} + +//鼠标点击事件 +void ButtonWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->buttons() == Qt::LeftButton) + { + m_pTakeinSvgRender->load(m_strPressIcon); + m_pTakeinPressPixmap->fill(Qt::transparent); + QPainter takeinPainter(m_pTakeinPressPixmap); + m_pTakeinSvgRender->render(&takeinPainter); + m_ToolButton->setPixmap(*m_pTakeinPressPixmap); + } + + return; +} + +void ButtonWidget::mouseReleaseEvent(QMouseEvent *event) +{ + int x = event->x(); + int y = event->y(); + qDebug()<<"ButtonWidget::mouseReleaseEvent" <= 0 && x <= 24 && y >= 0 && y<=24) + { + emit Sig_clicked(); + } + + return; +} diff --git a/src/plugins/ukui-sidebar-notification/buttonwidget.h b/src/plugins/ukui-sidebar-notification/buttonwidget.h new file mode 100644 index 0000000..51d97ca --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/buttonwidget.h @@ -0,0 +1,57 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include + +class QSvgRenderer; + +class ButtonWidget : public QWidget +{ + Q_OBJECT +public: + explicit ButtonWidget(QString strIcon, QString strHoverIcon, QString strPressIcon,QSize nomalIconSize,QSize pressIconSize); + +protected: + virtual void enterEvent(QEvent *event) override; + virtual void leaveEvent(QEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; + +private: + QLabel* m_ToolButton; + QSvgRenderer* m_pTakeinSvgRender; + QPixmap* m_pTakeinPixmap; //收纳默认或悬停时的像素 + QPixmap* m_pTakeinPressPixmap; //收纳点击时的像素 + + bool m_bTakeInFlag; + QString m_strIcon; + QString m_strHoverIcon; + QString m_strPressIcon; + +signals: + void Sig_clicked(); + +public slots: + +}; + +#endif // BUTTONWIDGET_H diff --git a/src/plugins/ukui-sidebar-notification/customstylePushbutton2.cpp b/src/plugins/ukui-sidebar-notification/customstylePushbutton2.cpp new file mode 100644 index 0000000..2c5350d --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/customstylePushbutton2.cpp @@ -0,0 +1,218 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +#include +#include + +#include + +CustomStyle_pushbutton_2::CustomStyle_pushbutton_2(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) +{ + Q_UNUSED(parent); +} + +void CustomStyle_pushbutton_2::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + return QProxyStyle::drawComplexControl(control, option, painter, widget); +} + +void CustomStyle_pushbutton_2::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch (element) { + case QStyle::CE_PushButton: { + QStyleOptionButton button = *qstyleoption_cast(option); + button.palette.setColor(QPalette::HighlightedText, button.palette.buttonText().color()); + return QProxyStyle::drawControl(element, &button, painter, widget); + break; + } + default: + break; + } + return QProxyStyle::drawControl(element, option, painter, widget); +} + +void CustomStyle_pushbutton_2::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +} + +void CustomStyle_pushbutton_2::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +} + +/// 我们重写button的绘制方法,通过state和当前动画的状态以及value值改变相关的绘制条件 +/// 这里通过判断hover与否,动态的调整painter的透明度然后绘制背景 +/// 需要注意的是,默认控件的绘制流程只会触发一次,而动画需要我们在一段时间内不停绘制才行, +/// 要使得动画能够持续,我们需要使用QWidget::update()在动画未完成时, +/// 手动更新一次,这样button将在一段时间后再次调用draw方法,从而达到更新动画的效果 +/// +/// 需要注意绘制背景的流程会因主题不同而产生差异,所以这一部分代码在一些主题中未必正常, +/// 如果你需要自己实现一个主题,这同样是你需要注意和考虑的点 +void CustomStyle_pushbutton_2::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ +// if (element == PE_PanelButtonCommand) { +// qDebug()<<"draw pe button"; +// if (widget) { +// bool isPressed = false; +// bool isHover = false; +// if (!option->state.testFlag(State_Sunken)) { +// if (option->state.testFlag(State_MouseOver)) { +// isHover = true; +// } +// } else { +// isPressed = true; +// } + +// QStyleOption opt = *option; +// if (isHover) { +// QColor color(255,255,255,51); +// opt.palette.setColor(QPalette::Highlight, color); + +// } +// if (isPressed) { +// QColor color(255,255,255,21); +// opt.palette.setColor(QPalette::Highlight, color); +// } +// if (!isHover && !isPressed) { +// QColor color(255,255,255,31); +// opt.palette.setColor(QPalette::Button,color); +// } +// return QProxyStyle::drawPrimitive(element, &opt, painter, widget); +// } +// } +// return QProxyStyle::drawPrimitive(element, option, painter, widget); + if (element == PE_PanelButtonCommand) { + if (widget) { + if (option->state & State_MouseOver) { + if (option->state & State_Sunken) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,21); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,51); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + } else { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing,true); + painter->setPen(Qt::NoPen); + QColor color(255,255,255,0); + painter->setBrush(color); + painter->drawRoundedRect(option->rect, 4, 4); + painter->restore(); + } + return; + } + } + return QProxyStyle::drawPrimitive(element, option, painter, widget); +} + +QPixmap CustomStyle_pushbutton_2::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl CustomStyle_pushbutton_2::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +{ + return QProxyStyle::hitTestComplexControl(control, option, position, widget); +} + +QRect CustomStyle_pushbutton_2::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +{ + return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +} + +QRect CustomStyle_pushbutton_2::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +{ + return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +} + +int CustomStyle_pushbutton_2::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::pixelMetric(metric, option, widget); +} + +/// 我们需要将动画与widget一一对应起来, +/// 在一个style的生命周期里,widget只会进行polish和unpolish各一次, +/// 所以我们可以在polish时将widget与一个新的动画绑定,并且对应的在unpolish中解绑定 +void CustomStyle_pushbutton_2::polish(QWidget *widget) +{ + return QProxyStyle::polish(widget); +} + +void CustomStyle_pushbutton_2::polish(QApplication *application) +{ + return QProxyStyle::polish(application); +} + +void CustomStyle_pushbutton_2::polish(QPalette &palette) +{ + return QProxyStyle::polish(palette); +} + +void CustomStyle_pushbutton_2::unpolish(QWidget *widget) +{ + return QProxyStyle::unpolish(widget); +} + +void CustomStyle_pushbutton_2::unpolish(QApplication *application) +{ + return QProxyStyle::unpolish(application); +} + +QSize CustomStyle_pushbutton_2::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} + +QIcon CustomStyle_pushbutton_2::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::standardIcon(standardIcon, option, widget); +} + +QPalette CustomStyle_pushbutton_2::standardPalette() const +{ + return QProxyStyle::standardPalette(); +} + +int CustomStyle_pushbutton_2::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +QRect CustomStyle_pushbutton_2::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +{ + return QProxyStyle::subControlRect(control, option, subControl, widget); +} + +QRect CustomStyle_pushbutton_2::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + return QProxyStyle::subElementRect(element, option, widget); +} diff --git a/src/plugins/ukui-sidebar-notification/customstylePushbutton2.h b/src/plugins/ukui-sidebar-notification/customstylePushbutton2.h new file mode 100644 index 0000000..abfbd93 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/customstylePushbutton2.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +class CustomStyle_pushbutton_2 : public QProxyStyle +{ + Q_OBJECT +public: + explicit CustomStyle_pushbutton_2(const QString &proxyStyleName = "windows", QObject *parent = nullptr); + virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + /*! + * \brief drawPrimitive + * \param element 背景绘制,对应PE枚举类型 + * \param option + * \param painter + * \param widget + * \details + * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, + * 我们一般需要判断控件的状态来绘制不同的背景, + * 比如按钮的hover和点击效果。 + */ + virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; + virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; + virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; + virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; + virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; + //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); + virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + + virtual void polish(QWidget *widget); + virtual void polish(QApplication *application); + virtual void polish(QPalette &palette); + virtual void unpolish(QWidget *widget); + virtual void unpolish(QApplication *application); + + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; + virtual QPalette standardPalette() const; + virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; + + virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; + + virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; + +signals: + +public slots: + +private: +}; + +#endif // CUSTOMSTYLE_PUSHBUTTON_2_H diff --git a/src/plugins/ukui-sidebar-notification/images/box-14-translucent.svg b/src/plugins/ukui-sidebar-notification/images/box-14-translucent.svg new file mode 100644 index 0000000..0dcf97d --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/box-14-translucent.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/box-16-translucent.svg b/src/plugins/ukui-sidebar-notification/images/box-16-translucent.svg new file mode 100644 index 0000000..c08a98a --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/box-16-translucent.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/box-16.svg b/src/plugins/ukui-sidebar-notification/images/box-16.svg new file mode 100644 index 0000000..efcce31 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/box-16.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/box-20-hover.svg b/src/plugins/ukui-sidebar-notification/images/box-20-hover.svg new file mode 100644 index 0000000..f8d5954 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/box-20-hover.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/box-24-hover.svg b/src/plugins/ukui-sidebar-notification/images/box-24-hover.svg new file mode 100644 index 0000000..15fff37 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/box-24-hover.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/box-24.svg b/src/plugins/ukui-sidebar-notification/images/box-24.svg new file mode 100644 index 0000000..2238f7b --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/box-24.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/exitbox-14-translucent.svg b/src/plugins/ukui-sidebar-notification/images/exitbox-14-translucent.svg new file mode 100644 index 0000000..9065e3b --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/exitbox-14-translucent.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/exitbox-16-translucent.svg b/src/plugins/ukui-sidebar-notification/images/exitbox-16-translucent.svg new file mode 100644 index 0000000..ed00954 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/exitbox-16-translucent.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/exitbox-16.svg b/src/plugins/ukui-sidebar-notification/images/exitbox-16.svg new file mode 100644 index 0000000..ea80f15 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/exitbox-16.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/exitbox-20-hover.svg b/src/plugins/ukui-sidebar-notification/images/exitbox-20-hover.svg new file mode 100644 index 0000000..92d8c6c --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/exitbox-20-hover.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/exitbox-24-hover.svg b/src/plugins/ukui-sidebar-notification/images/exitbox-24-hover.svg new file mode 100644 index 0000000..7cc40ee --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/exitbox-24-hover.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/exitbox-24.svg b/src/plugins/ukui-sidebar-notification/images/exitbox-24.svg new file mode 100644 index 0000000..f839f6b --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/exitbox-24.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/hover-translucent.svg b/src/plugins/ukui-sidebar-notification/images/hover-translucent.svg new file mode 100644 index 0000000..d4997c3 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/hover-translucent.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/images/hover.svg b/src/plugins/ukui-sidebar-notification/images/hover.svg new file mode 100644 index 0000000..4a66e28 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/images/hover.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/plugins/ukui-sidebar-notification/monitorthread.cpp b/src/plugins/ukui-sidebar-notification/monitorthread.cpp new file mode 100644 index 0000000..41bcdce --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/monitorthread.cpp @@ -0,0 +1,313 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +} + +#define NOTICE_ORIGIN_SCHEMA "org.ukui.control-center.noticeorigin" +#define NOTICE_ORIGIN_PATH "/org/ukui/control-center/noticeorigin/" + +#define SWITCH_KEY "messages" +#define MAXIMINE_KEY "maximize" +#define NAME_KEY "nameCn" + +MonitorThread::MonitorThread(NotificationPlugin *parent) +{ + m_parent = parent; +// getSettingsValue(); + + this->moveToThread(this); +} + +void MonitorThread::extractData(QString strOutput) +{ + QString strOutputTmp = strOutput; + + //app名的获取 + int nIndex = strOutputTmp.indexOf("\""); + if (-1 == nIndex) { + return; + } + + strOutputTmp = strOutputTmp.mid(nIndex + 1); + nIndex = strOutputTmp.indexOf("\""); + if (-1 == nIndex) { + return; + } + QString strAppName = strOutputTmp.mid(0, nIndex); + if(strAppName =="") { + return; + } + strOutputTmp = strOutputTmp.mid(nIndex + 1); + + if(!getControlCentorAppNotify(strAppName)) { + qDebug()<::const_iterator iter = m_nAppMaxNum.find(strAppName); + int nMaxNum = 3; + + if ((iter != m_nAppMaxNum.end()) && (iter.value() > 0)) { //找到 + nMaxNum = iter.value(); + } + + QDateTime dateTime(QDateTime::currentDateTime()); + + QMap::const_iterator iter1 = m_mapAppSwitch.find(strAppName); + if (iter1 == m_mapAppSwitch.end()) { //未找到 + emit Sig_Notify(strAppName, strIcon, strSummary, strBody, dateTime, nMaxNum, true); + } else { + emit Sig_Takein(strAppName, strIcon, strSummary, strBody, dateTime, nMaxNum, true); + } + + return; +} + +//获取路径并创建gsetting +void MonitorThread::getSettingsValue() +{ + QList existsPath = listExistsPath(); + for (char* path : existsPath) { + char* prepath = QString(NOTICE_ORIGIN_PATH).toLatin1().data(); + char* allpath = strcat(prepath, path); + + const QByteArray ba(NOTICE_ORIGIN_SCHEMA); + const QByteArray bba(allpath); + m_pSettings = new QGSettings(ba, bba, this); + fromSettingsGetInfoToList(); + //监听setting的状态和最大数目改变 + connect(m_pSettings, SIGNAL(changed(const QString &)),this,SLOT(appNotifySettingChangedSlot())); + } +} + +void MonitorThread::fromSettingsGetInfoToList() +{ + //存储settings,应用名和最大显示数目,以及true + if (false == m_pSettings->keys().contains(NAME_KEY)) { + return; + } + + QString strAppName = m_pSettings->get(NAME_KEY).toString(); + + if (m_pSettings->keys().contains(MAXIMINE_KEY)) { + int maxNum = m_pSettings->get(MAXIMINE_KEY).toInt(); + m_nAppMaxNum.insert(strAppName, maxNum); + } + + if (m_pSettings->keys().contains(SWITCH_KEY)) { + powerstatus = m_pSettings->get(SWITCH_KEY).toBool(); + qDebug()<<"初始电源通知状态:"< MonitorThread::listExistsPath() +{ + char** childs; + int len; + + DConfClient * client = dconf_client_new(); + childs = dconf_client_list(client, NOTICE_ORIGIN_PATH, &len); + g_object_unref(client); + + QList vals; + + for (int i = 0; childs[i] != NULL; i++) { + if (dconf_is_rel_dir(childs[i], NULL)) { + char* val = g_strdup(childs[i]); + vals.append(val); + } + } + g_strfreev(childs); + return vals; +} + +bool MonitorThread::getControlCentorAppNotify(QString appName) +{ + // 初始化控制面板对于通知开关读取 + const QByteArray id_3(NOTICE_ORIGIN_SCHEMA); + if (QGSettings::isSchemaInstalled(id_3)) { + QString dynamicPath = QString("%1%2/") + .arg(NOTICE_ORIGIN_PATH) + .arg(QString(appName)); + const QByteArray id_4(dynamicPath.toUtf8().data()); + m_pControlCenterGseting = new QGSettings(id_3, id_4, this); + bool status = m_pControlCenterGseting->get(SWITCH_KEY).toBool(); + return status; + } else { + return false; + } +} + +void MonitorThread::appNotifySettingChangedSlot() +{ + int maxNum = 0; + QString strAppName = ""; + bool status = false; + + if (false == m_pSettings->keys().contains(NAME_KEY)) { + return; + } + + strAppName = m_pSettings->get(NAME_KEY).toString(); + + if (m_pSettings->keys().contains(MAXIMINE_KEY)) { + maxNum = m_pSettings->get(MAXIMINE_KEY).toInt(); + m_nAppMaxNum[strAppName] = maxNum; + emit Sig_UpdateAppMaxNum(strAppName, maxNum); + } + + if (m_pSettings->keys().contains(SWITCH_KEY)) { + status = m_pSettings->get(SWITCH_KEY).toBool(); + powerstatus= m_pSettings->get(SWITCH_KEY).toBool(); + qDebug()<<"电源统计状态更改为:"<::const_iterator iter1 = m_mapAppSwitch.find(strAppName); + if (iter1 == m_mapAppSwitch.end()) { //没找到,没在黑名单 + if(false == status) { + m_mapAppSwitch.insert(strAppName, status); + emit Sig_CloseAppMsg(strAppName); //对于没在黑名单的,新增黑名单关闭消息要求实时更新至通知列表 + } + } else { + if (true == status) { + m_mapAppSwitch.remove(strAppName); + } + } + } +} + +void MonitorThread::readOutputData() +{ + QByteArray output = m_pProcess->readAllStandardOutput(); + + if (false == m_bEnabled) { //上面的内容必须读空再返回,不然就一直有缓存 + return; + } + + QString str_output = output; + + if (str_output.isEmpty()) { + return; + } + + int nIndex = 0; + do { + nIndex = str_output.indexOf("member=Notify"); + if (-1 == nIndex) { + break; + } + str_output = str_output.mid(nIndex + 13); + extractData(str_output); + + } while (str_output.size() > 0); + + return; +} + +void MonitorThread::switchEnable(bool bEnabled) +{ + if (m_bEnabled != bEnabled) { + m_bEnabled = bEnabled; + } +} + +void MonitorThread::run() +{ + getSettingsValue(); + system("killall dbus-monitor"); + m_pProcess = new QProcess(this); + m_pProcess->start("dbus-monitor interface=org.freedesktop.Notifications"); + + QTimer* pTimer = new QTimer(this); + connect(pTimer, SIGNAL(timeout()), this, SLOT(readOutputData())); + pTimer->start(1000); + + //将消息添加到通知中心或收纳盒 + connect(this, SIGNAL(Sig_Notify(QString, QString, QString, QString, QDateTime, int, bool)), m_parent, SLOT(onAddSingleNotify(QString, QString, QString, QString, QDateTime, int, bool))); + + connect(this, SIGNAL(Sig_Takein(QString, QString, QString, QString, QDateTime, int, bool)), m_parent, SLOT(onTakeInSingleNotify(QString, QString, QString, QString, QDateTime, int, bool))); + + //配置实时关闭通知消息 + connect(this, SIGNAL(Sig_CloseAppMsg(QString)), m_parent, SLOT(onCloseAppMsg(QString))); + //配置实时更新通知消息最大数 + connect(this, SIGNAL(Sig_UpdateAppMaxNum(QString, int)), m_parent, SLOT(onUpdateAppMaxNum(QString, int))); + + exec(); + +} diff --git a/src/plugins/ukui-sidebar-notification/monitorthread.h b/src/plugins/ukui-sidebar-notification/monitorthread.h new file mode 100644 index 0000000..c33b035 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/monitorthread.h @@ -0,0 +1,64 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include + +class NotificationPlugin; +class QProcess; + +class MonitorThread : public QThread +{ + Q_OBJECT +public: + MonitorThread(NotificationPlugin *parent); + void run(); //线程入口函数(工作线程的主函数) + void extractData(QString strOutput); + void getSettingsValue(); + QList listExistsPath(); + void fromSettingsGetInfoToList(); + void switchEnable(bool bEnabled); + bool powerstatus =true; + +private: + NotificationPlugin* m_parent; //传一个插件对象指针,用来回传槽函数 + QProcess* m_pProcess; + QGSettings* m_pSettings; + QGSettings* m_pControlCenterGseting; + QMap m_nAppMaxNum; + QMap m_mapAppSwitch; + bool m_bEnabled; //控制面板通知中心总开关 + bool getControlCentorAppNotify(QString appName); + +signals: + void Sig_Notify(QString, QString, QString, QString, QDateTime, int, bool); + void Sig_Takein(QString, QString, QString, QString, QDateTime, int, bool); + void Sig_CloseAppMsg(QString strAppName); + void Sig_UpdateAppMaxNum(QString strAppName, int maxNum); + +public slots: + void readOutputData(); + void appNotifySettingChangedSlot(); +}; + +#endif // MONITORTHREAD_H diff --git a/src/plugins/ukui-sidebar-notification/notificationDbus.cpp b/src/plugins/ukui-sidebar-notification/notificationDbus.cpp new file mode 100644 index 0000000..4e4b557 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/notificationDbus.cpp @@ -0,0 +1,192 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include + +/* qt会将glib里的signals成员识别为宏,所以取消该宏 + * 后面如果用到signals时,使用Q_SIGNALS代替即可 + **/ +#ifdef signals +#undef signals +#endif + +extern "C" { +#include +#include +#include +} +#define NOTICE_ORIGIN_SCHEMA "org.ukui.control-center.noticeorigin" +#define NOTICE_ORIGIN_PATH "/org/ukui/control-center/noticeorigin/" +#define SWITCH_KEY "messages" +#define MAXIMINE_KEY "maximize" +#define NAME_KEY "nameCn" + +NotificationDbus::NotificationDbus(NotificationPlugin *parent) +{ + m_parent = parent; + getSettingsValue(); + + //注册dbus + QDBusConnection::sessionBus().unregisterService("org.ukui.Sidebar"); + QDBusConnection::sessionBus().registerService("org.ukui.Sidebar"); + //注册对象路径,导出所有此对象的插槽 + //registerObject参数:路径,interface,对象,options + QDBusConnection::sessionBus().registerObject("/org/ukui/Sidebar/notification",this, + QDBusConnection::ExportAllSlots|QDBusConnection::ExportAllSignals); + + //将消息添加到通知中心或收纳盒 + connect(this, SIGNAL(Sig_Notify(QString, QString, QString, QString, QString, QString, QDateTime, int, bool)), + m_parent, SLOT(onAddSingleNotify(QString, QString, QString, QString, QString, QString, QDateTime, int, bool))); + + connect(this, SIGNAL(Sig_Takein(QString, QString, QString, QString, QString, QString, QDateTime, int, bool)), + m_parent, SLOT(onTakeInSingleNotify(QString, QString, QString, QString, QString, QString, QDateTime, int, bool))); + + //配置实时关闭通知消息 + connect(this, SIGNAL(Sig_CloseAppMsg(QString)), m_parent, SLOT(onCloseAppMsg(QString))); + //配置实时更新通知消息最大数 + connect(this, SIGNAL(Sig_UpdateAppMaxNum(QString, int)), m_parent, SLOT(onUpdateAppMaxNum(QString, int))); +} + +//创建一条侧边栏通知 +void NotificationDbus::sidebarNotification(const QString &appName, const QString &appIcon, + const QString &summary, const QString &body, + const QString &urlStr, const QString &actions) +{ + qInfo()<<"--------------->"<::const_iterator iter = m_nAppMaxNum.find(appName); + int nMaxNum = 3; + if ((iter != m_nAppMaxNum.end()) && (iter.value() > 0)) { //找到 + nMaxNum = iter.value(); + } + + QDateTime dateTime(QDateTime::currentDateTime()); + QMap::const_iterator iter1 = m_mapAppSwitch.find(appName); + if (iter1 == m_mapAppSwitch.end()) { //未找到 + emit Sig_Notify(appName, appIcon, summary, body, urlStr, actions, dateTime, nMaxNum, true); + } else { + emit Sig_Takein(appName, appIcon, summary, body, urlStr, actions, dateTime, nMaxNum, true); + } +} + +void NotificationDbus::proxyNotificationJump(const QString &urlStr) +{ + if(!urlStr.isEmpty()){ + QString cmd = QString("xdg-open ") + urlStr; + qInfo()<<"proxy Jump Url:"<start(cmd); + } +} + +//获取路径并创建gsetting +void NotificationDbus::getSettingsValue() +{ + QList existsPath = listExistsPath(); + for (char* path : existsPath) { + char* prepath = QString(NOTICE_ORIGIN_PATH).toLatin1().data(); + char* allpath = strcat(prepath, path); + + const QByteArray ba(NOTICE_ORIGIN_SCHEMA); + const QByteArray bba(allpath); + m_pSettings = new QGSettings(ba, bba, this); + fromSettingsGetInfoToList(); + //监听setting的状态和最大数目改变 + connect(m_pSettings, SIGNAL(changed(const QString &)),this,SLOT(appNotifySettingChangedSlot())); + } +} + +void NotificationDbus::fromSettingsGetInfoToList() +{ + //存储settings,应用名和最大显示数目,以及true + if (false == m_pSettings->keys().contains(NAME_KEY)) { + return; + } + QString strAppName = m_pSettings->get(NAME_KEY).toString(); + + if (m_pSettings->keys().contains(MAXIMINE_KEY)) { + int maxNum = m_pSettings->get(MAXIMINE_KEY).toInt(); + m_nAppMaxNum.insert(strAppName, maxNum); + } + if (m_pSettings->keys().contains(SWITCH_KEY)) { + powerstatus = m_pSettings->get(SWITCH_KEY).toBool(); + if (false == powerstatus) { + m_mapAppSwitch.insert(strAppName, powerstatus); + } + } +} + +void NotificationDbus::appNotifySettingChangedSlot() +{ + int maxNum = 0; + QString strAppName = ""; + bool status = false; + + if (false == m_pSettings->keys().contains(NAME_KEY)) { + return; + } + + strAppName = m_pSettings->get(NAME_KEY).toString(); + if (m_pSettings->keys().contains(MAXIMINE_KEY)) { + maxNum = m_pSettings->get(MAXIMINE_KEY).toInt(); + m_nAppMaxNum[strAppName] = maxNum; + emit Sig_UpdateAppMaxNum(strAppName, maxNum); + } + + if (m_pSettings->keys().contains(SWITCH_KEY)) { + status = m_pSettings->get(SWITCH_KEY).toBool(); + powerstatus= m_pSettings->get(SWITCH_KEY).toBool(); + QMap::const_iterator iter1 = m_mapAppSwitch.find(strAppName); + if (iter1 == m_mapAppSwitch.end()) { //没找到,没在黑名单 + if(false == status) { + m_mapAppSwitch.insert(strAppName, status); + emit Sig_CloseAppMsg(strAppName); //对于没在黑名单的,新增黑名单关闭消息要求实时更新至通知列表 + } + } else { + if (true == status) { + m_mapAppSwitch.remove(strAppName); + } + } + } +} + +//列出存在的路径 +QList NotificationDbus::listExistsPath() +{ + char** childs; + int len; + + DConfClient * client = dconf_client_new(); + childs = dconf_client_list(client, NOTICE_ORIGIN_PATH, &len); + g_object_unref(client); + + QList vals; + + for (int i = 0; childs[i] != NULL; i++) { + if (dconf_is_rel_dir(childs[i], NULL)) { + char* val = g_strdup(childs[i]); + vals.append(val); + } + } + g_strfreev(childs); + return vals; +} + diff --git a/src/plugins/ukui-sidebar-notification/notificationDbus.h b/src/plugins/ukui-sidebar-notification/notificationDbus.h new file mode 100644 index 0000000..e8d6af0 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/notificationDbus.h @@ -0,0 +1,71 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include + +#define DBUS_INTERFACE "org.ukui.Sidebar.notification" + +class NotificationPlugin; + +class NotificationDbus : public QObject +{ + Q_OBJECT + //申明该类有D-BUS服务接口 + Q_CLASSINFO("D-Bus Interface", "org.ukui.Sidebar.notification") + +public: + NotificationDbus(NotificationPlugin *parent); + void getSettingsValue(); + void fromSettingsGetInfoToList(); + void appNotifySettingChangedSlot(); + QList listExistsPath(); + +signals: + void Sig_Notify(QString appName, QString appIcon, + QString summary, QString body, + QString urlStr, QString actions, + QDateTime dateTime, int nMaxNum, bool flag); + void Sig_Takein(QString appName, QString appIcon, + QString summary, QString body, + QString urlStr, QString actions, + QDateTime dateTime, int nMaxNum, bool flag); + void Sig_CloseAppMsg(QString strAppName); + void Sig_UpdateAppMaxNum(QString strAppName, int maxNum); +public slots: + void sidebarNotification(const QString &appName,const QString &appIcon, + const QString &summary,const QString &body, + const QString &urlStr, const QString &actions); //创建一条侧边栏通知 + void proxyNotificationJump(const QString &urlStr); //代理通知中心的跳转动作 + +public: + bool powerstatus = true; + +private: + NotificationPlugin* m_parent; //传一个插件对象指针,用来回传槽函数 + QGSettings* m_pSettings; + QMap m_nAppMaxNum; + QMap m_mapAppSwitch; +}; + +#endif // NOTIFICATIONDBUS_H diff --git a/src/plugins/ukui-sidebar-notification/notificationPlugin.cpp b/src/plugins/ukui-sidebar-notification/notificationPlugin.cpp new file mode 100644 index 0000000..bd8f3e9 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/notificationPlugin.cpp @@ -0,0 +1,746 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include "customstylePushbutton2.h" +#include "notificationDbus.h" + + +NotificationPlugin::NotificationPlugin() +{ + //初始化翻译文件 + initTrans(); + + //初始化任务栏gsetting,用以监听任务栏的位置变化 + initPanelGsettings(); + + //初始化界面 + initUI(); + + +// //新建一个监控dbus消息的线程 +// MonitorThread* pMonitorThread = new MonitorThread(this); +// QGSettings* pEnablenotice = new QGSettings("org.ukui.control-center.notice", "", this); +// if(pEnablenotice->get("enable-notice").toBool()) { +// pMonitorThread->start(); +// pMonitorThread->switchEnable(pEnablenotice->get("enable-notice").toBool()); +// } + +// connect(pEnablenotice, &QGSettings::changed, [=](){ +// pMonitorThread->switchEnable(pEnablenotice->get("enable-notice").toBool()); +// }); + + //注册dbus接口,接收通知中心发送的通知信息 + NotificationDbus *notifyDbus = new NotificationDbus(this); + + + connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &NotificationPlugin::onResolutionChanged); + connect(QApplication::primaryScreen(), &QScreen::virtualGeometryChanged, this, &NotificationPlugin::onResolutionChanged); + + + return; +} + + +QWidget* NotificationPlugin::centerWidget() +{ + return m_pMainWidget; +} + +void NotificationPlugin::initTrans() +{ + QTranslator *translator = new QTranslator; + if (translator->load(QLocale(), QLatin1String("ukui-sidebar-notification"), QLatin1String("_"), QLatin1String("/usr/share/ukui-sidebar/ukui-sidebar-notification"))) + QApplication::installTranslator(translator); + else + qDebug() << "cannot load translator ukui-sidebar-notification_" << QLocale::system().name() << ".qm!"; +} + +void NotificationPlugin::initUI() +{ + m_pMainWidget = new QWidget; + m_pMainWidget->setObjectName("NotificationCenter"); + + //消息通知模块总VBoxLayout布局器 + QVBoxLayout* pNotificationVBoxLayout = new QVBoxLayout; + pNotificationVBoxLayout->setContentsMargins(10,21,0,0); + pNotificationVBoxLayout->setSpacing(0); + + //装第一行通知中心的Widget + QWidget* pWidget1= new QWidget; + pWidget1->setObjectName("NotificationName"); + pWidget1->setAttribute(Qt::WA_TranslucentBackground); + + //第一行通知中心标题栏,左侧-标题通知中心,右侧-收纳按钮 + QHBoxLayout* pQHBoxLayout1 = new QHBoxLayout; + pQHBoxLayout1->setContentsMargins(11,0,28,0); + pQHBoxLayout1->setSpacing(0); + + //标题-通知中心 + QLabel* pLabel = new QLabel(QObject::tr("Notification center")); + pLabel->setObjectName("notificationcentername"); + pLabel->setAttribute(Qt::WA_TranslucentBackground); + + //收纳按钮 + m_pTakeInBoxToolButton = new TakeInBoxToolButton(); + m_pTakeInBoxToolButton->setStyle(new CustomStyle_pushbutton_2("ukui-default")); + m_pTakeInBoxToolButton->setFocusPolicy(Qt::NoFocus); + connect(m_pTakeInBoxToolButton, SIGNAL(Sig_clicked()), this, SLOT(onShowTakeInMessage())); + + m_pTakeInBoxToolButton->setFixedSize(30,30); + m_pTakeInBoxToolButton->setIconSize(QSize(24,24)); + m_pTakeInBoxToolButton->setIcon(QIcon(":/images/box-24.svg")); + + pQHBoxLayout1->addWidget(pLabel, 0, Qt::AlignLeft); + pQHBoxLayout1->addWidget(m_pTakeInBoxToolButton, 0, Qt::AlignRight); + pWidget1->setLayout(pQHBoxLayout1); + pNotificationVBoxLayout->addWidget(pWidget1); + + //悬浮收纳数标签 + m_pTakeInCoutLabel = new TakeInCoutLabel(m_pMainWidget); + m_pTakeInCoutLabel->setObjectName("takeincout"); + m_pTakeInCoutLabel->setFixedSize(23,23); + + QPalette pe1; + pe1.setColor(QPalette::WindowText,Qt::black); + m_pTakeInCoutLabel->setPalette(pe1); + m_pTakeInCoutLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + m_pTakeInCoutLabel->setVisible(false); + + //添加24px的间距 + QSpacerItem* pVFixedSpacer = new QSpacerItem(10, 24, QSizePolicy::Fixed, QSizePolicy::Fixed); + pNotificationVBoxLayout->addSpacerItem(pVFixedSpacer); + + //装第二行重要通知中的Widget + QWidget* pWidget2= new QWidget; + pWidget2->setFixedWidth(390); + + //第二行左侧标签“重要的信息”,右侧一个清空按钮,一个设置按钮 + QHBoxLayout* pQHBoxLayout2 = new QHBoxLayout; + pQHBoxLayout2->setContentsMargins(12,0,10,8); + + //标签-重要的信息 + m_pNotificationLabel = new QLabel(QObject::tr("Important notice")); + m_pNotificationLabel->setObjectName("importantnotification"); + m_pNotificationLabel->setAttribute(Qt::WA_TranslucentBackground); + + //清空按钮 + m_pClearAllToolButton = new QPushButton(); + m_pClearAllToolButton->setObjectName("clearall"); + connect(m_pClearAllToolButton, SIGNAL(clicked()), this, SLOT(onClearAllMessage())); + m_pClearAllToolButton->setText(QObject::tr("Clean up")); + m_pClearAllToolButton->setStyle(new CustomStyle_pushbutton_2("ukui-default")); + m_pClearAllToolButton->setVisible(false); + + //设置按钮 + QPushButton* pSettingToolButton = new QPushButton(); + pSettingToolButton->setObjectName("setting"); + connect(pSettingToolButton, SIGNAL(clicked()), this, SLOT(onCallControlPanel())); + pSettingToolButton->setText(QObject::tr("Set up")); + pSettingToolButton->setStyle(new CustomStyle_pushbutton_2("ukui-default")); + + //布局 + QSpacerItem* pFixSpacer = new QSpacerItem(5, 10, QSizePolicy::Fixed, QSizePolicy::Fixed); + QSpacerItem* pHSpacer = new QSpacerItem(300, 10, QSizePolicy::Expanding, QSizePolicy::Fixed); + pQHBoxLayout2->addWidget(m_pNotificationLabel, 0, Qt::AlignLeft); + pQHBoxLayout2->addSpacerItem(pHSpacer); + pQHBoxLayout2->addWidget(m_pClearAllToolButton, 0, Qt::AlignRight); + pQHBoxLayout2->addSpacerItem(pFixSpacer); + pQHBoxLayout2->addWidget(pSettingToolButton, 0, Qt::AlignRight); + pWidget2->setLayout(pQHBoxLayout2); + pNotificationVBoxLayout->addWidget(pWidget2, 0); + + //消息列表widget + m_pMsgListWidget = new QWidget; + pNotificationVBoxLayout->addWidget(m_pMsgListWidget, 1); + m_pMsgListWidget->setParent(m_pMainWidget); + + + //消息列表部件,用于装两个消息列表的,浮动在m_pMsgListWidget里面 + m_pMsgDoubleListWidget = new QWidget(m_pMsgListWidget); + QHBoxLayout* pMsgDoubleListHBoxLayout = new QHBoxLayout; + pMsgDoubleListHBoxLayout->setContentsMargins(0, 0, 0, 0); + pMsgDoubleListHBoxLayout->setSpacing(0); + m_pMsgDoubleListWidget->setLayout(pMsgDoubleListHBoxLayout); + m_pMsgDoubleListWidget->setAttribute(Qt::WA_TranslucentBackground); + + //双列表部件切换动画 + m_pSwitchAnimation = new QPropertyAnimation(m_pMsgDoubleListWidget, "geometry", this); + m_pSwitchAnimation->setDuration(300); + connect(m_pSwitchAnimation, SIGNAL(finished()), this, SLOT(onSwitchMsgBoxFinish())); + + //通知列表 + m_pQScrollAreaNotify = new ScrollAreaWidget(); + m_pQScrollAreaNotify->setAttribute(Qt::WA_TranslucentBackground); + m_pQScrollAreaNotify->setStyleSheet("QScrollArea {background-color:transparent;}"); + m_pQScrollAreaNotify->viewport()->setStyleSheet("background-color:transparent;"); + m_pQScrollAreaNotify->setFrameShape(QFrame::NoFrame); + m_pQScrollAreaNotify->setFixedWidth(390); + m_pScrollAreaNotifyVBoxLayout = new QVBoxLayout(); + m_pScrollAreaNotifyVBoxLayout->setContentsMargins(0, 0, 0, 0); + m_pScrollAreaNotifyVBoxLayout->setSpacing(6); + + //通知列表的最内层部件 + QWidget* pInQWidget = new QWidget(); + pInQWidget->setObjectName("QScrollAreaInQWidget"); + pInQWidget->setLayout(m_pScrollAreaNotifyVBoxLayout); + pInQWidget->setAttribute(Qt::WA_TranslucentBackground); + m_pQScrollAreaNotify->setWidget(pInQWidget); + m_pMessageCenterLabel = new QLabel(QObject::tr("No new notifications")); + m_pMessageCenterLabel->setStyleSheet("background:transparent"); + m_pScrollAreaNotifyVBoxLayout->addWidget(m_pMessageCenterLabel, 4, Qt::AlignCenter); + m_pMessageCenterLabel->setAttribute(Qt::WA_TranslucentBackground); + QSpacerItem* pVSpacer = new QSpacerItem(10, 1, QSizePolicy::Fixed, QSizePolicy::Expanding); + m_pScrollAreaNotifyVBoxLayout->addSpacerItem(pVSpacer); + pMsgDoubleListHBoxLayout->addWidget(m_pQScrollAreaNotify, 0); + + //收纳列表 + m_pQScrollAreaTakeIn = new ScrollAreaWidget(); + m_pQScrollAreaTakeIn->setAttribute(Qt::WA_TranslucentBackground); + m_pQScrollAreaTakeIn->setStyleSheet("QScrollArea {background-color:transparent;}"); + m_pQScrollAreaTakeIn->viewport()->setStyleSheet("background-color:transparent;"); + m_pQScrollAreaTakeIn->setFrameShape(QFrame::NoFrame); + m_pQScrollAreaTakeIn->setFixedWidth(390); + + m_pScrollAreaTakeInVBoxLayout = new QVBoxLayout(); + m_pScrollAreaTakeInVBoxLayout->setContentsMargins(0,0,0,0); + m_pScrollAreaTakeInVBoxLayout->setSpacing(0); + + //收纳列表的最内层部件 + QWidget* pTakeInQWidget = new QWidget(); + pTakeInQWidget->setObjectName("QScrollAreaInQWidget"); + pTakeInQWidget->setLayout(m_pScrollAreaTakeInVBoxLayout); + pTakeInQWidget->setAttribute(Qt::WA_TranslucentBackground); + m_pQScrollAreaTakeIn->setWidget(pTakeInQWidget); + m_pTakeinMessageCenterLabel = new QLabel(QObject::tr("No unimportant notice")); + m_pTakeinMessageCenterLabel->setAttribute(Qt::WA_TranslucentBackground); + + m_pScrollAreaTakeInVBoxLayout->addWidget(m_pTakeinMessageCenterLabel, 4, Qt::AlignCenter); + QSpacerItem* pVSpacer2 = new QSpacerItem(10, 1, QSizePolicy::Fixed, QSizePolicy::Expanding); + m_pScrollAreaTakeInVBoxLayout->addSpacerItem(pVSpacer2); + pMsgDoubleListHBoxLayout->addWidget(m_pQScrollAreaTakeIn, 0); + + //通知中心最底部固定9px的空白 + QSpacerItem* pVBottomSpacer = new QSpacerItem(9, 9, QSizePolicy::Fixed, QSizePolicy::Fixed); + pNotificationVBoxLayout->addSpacerItem(pVBottomSpacer); + m_pMainWidget->setLayout(pNotificationVBoxLayout); + +} + +void NotificationPlugin::onResolutionChanged() +{ + //获取屏幕高度 + QRect screenRect = QGuiApplication::primaryScreen()->geometry(); + + //如果任务栏是在上或下时减去任务栏高度 + if (getPanelSite() == 0 || getPanelSite() == 1) { + m_pMsgListWidget->setFixedHeight(screenRect.height() - getTaskBarHeight() - TITLE_HEIGHT - CLIPBOARD_HEIGHT); + } else { + m_pMsgListWidget->setFixedHeight(screenRect.height() - TITLE_HEIGHT - CLIPBOARD_HEIGHT); + } + + qDebug()<<"消息通知的监听屏幕分辨率&&任务栏的位置改变,刷新消息通知区域大小"; + qDebug()<<"消息通知区域大小:"<< m_pMsgListWidget->height() << m_pMsgListWidget->width(); + m_pMsgDoubleListWidget->setGeometry(0, 0, m_pMsgListWidget->width()*2, m_pMsgListWidget->height()); + m_pMsgDoubleListWidget->update(); +} + +void NotificationPlugin::initPanelGsettings() +{ + /* 链接任务栏gsetting接口 */ + if(QGSettings::isSchemaInstalled(UKUI_PANEL_SETTING)){ + m_pPanelSetting = new QGSettings(UKUI_PANEL_SETTING); + if (m_pPanelSetting != nullptr) { + connect(m_pPanelSetting, &QGSettings::changed, this, [=](QString value) { + if (value == "panelposition") { + onResolutionChanged(); + } + }); + } + } +} + +//获取任务栏状态位置下上左右 +int NotificationPlugin::getPanelSite() +{ + int panelPosition = 0; + /* 链接任务栏Dbus接口,获取任务栏高度和位置 */ + QDBusInterface* serviceInterface = new QDBusInterface(PANEL_DBUS_SERVICE, PANEL_DBUS_PATH, PANEL_DBUS_INTERFACE, QDBusConnection::sessionBus()); + + /* 获取任务栏位置信息 */ + if(QGSettings::isSchemaInstalled(UKUI_PANEL_SETTING)){ + if (m_pPanelSetting != nullptr) { + QStringList keys = m_pPanelSetting->keys(); + if (keys.contains("panelposition")) { + panelPosition = m_pPanelSetting->get("panelposition").toInt(); + } + } else { + QDBusMessage msg = serviceInterface->call("GetPanelPosition", QVariant("Site")); + panelPosition = msg.arguments().at(0).toInt(); + } + } + serviceInterface->deleteLater(); + + return panelPosition; +} + +//链接任务栏dbus获取高度的接口 +int NotificationPlugin::getTaskBarHeight() +{ + int panelHeight = 0; + /* 链接任务栏Dbus接口,获取任务栏高度和位置 */ + QDBusInterface* serviceInterface = new QDBusInterface(PANEL_DBUS_SERVICE, PANEL_DBUS_PATH, PANEL_DBUS_INTERFACE, QDBusConnection::sessionBus()); + + + /* 获取任务栏的高度信息 */ + if(QGSettings::isSchemaInstalled(UKUI_PANEL_SETTING)){ + if (m_pPanelSetting != nullptr) { + QStringList keys = m_pPanelSetting->keys(); + if (keys.contains("panelsize")) { + panelHeight = m_pPanelSetting->get("panelsize").toInt(); + } + } else { + QDBusMessage msg = serviceInterface->call("GetPanelSize", QVariant("Hight")); + panelHeight = msg.arguments().at(0).toInt(); + return panelHeight; + } + } + serviceInterface->deleteLater(); + + return panelHeight; +} + +void NotificationPlugin::showNotification() +{ + if (false == m_bInitialFlag) { + m_bInitialFlag = true; + qDebug()<<"消息通知区域大小:"<height() <width(); + m_pMsgDoubleListWidget->setGeometry(0, 0, m_pMsgListWidget->width()*2, m_pMsgListWidget->height()); + } + //上面不需要判断,因为在隐藏时,已经切换至通知中心,m_bShowTakeIn为false + for (int i = 0; i < m_listAppMsg.count(); i++) { + AppMsg* pAppMsg = m_listAppMsg.at(i); + pAppMsg->updateAppPushTime(); + } +} + +void NotificationPlugin::hideNotification() +{ + //侧边栏隐藏时,如果已经显示收纳盒,则切换至通知列表 + if (true == m_bShowTakeIn) { + onShowTakeInMessage(); + } + + //隐藏时,因为上面已切换至通知列表,所以只需将通知列表都折叠即可 + for (int i = 0; i < m_listAppMsg.count(); i++) { + AppMsg* pAppMsg = m_listAppMsg.at(i); + pAppMsg->setAppFold(); + } + +} + +AppMsg* NotificationPlugin::getAppMsgAndIndexByName(QString strAppName, int& nIndex) +{ + AppMsg* pAppMsg = NULL; + for (int i = 0; i < m_listAppMsg.count(); i++) { + AppMsg* pTmpAppMsg = m_listAppMsg.at(i); + if (strAppName == pTmpAppMsg->getAppName()) { + pAppMsg = pTmpAppMsg; + nIndex = i; + break; + } + } + return pAppMsg; +} + +uint NotificationPlugin::onAddSingleNotify(QString strAppName, QString strIconPath, QString strSummary, + QString strBody, QString urlStr, QString actions, + QDateTime dateTime, int maxNum, bool bNewNotificationFlag) +{ + qInfo()<<"------------->NotificationPlugin:"<count()) { + m_pScrollAreaNotifyVBoxLayout->removeWidget(m_pMessageCenterLabel); + m_pMessageCenterLabel->setVisible(false); + m_pClearAllToolButton->setVisible(true); + } + + int nIndex = -1; + //通过查找m_listAppMsg列表看该app是否已存在 + AppMsg* pAppMsg = getAppMsgAndIndexByName(strAppName, nIndex); + + //如果不存在,则新建一个AppMsg消息,并且直接置顶 + if (NULL == pAppMsg) { + pAppMsg = new AppMsg(this, strAppName); + } else { + m_listAppMsg.removeAt(nIndex); + m_pScrollAreaNotifyVBoxLayout->removeWidget(pAppMsg); + } + + if (true == bNewNotificationFlag) { +// pAppMsg->setMaxNumMsg(maxNum); + } + + //在strAppName对应的AppMsg中添加单条信息 + if(pAppMsg->getSingleMsgCount() < maxNum){ + pAppMsg->addSingleMsg(strIconPath, strSummary, dateTime, strBody, urlStr, actions); + } + else{ + pAppMsg->deleteExceedingMsg(); + pAppMsg->addSingleMsg(strIconPath, strSummary, dateTime, strBody, urlStr, actions); + } + + int uIndex = m_listAppMsg.count(); + for (int i = m_listAppMsg.count() - 1; i >= 0; i--) { + AppMsg* pTmpAppMsg = m_listAppMsg.at(i); + if (pAppMsg->getAppPushTime() < pTmpAppMsg->getAppPushTime()) { + break; + } + uIndex = i; + } + + m_listAppMsg.insert(uIndex, pAppMsg); + m_pScrollAreaNotifyVBoxLayout->insertWidget(uIndex, pAppMsg); + + //如果是新通知,有必要对通知列表更新推送时间;如果是恢复,说明在收纳盒中,所以更新收纳盒中的推送时间 + if (true == bNewNotificationFlag) { + for (int i = 0; i < m_listAppMsg.count(); i++) { + AppMsg* pTmpAppMsg = m_listAppMsg.at(i); + pTmpAppMsg->updateAppPushTime(); + } + } else { + for (int i = 0; i < m_listTakeInAppMsg.count(); i++) { + AppMsg* pTmpAppMsg = m_listTakeInAppMsg.at(i); + pTmpAppMsg->updateAppPushTime(); + } + } + return 1; +} + +void NotificationPlugin::onCountTakeInBitAndUpate() //统计收纳位数并更新至右上角提示 +{ + int nCount = 0; + for (int i = 0; i < m_listTakeInAppMsg.count(); i++) { + AppMsg* pTmpAppMsg = m_listTakeInAppMsg.at(i); + nCount = nCount + pTmpAppMsg->getSingleMsgCount(); + } + + QString strCount = QString::number(nCount); + + //收纳数的位数 + int nBit = 1; + if (nCount > 999) { + nBit = 3; + strCount = "..."; + } else { + while (nCount >= 10) { + nCount = nCount / 10; + nBit++; + } + } + + m_pTakeInCoutLabel->setGeometry(361, 21, (6 + 6 * nBit), 12); + m_pTakeInCoutLabel->setText(strCount); + if (false == m_bShowTakeIn) { + m_pTakeInCoutLabel->setVisible(true); + } + return; +} + +void NotificationPlugin::onClearAppMsg(AppMsg* pAppMsg) +{ + int nIndex = m_listAppMsg.indexOf(pAppMsg); + if (-1 == nIndex) { + qDebug()<<"NotificationPlugin::onClearAppMsg 在通知链表中未找到pSingleMsg指针"; + return; + } + + m_listAppMsg.removeAt(nIndex); + m_pScrollAreaNotifyVBoxLayout->removeWidget(pAppMsg); + pAppMsg->deleteLater(); + + if (0 == m_listAppMsg.count() && 1 == m_pScrollAreaNotifyVBoxLayout->count()) { + m_pMessageCenterLabel->setVisible(true); + m_pScrollAreaNotifyVBoxLayout->insertWidget(0, m_pMessageCenterLabel, 4, Qt::AlignHCenter); + m_pClearAllToolButton->setVisible(false); + } + + return; +} + +void NotificationPlugin::onClearAllMessage() +{ + //当展示通知列表时 + if (false == m_bShowTakeIn) { + while (m_listAppMsg.count() > 0) { + AppMsg* pSingleMsg = m_listAppMsg.at(0); + m_pScrollAreaNotifyVBoxLayout->removeWidget(pSingleMsg); + pSingleMsg->deleteLater(); + m_listAppMsg.removeAt(0); + } + + if (1 == m_pScrollAreaNotifyVBoxLayout->count()) { + m_pMessageCenterLabel->setVisible(true); + m_pScrollAreaNotifyVBoxLayout->insertWidget(0, m_pMessageCenterLabel, 4, Qt::AlignHCenter); + m_pClearAllToolButton->setVisible(false); + } + } else { + while (m_listTakeInAppMsg.count() > 0) { + AppMsg* pSingleMsg = m_listTakeInAppMsg.at(0); + m_pScrollAreaTakeInVBoxLayout->removeWidget(pSingleMsg); + pSingleMsg->deleteLater(); + m_listTakeInAppMsg.removeAt(0); + } + + if (1 == m_pScrollAreaTakeInVBoxLayout->count()) { + m_pTakeinMessageCenterLabel->setVisible(true); + m_pScrollAreaTakeInVBoxLayout->insertWidget(0, m_pTakeinMessageCenterLabel, 4, Qt::AlignHCenter); + m_pClearAllToolButton->setVisible(false); + } + onCountTakeInBitAndUpate(); + } + return; +} + +//配置实时关闭通知消息和收纳消息 +void NotificationPlugin::onCloseAppMsg(QString strAppName) +{ + int nIndex = -1; + AppMsg* pAppMsg = getAppMsgAndIndexByName(strAppName, nIndex); + if (NULL != pAppMsg) { + onClearAppMsg(pAppMsg); + } + + //通过查找m_listTakeInAppMsg列表看该app是否已存在 + //AppMsg* pTakeinAppMsg = getTakeinAppMsgAndIndexByName(strAppName, nIndex); + //if(NULL != pTakeinAppMsg) + //{ + // onClearTakeInAppMsg(pTakeinAppMsg); + //} +} + +//配置实时更新通知消息最大数 +void NotificationPlugin::onUpdateAppMaxNum(QString strAppName, int maxNum) +{ + int nIndex = -1; + AppMsg* pAppMsg = getAppMsgAndIndexByName(strAppName, nIndex); + if (NULL != pAppMsg) { +// pAppMsg->setMaxNumMsg(maxNum); + pAppMsg->deleteExceedingMsg(); + } + + //通过查找m_listTakeInAppMsg列表看该app是否已存在 + AppMsg* pTakeinAppMsg = getTakeinAppMsgAndIndexByName(strAppName, nIndex); + if (NULL != pTakeinAppMsg) { + pTakeinAppMsg->setMaxNumMsg(maxNum); + pTakeinAppMsg->deleteExceedingMsg(); + } +} + +AppMsg* NotificationPlugin::getTakeinAppMsgAndIndexByName(QString strAppName, int& nIndex) +{ + AppMsg* pAppMsg = NULL; + for (int i = 0; i < m_listTakeInAppMsg.count(); i++) { + AppMsg* pTmpAppMsg = m_listTakeInAppMsg.at(i); + if (strAppName == pTmpAppMsg->getAppName()) { + pAppMsg = pTmpAppMsg; + nIndex = i; + break; + } + } + return pAppMsg; +} + +void NotificationPlugin::onTakeInSingleNotify(QString strAppName, QString strIcon, QString strSummary, QString strBody, QString urlStr, QString actions, QDateTime dateTime, int maxNum, bool bNewTakeinFlag) +{ + //当列表信息为空表明第一次来通知,列表个数为2,一个表面是“没有新通知标签”,一个是底部弹簧 + if (0 == m_listTakeInAppMsg.count() && 2 == m_pScrollAreaTakeInVBoxLayout->count()) { + m_pScrollAreaTakeInVBoxLayout->removeWidget(m_pTakeinMessageCenterLabel); + m_pTakeinMessageCenterLabel->setVisible(false); + m_pClearAllToolButton->setVisible(true); + } + + int nIndex = -1; + //通过查找m_listTakeInAppMsg列表看该app是否已存在 + AppMsg* pAppMsg = getTakeinAppMsgAndIndexByName(strAppName, nIndex); + //如果不存在,则新建一个AppMsg消息 + if (NULL == pAppMsg) { + pAppMsg = new AppMsg(this, strAppName, true); + } else { + //如果找到该收纳应用,则先移除,后面根据时间插入 + m_listTakeInAppMsg.removeAt(nIndex); + m_pScrollAreaTakeInVBoxLayout->removeWidget(pAppMsg); + } + + if (true == bNewTakeinFlag) { + pAppMsg->setMaxNumMsg(maxNum); + } + pAppMsg->addSingleMsg(strIcon, strSummary, dateTime, strBody, urlStr, actions); + + + int uIndex = m_listTakeInAppMsg.count(); + for (int i = m_listTakeInAppMsg.count() - 1; i >= 0; i--) { + AppMsg* pTmpAppMsg = m_listTakeInAppMsg.at(i); + if (pAppMsg->getAppPushTime() < pTmpAppMsg->getAppPushTime()) { + break; + } + uIndex = i; + } + + m_listTakeInAppMsg.insert(uIndex, pAppMsg); + m_pScrollAreaTakeInVBoxLayout->insertWidget(uIndex, pAppMsg); + + //收纳的时候没必要对收纳列表更新,可以对通知列表更新时间,反正点击进入收纳盒时,会更新收纳列表 + for (int i = 0; i < m_listAppMsg.count(); i++) { + AppMsg* pTmpAppMsg = m_listAppMsg.at(i); + pTmpAppMsg->updateAppPushTime(); + } + onCountTakeInBitAndUpate(); + return; +} + +//处理删除收纳应用的槽函数 +void NotificationPlugin::onClearTakeInAppMsg(AppMsg* pAppMsg) +{ + int nIndex = m_listTakeInAppMsg.indexOf(pAppMsg); + if (-1 == nIndex) { + qDebug()<<"NotificationPlugin::onClearTakeInAppMsg 在收纳链表中未找到pSingleMsg指针"; + return; + } + + m_listTakeInAppMsg.removeAt(nIndex); + m_pScrollAreaTakeInVBoxLayout->removeWidget(pAppMsg); + pAppMsg->deleteLater(); + + onCountTakeInBitAndUpate(); + + if (0 == m_listTakeInAppMsg.count() && 1 == m_pScrollAreaTakeInVBoxLayout->count()) { + m_pTakeinMessageCenterLabel->setVisible(true); + m_pScrollAreaTakeInVBoxLayout->insertWidget(0, m_pTakeinMessageCenterLabel, 4, Qt::AlignHCenter); + m_pClearAllToolButton->setVisible(false); + } + return; +} + +void NotificationPlugin::onCallControlPanel() +{ + QProcess p(0); + p.startDetached("ukui-control-center -m Notice"); + p.waitForStarted(); + return; +} + +void NotificationPlugin::onShowTakeInMessage() +{ + if (false == m_bShowTakeIn) { + m_pSwitchAnimation->setStartValue(QRect(0, 0, m_pMsgListWidget->width()*2, m_pMsgListWidget->height())); + m_pSwitchAnimation->setEndValue(QRect(0 - m_pMsgListWidget->width(), 0, m_pMsgListWidget->width()*2, m_pMsgListWidget->height())); + m_pSwitchAnimation->start(); + } else { + m_pSwitchAnimation->setStartValue(QRect(0 - m_pMsgListWidget->width(), 0, m_pMsgListWidget->width()*2, m_pMsgListWidget->height())); + m_pSwitchAnimation->setEndValue(QRect(0, 0, m_pMsgListWidget->width()*2, m_pMsgListWidget->height())); + m_pSwitchAnimation->start(); + } +} + +//收纳盒按钮切换动画完成后处理 +void NotificationPlugin::onSwitchMsgBoxFinish() +{ + if (false == m_bShowTakeIn) { + m_bShowTakeIn = true; + m_pNotificationLabel->setText(QObject::tr("Unimportant notice")); + if(m_pTakeinMessageCenterLabel->isVisible()) { + m_pClearAllToolButton->setVisible(false); + } else { + m_pClearAllToolButton->setVisible(true); + } + m_pTakeInBoxToolButton->setIcon(QIcon(":/images/exitbox-24.svg")); + m_pTakeInBoxToolButton->setEnterFlags(m_bShowTakeIn); + m_pTakeInCoutLabel->setVisible(false); + + //当切换至收纳盒时,先将各个收纳应用更新下时间 + for (int i = 0; i < m_listTakeInAppMsg.count(); i++) { + AppMsg* pAppMsg = m_listTakeInAppMsg.at(i); + pAppMsg->updateAppPushTime(); + } + + //再将各个通知应用折叠起来 + for (int i = 0; i < m_listAppMsg.count(); i++) { + AppMsg* pAppMsg = m_listAppMsg.at(i); + pAppMsg->setAppFold(); + } + } else { + m_bShowTakeIn = false; + m_pNotificationLabel->setText(QObject::tr("Important notice")); + if(m_pMessageCenterLabel->isVisible()) { + m_pClearAllToolButton->setVisible(false); + } else { + m_pClearAllToolButton->setVisible(true); + } + + m_pTakeInBoxToolButton->setIcon(QIcon(":/images/box-24.svg")); + m_pTakeInBoxToolButton->setEnterFlags(m_bShowTakeIn); + + if (m_listTakeInAppMsg.count() > 0) { + m_pTakeInCoutLabel->setVisible(true); + } + + //当切换至通知列表时,先将各个通知应用更新下时间 + for (int i = 0; i < m_listAppMsg.count(); i++) { + AppMsg* pAppMsg = m_listAppMsg.at(i); + pAppMsg->updateAppPushTime(); + } + + //再将各个收纳应用折叠起来 + for (int i = 0; i < m_listTakeInAppMsg.count(); i++) { + AppMsg* pAppMsg = m_listTakeInAppMsg.at(i); + pAppMsg->setAppFold(); + } + } +} + +TakeInCoutLabel::TakeInCoutLabel(QWidget *parent) : QLabel(parent) +{ + +} + + +void TakeInCoutLabel::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + QRect rect = this->rect(); + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.setBrush(QBrush(QColor(255,255,255))); + p.setOpacity(0.7); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect,20,20); + QLabel::paintEvent(e); +} + diff --git a/src/plugins/ukui-sidebar-notification/notificationPlugin.h b/src/plugins/ukui-sidebar-notification/notificationPlugin.h new file mode 100644 index 0000000..77d51de --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/notificationPlugin.h @@ -0,0 +1,126 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include + +#define UKUI_TRANSPARENCY_SETTING "org.ukui.control-center.personalise" +#define STYLE_FONT_SCHEMA "org.ukui.style" + +#define PANEL_DBUS_SERVICE "com.ukui.panel.desktop" +#define PANEL_DBUS_PATH "/" +#define PANEL_DBUS_INTERFACE "com.ukui.panel.desktop" + +#define UKUI_PANEL_SETTING "org.ukui.panel.settings" + +#define TITLE_HEIGHT 120 //消息通知抬头高度 +#define CLIPBOARD_HEIGHT 385 + +class AppMsg; +class ScrollAreaWidget; +class QSvgRenderer; +class TakeInBoxToolButton; +class TakeInCoutLabel; + +class NotificationPlugin : public QWidget, public NotificationInterface +{ + Q_OBJECT + //Q_INTERFACES宏用于告诉Qt该类实现的接口 + Q_INTERFACES(NotificationInterface) + //Q_PLUGIN_METADATA宏用于描述插件元数据 + Q_PLUGIN_METADATA(IID NotificationInterface_iid FILE "notificationPlugin.json") + //申明该类有D-BUS服务接口 + //Q_CLASSINFO("D-Bus Interface", "com.scorpio.test.value") + +public: + NotificationPlugin(); + virtual QWidget* centerWidget() override; + virtual void showNotification() override; + virtual void hideNotification() override; + AppMsg* getAppMsgAndIndexByName(QString strAppName, int& nIndex); + AppMsg* getTakeinAppMsgAndIndexByName(QString strAppName, int& nIndex); + void modifyNotifyWidgetTransparency(double transparency); + void initTrans(); + void initUI(); + +private: + QWidget* m_pMainWidget; + QList m_listAppMsg; //对于SingleMsg类对象用list表记录 + QList m_listTakeInAppMsg; + QWidget* m_pMsgListWidget; //消息列表部件,用于装消息的 + QWidget * m_pMsgDoubleListWidget; //消息列表部件,用于装两个消息列表的 + QPropertyAnimation* m_pSwitchAnimation; + ScrollAreaWidget* m_pQScrollAreaNotify; //通知列表ScrollAreaWidget + QVBoxLayout* m_pScrollAreaNotifyVBoxLayout; + ScrollAreaWidget* m_pQScrollAreaTakeIn; //收纳列表ScrollAreaWidget + QVBoxLayout* m_pScrollAreaTakeInVBoxLayout; + QLabel* m_pMessageCenterLabel; + QLabel* m_pTakeinMessageCenterLabel; + QLabel* m_pNotificationLabel; //重要的通知和不重要的通知标签 + QSvgRenderer* m_pSvgRender; + TakeInBoxToolButton* m_pTakeInBoxToolButton; + QPushButton* m_pClearAllToolButton; + QPixmap* m_pPixmap; + TakeInCoutLabel* m_pTakeInCoutLabel; //收纳盒计数统计Label + bool m_bShowTakeIn = false; + bool m_bInitialFlag = false; + + double transparency = 0.7; //初始化透明度 + + void initPanelGsettings(); // 初始化任务栏gsetting,用以监听任务栏的位置变化 + int getTaskBarHeight(); // 连接任务栏dbus接口,获取任务栏高度 + int getPanelSite(); // 获取任务栏位置 + QGSettings* m_pPanelSetting; + + +signals: + void Sig_onNewNotification(); + +private slots: + uint onAddSingleNotify(QString strAppName, QString strIconPath, QString strSummary, QString strBody, QString urlStr, QString actions, QDateTime dateTime, int maxNum, bool bNewNotificationFlag); //处理新增单条通知 + void onTakeInSingleNotify(QString strAppName, QString strIcon, QString strSummary, QString strBody, QString urlStr, QString actions, QDateTime dateTime, int maxNum, bool bNewTakeinFlag); //处理收纳单条通知 + void onClearAllMessage(); //清除所有消息 + void onClearAppMsg(AppMsg* pAppMsg); //处理删除通知应用消息槽函数 + void onClearTakeInAppMsg(AppMsg* pAppMsg); //处理删除收纳应用的槽函数 + void onShowTakeInMessage(); //切换至收纳盒 + void onCallControlPanel(); //调用控制面板 + void onCountTakeInBitAndUpate(); //统计收纳位数并更新至右上角提示 + void onCloseAppMsg(QString strAppName); //配置实时关闭通知消息 + void onUpdateAppMaxNum(QString strAppName, int maxNum); //配置实时更新通知消息最大数 + void onSwitchMsgBoxFinish(); + void onResolutionChanged(); + +}; + +class TakeInCoutLabel : public QLabel +{ + Q_OBJECT +public: + explicit TakeInCoutLabel(QWidget *parent = nullptr); + +protected: + void paintEvent(QPaintEvent *e); +}; + +#endif // NOTIFICATION_PLUGIN_H diff --git a/src/plugins/ukui-sidebar-notification/notificationPlugin.json b/src/plugins/ukui-sidebar-notification/notificationPlugin.json new file mode 100644 index 0000000..1e81138 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/notificationPlugin.json @@ -0,0 +1,3 @@ +{ + "Keys" : [ ] +} diff --git a/src/plugins/ukui-sidebar-notification/notificationPlugin.qrc b/src/plugins/ukui-sidebar-notification/notificationPlugin.qrc new file mode 100644 index 0000000..c42d875 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/notificationPlugin.qrc @@ -0,0 +1,19 @@ + + + qss/notificationPlugin.css + images/hover.svg + images/hover-translucent.svg + images/box-14-translucent.svg + images/box-16-translucent.svg + images/box-16.svg + images/box-24.svg + images/exitbox-14-translucent.svg + images/exitbox-16-translucent.svg + images/exitbox-16.svg + images/exitbox-24.svg + images/box-24-hover.svg + images/exitbox-24-hover.svg + images/exitbox-24-hover.svg + images/box-24-hover.svg + + diff --git a/src/plugins/ukui-sidebar-notification/picturetowhite.cpp b/src/plugins/ukui-sidebar-notification/picturetowhite.cpp new file mode 100644 index 0000000..2757868 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/picturetowhite.cpp @@ -0,0 +1,73 @@ +/* +* Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see get(STYLE_NAME).toString()) && m_pgsettings->get(STYLE_NAME).toString() == STYLE_NAME_KEY_LIGHT) + tray_icon_color = TRAY_ICON_COLOR_LOGHT; + else + tray_icon_color = TRAY_ICON_COLOR_DRAK; + } + connect(m_pgsettings, &QGSettings::changed, this, [=] (const QString &key) { + if (key==STYLE_NAME) { + if (stylelist.contains(m_pgsettings->get(STYLE_NAME).toString()) && m_pgsettings->get(STYLE_NAME).toString() == STYLE_NAME_KEY_LIGHT) + tray_icon_color = TRAY_ICON_COLOR_LOGHT; + else + tray_icon_color = TRAY_ICON_COLOR_DRAK; + } + }); +} + +QPixmap PictureToWhite::drawSymbolicColoredPixmap(const QPixmap &source) +{ + QColor gray(128,128,128); + QColor standard (31,32,34); + QImage img = source.toImage(); + qDebug() << "tray_icon_color-->" << tray_icon_color; + for (int x = 0; x < img.width(); x++) { + for (int y = 0; y < img.height(); y++) { + auto color = img.pixelColor(x, y); + if (color.alpha() > 0) { + if (qAbs(color.red()-gray.red()) < 20 && qAbs(color.green()-gray.green()) < 20 && qAbs(color.blue()-gray.blue()) < 20) { + color.setRed(tray_icon_color); + color.setGreen(tray_icon_color); + color.setBlue(tray_icon_color); + img.setPixelColor(x, y, color); + } else if (qAbs(color.red()-standard.red()) < 20 && qAbs(color.green()-standard.green()) < 20 && qAbs(color.blue()-standard.blue()) < 20) { + color.setRed(tray_icon_color); + color.setGreen(tray_icon_color); + color.setBlue(tray_icon_color); + img.setPixelColor(x, y, color); + } else + img.setPixelColor(x, y, color); + } + } + } + return QPixmap::fromImage(img); +} diff --git a/src/plugins/ukui-sidebar-notification/picturetowhite.h b/src/plugins/ukui-sidebar-notification/picturetowhite.h new file mode 100644 index 0000000..6a0ba73 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/picturetowhite.h @@ -0,0 +1,52 @@ +/* +* Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include + +#define ORG_UKUI_STYLE "org.ukui.style" +#define STYLE_NAME "styleName" +#define STYLE_NAME_KEY_DARK "ukui-dark" +#define STYLE_NAME_KEY_DEFAULT "ukui-default" +#define STYLE_NAME_KEY_BLACK "ukui-black" +#define STYLE_NAME_KEY_LIGHT "ukui-light" +#define STYLE_NAME_KEY_WHITE "ukui-white" +#define TRAY_ICON_COLOR_LOGHT 0 +#define TRAY_ICON_COLOR_DRAK 255 + +class PictureToWhite : public QObject +{ + Q_OBJECT +public: + explicit PictureToWhite(QObject *parent = nullptr); + void initGsettingValue(); + QPixmap drawSymbolicColoredPixmap(const QPixmap &source); + +public: + QGSettings *m_pgsettings; + int tray_icon_color; + +}; + +#endif // PICTURETOWHITE_H diff --git a/src/plugins/ukui-sidebar-notification/qss/notificationPlugin.css b/src/plugins/ukui-sidebar-notification/qss/notificationPlugin.css new file mode 100755 index 0000000..79b8332 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/qss/notificationPlugin.css @@ -0,0 +1,325 @@ +/*QPalette{background:#1A1A1A;}*{outline:1px;color:rgba(255, 255, 255, 0.05);}*/ + +QWidget{ + margin-left: 0px; + margin-top: 0px; + margin-right: 0px; + margin-bottom: 0px; +/* background:rgba(26,26,26,0.95);*/ +} + +/*QWidget#NotificationCenter{ + background:rgba(19,19,20,0.5); +}*/ + +QWidget#SingleNotification{ + background:rgba(255,255,255,0.12); + border-radius:6px; +} + +/*QWidget#QScrollAreaInQWidget{ + background:rgba(19,19,20,0.1); +}*/ + +QWidget#BaseMap{ + background:rgba(255,255,255,0.06); + width:360px; + height:6px; + border-radius:0px 0px 6px 6px; +} + +/*QWidget#NotificationCenter{ + margin-left: 10px; + margin-top: 21px; + margin-right: 0px; + margin-bottom: 0px; + width:400px; +}*/ + +QWidget#NotificationName{ + margin-left: 11px; + margin-top: 0px; + margin-right: 28px; + margin-bottom: 0px; + width:390px; +} + +QToolButton#takein{ + border:0px solid #242424; + padding:0px; + background:transparent; +/* background:rgba(238,238,238,1);*/ +/* width:24px; + height:30px;*/ +} + +QPushButton{ + color:rgba(255,255,255,1); + font-size:14px; + font-family:Noto Sans CJK SC; +/* background:transparent;*/ +} + +QPushButton#clearall{ + color:rgba(255,255,255,0.91); + font-weight:400; + border:0px; + line-height:24px; +/* padding:0px;*/ + font-size:14px; + width:80px; + height:34px; +} + +QPushButton:hover#clearall{ + color:rgba(255,255,255,0.91); + font-weight:400; + border:0px; + line-height:24px; + background:rgba(255,255,255,0.12); + font-size:14px; + width:80px; + height:34px; + border-radius:3px; +} + +QPushButton:pressed#clearall{ + color:rgba(255,255,255,0.91); + font-weight:400; + border:0px; + line-height:24px; + background:rgba(255,255,255,0.08); + font-size:14px; + width:80px; + height:34px; + border-radius:3px; +} + +QPushButton#setting{ + color:rgba(255,255,255,0.91); + font-weight:400; + border:0px; + line-height:24px; + font-size:14px; + width:80px; + height:34px; +} + +QPushButton:hover#setting{ + color:rgba(255,255,255,0.91); + font-weight:400; + border:0px; + line-height:24px; + background:rgba(255,255,255,0.12); + font-size:14px; + width:80px; + height:34px; + border-radius:3px; +} + +QPushButton:pressed#setting{ + color:rgba(255,255,255,0.91); + font-weight:400; + border:0px; + line-height:24px; + background:rgba(255,255,255,0.08); + font-size:14px; + width:80px; + height:34px; + border-radius:3px; +} + +QPushButton#takein{ + color:rgba(255,255,255,231); + font-weight:400; + border:0px; +/* background:transparent; + background:rgba(238,238,238,1);*/ + width:184px; + height:34px; +} + +QPushButton:hover#takein{ + color:rgba(255,255,255,231); + font-weight:400; + border:0px; + background:rgba(255,255,255,0.12); + width:184px; + height:34px; +} + +QPushButton#delete{ + color:rgba(255,255,255,231); + font-weight:400; + border:0px; +/* background:transparent; + background:rgba(238,238,238,1);*/ + width:184px; + height:34px; +} + +QPushButton:hover#delete{ + color:rgba(255,255,255,231); + font-weight:400; + border:0px; + background:rgba(255,255,255,0.12); + width:184px; + height:34px; +} + +QPushButton#fold{ + color:rgba(107,142,235,0.91); + font-weight:400; + border:0px; + font-size:14px; +} + +QPushButton:hover#fold{ + color:rgba(151,175,241,0.91); + font-weight:400; + border:0px; + font-size:14px; +} + +QPushButton:pressed#fold{ + color:rgba(61,107,229,0.91); + font-weight:400; + border:0px; + font-size:14px; +} + +QLabel{ + color:#FFFFFF; /*文字颜色*/ + font-family:NotoSansCJKsc-Regular; + background-color:transparent; +} + +QLabel#notificationcentername{ + color:rgba(255,255,255,247); /*文字颜色*/ + background-color:transparent ; + font-family : NotoSansCJKsc-Regular; + font-size:20px; +} + +QLabel#importantnotification{ + color:rgba(255,255,255,0.91); /*文字颜色*/ + font-family : NotoSansCJKsc-Regular; + font-size:14px; +} + +QLabel#AppName{ + color:rgba(255,255,255,0.57); /*文字颜色*/ + font-size:14px; + font-weight:400; + font-family:NotoSansCJKsc-Regular; +/* background-color:transparent;*/ +} + +QLabel#pushtime{ + color:rgba(255,255,255,0.57); /*文字颜色*/ + font-size:14px; +} + +QLabel#Summary{ + color:rgba(255,255,255,0.97); /*文字颜色*/ + font-size:16px; +} + +QLabel#body{ + color:rgba(255,255,255,0.57); /*文字颜色*/ + font-size:14px; + background-color:transparent; + padding:0px; +/* height:24px;*/ +} + +QLabel#ShowLeftItem{ + color:rgba(255,255,255,0.35); + font-size:14px; + padding:0px; +} + +QLabel#takeincout{ + font-size:11px; + background-color:rgba(61,107,229,1); + border-radius:6px; +} + +QScrollBar:horizontal{ +background:#484848; +padding:0px; +border-radius:6px; +max-height:12px; +} + +QScrollBar::handle:horizontal{ +background:#242424; +min-width:50px; +border-radius:6px; +} + +QScrollBar::handle:horizontal:hover{ +background:#00BB9E; +} + +QScrollBar::handle:horizontal:pressed{ +background:#00BB9E; +} + +QScrollBar::add-page:horizontal{ +background:none; +} + +QScrollBar::sub-page:horizontal{ +background:none; +} + +QScrollBar::add-line:horizontal{ +background:none; +} + +QScrollBar::sub-line:horizontal{ +background:none; +} + +QScrollBar:vertical{ +background:#484848; +padding:0px; +border-radius:6px; +max-width:12px; +} + +QScrollBar::handle:vertical{ +background:#242424; +min-height:50px; +border-radius:6px; +} + +QScrollBar::handle:vertical:hover{ +background:#00BB9E; +} + +QScrollBar::handle:vertical:pressed{ +background:#00BB9E; +} + +QScrollBar::add-page:vertical{ +background:none; +} + +QScrollBar::sub-page:vertical{ +background:none; +} + +QScrollBar::add-line:vertical{ +background:none; +} + +QScrollBar::sub-line:vertical{ +background:none; +} + +QScrollArea{ +border:0px; +} + diff --git a/src/plugins/ukui-sidebar-notification/scrollareawidget.cpp b/src/plugins/ukui-sidebar-notification/scrollareawidget.cpp new file mode 100644 index 0000000..6b256da --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/scrollareawidget.cpp @@ -0,0 +1,82 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see verticalScrollBar()->setStyleSheet("QScrollBar::vertical {width:10px;padding-left:3px;padding-top:0px;padding-right:3px;padding-bottom:0px;background:transparent;border-radius:6px;}" + "QScrollBar::handle:vertical {width:4px;background-color:rgba(61,61,65,1);border-radius:2px;}" + "QScrollBar::sub-line:vertical {background-color:transparent;height:0px;width:0px;}" + "QScrollBar::add-line:vertical {background-color:transparent;height:0px;width:0px;}"); + return; +} + +void ScrollAreaWidget::leaveEvent(QEvent *event) +{ + Q_UNUSED(event); + this->verticalScrollBar()->setStyleSheet("QScrollBar::vertical {width:10px;padding-left:3px;padding-top:0px;padding-right:3px;padding-bottom:0px;background:transparent;border-radius:6px;}" + "QScrollBar::handle:vertical {width:4px;background-color:transparent;border-radius:2px;}" + "QScrollBar::sub-line:vertical {background-color:transparent;height:0px;width:0px;}" + "QScrollBar::add-line:vertical {background-color:transparent;height:0px;width:0px;}"); + return; +} diff --git a/src/plugins/ukui-sidebar-notification/scrollareawidget.h b/src/plugins/ukui-sidebar-notification/scrollareawidget.h new file mode 100644 index 0000000..4e409d9 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/scrollareawidget.h @@ -0,0 +1,56 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include + +class ScrollBarWidget : public QScrollBar +{ + Q_OBJECT +public: + explicit ScrollBarWidget(); + +protected: + virtual void enterEvent(QEvent *event) override; + virtual void leaveEvent(QEvent *event) override; + +signals: + +public slots: +}; + +class ScrollAreaWidget : public QScrollArea +{ + Q_OBJECT +public: + explicit ScrollAreaWidget(); + +protected: + virtual void enterEvent(QEvent *event) override; + virtual void leaveEvent(QEvent *event) override; + +signals: + +public slots: +}; + +#endif // SCROLLAREAWIDGET_H diff --git a/src/plugins/ukui-sidebar-notification/singlemsg.cpp b/src/plugins/ukui-sidebar-notification/singlemsg.cpp new file mode 100644 index 0000000..f956723 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/singlemsg.cpp @@ -0,0 +1,1025 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STYLE_FONT_SCHEMA "org.ukui.style" +#define SYSTEM_FONT_EKY "system-font-size" +#define SYSTEM_NAME_KEY "system-font" + + +SingleMsg::SingleMsg(AppMsg* pParent, QString strIconPath, QString strAppName, QString strSummary, QDateTime dateTime, QString strBody, QString strUrl, QString strAction, bool bTakeInFlag) +{ + listenTimeZone(); + m_bMain = true; //默认是主窗口 + m_bFold = true; //默认折叠状态 + m_bAppFold = true; //默认整组消息折叠状态 + jumpFlag = false; //默认未点击跳转 + m_pParent = pParent; + m_strIconPath = strIconPath; + m_strSummary = strSummary; + m_strBody = strBody; + m_strUrl = strUrl; + m_strAction = strAction; + + m_dateTime = dateTime; + m_uNotifyTime = dateTime.toTime_t(); + m_bTakeInFlag = bTakeInFlag; + + initTimeFormatGsetting(); + initGsettingValue(); + + connect(this, SIGNAL(Sig_setAppFoldFlag(bool)), pParent, SLOT(setAppFoldFlag(bool))); + connect(this, SIGNAL(Sig_onDeleSingleMsg(SingleMsg*)), pParent, SLOT(onDeleSingleMsg(SingleMsg*))); + connect(this, SIGNAL(Sig_onDeleteAppMsg()), pParent, SLOT(onDeleteAppMsg())); + connect(this, SIGNAL(Sig_onTakeInSingleMsg(SingleMsg*)), pParent, SLOT(onTakeInSingleMsg(SingleMsg*))); + connect(this, SIGNAL(Sig_onTakeinWholeApp()), pParent, SLOT(onTakeinWholeApp())); + connect(this, SIGNAL(Sig_onRecoverSingleMsg(SingleMsg*)), pParent, SLOT(onRecoverSingleMsg(SingleMsg*))); + connect(this, SIGNAL(Sig_onRecoverWholeApp()), pParent, SLOT(onRecoverWholeApp())); + connect(this, SIGNAL(Sig_onMainEnter()), pParent, SLOT(onMainMsgEnter())); + connect(this, SIGNAL(Sig_onMainLeave()), pParent, SLOT(onMainMsgLeave())); + connect(this, SIGNAL(Sig_notifyAppShowBaseMap()), pParent, SLOT(onShowBaseMap())); + connect(this, SIGNAL(Sig_notifyAppHideBaseMap()), pParent, SLOT(onHideBaseMap())); + + //为了设置SingleMsg的6px圆角的样式,在里面套了一个QWidget + m_pAppVLaout = new QVBoxLayout(); + m_pAppVLaout->setContentsMargins(0, 0, 0, 0); + m_pAppVLaout->setSpacing(0); + m_pSingleWidget = new QWidget(this); + m_pSingleWidget->setObjectName("SingleNotification"); + m_pSingleWidget->setAttribute(Qt::WA_TranslucentBackground); + + m_pAnimationBaseMapWidget = new QWidget(this); + m_pAnimationBaseMapWidget->setAttribute(Qt::WA_TranslucentBackground); + + //单条消息总体垂直布局器 + QVBoxLayout* pMainVLaout = new QVBoxLayout; + pMainVLaout->setContentsMargins(0, 0, 0, 0); + pMainVLaout->setSpacing(0); + + //图标和时间行的水平布局部件 + m_pIconWidget = new QWidget; + + //图标和时间行的水平布局器 + m_pIconHLayout = new QHBoxLayout(); + m_pIconHLayout->setContentsMargins(10, 11, 0, 0); + m_pIconHLayout->setSpacing(0); + + //设置通知消息中的Icon,使用QToolButton + QLabel* pIconToolButton = new QLabel; + + m_pAnimationBaseMapWidget->setAttribute(Qt::WA_TranslucentBackground); + + QPixmap pixmap; + pIconToolButton->setFixedSize(24, 24); + if (strIconPath.contains("file://")) { + int length = strIconPath.length(); + strIconPath = strIconPath.mid(7, length); + } + + const qreal pixelRatio = qApp->primaryScreen()->devicePixelRatio(); + + pixmap = QIcon::fromTheme(strIconPath).pixmap(QSize(24, 24)); + + + if (pixmap.isNull()) { + QString iconUrl; + const QUrl url(strIconPath); + iconUrl = url.isLocalFile() ? url.toLocalFile() : url.url(); + + if (strIconPath.contains("file://")) { + int length = strIconPath.length(); + strIconPath = strIconPath.mid(7, length); + } + const QIcon &icon = QIcon::fromTheme(strIconPath, QIcon::fromTheme("application-x-desktop")); + pixmap = icon.pixmap(width() * pixelRatio, height() * pixelRatio); + } + + + if (!pixmap.isNull()) { + pixmap = pixmap.scaled(pIconToolButton->width() * pixelRatio, pIconToolButton->height() * pixelRatio, + Qt::KeepAspectRatioByExpanding, + Qt::SmoothTransformation); + + pixmap.setDevicePixelRatio(pixelRatio); + + } + pIconToolButton->setPixmap(pixmap); + + //获取系统字体大小 + QFont ft; + int fontSize; + if(QGSettings::isSchemaInstalled(STYLE_FONT_SCHEMA)) + { + const QByteArray styleID(STYLE_FONT_SCHEMA); + stylesettings = new QGSettings(styleID); + fontSize = stylesettings->get("system-font-size").toInt(); + ft.setPointSize(fontSize); + } + connect(stylesettings, SIGNAL(changed(const QString &)), this, SLOT(slotChangeFonts(const QString &))); + + //设置应用名标签,采用省略模式 + QLabel* pAppNameLabel = new QLabel(); + pAppNameLabel->setObjectName("AppName"); + pAppNameLabel->setAttribute(Qt::WA_TranslucentBackground); + pAppNameLabel->setFont(ft); + QFontMetrics fontMetrics1(pAppNameLabel->font()); + QString formatAppName = fontMetrics1.elidedText(strAppName, Qt::ElideRight, pAppNameLabel->width()); + pAppNameLabel->setText(formatAppName);//第一行 + + //设置通知消息中的弹簧,水平任意伸缩使应用名和时间分开 + QSpacerItem* pHExpandSpacer = new QSpacerItem(500, 10, QSizePolicy::Expanding, QSizePolicy::Fixed); + + //放置时间和收纳删除按钮的窗口 + m_pTimeLabelWidget = new QWidget; + m_pTimeLabelWidget->setFixedSize(146, 22); + QHBoxLayout* pTimeLableHLayout = new QHBoxLayout(); + + + m_pStorageDeleteButtonWidget = new QWidget; + m_pStorageDeleteButtonWidget->setFixedSize(146, 20); + QHBoxLayout* pStorageDeleteButtonHLaout = new QHBoxLayout(); + + //设置通知消息中的通知时间 + m_pTimeLabel = new QLabel(); + m_pTimeLabel->setObjectName("pushtime"); + m_pTimeLabel->setText(tr("now"));//提示时间 + m_pTimeLabel->setAttribute(Qt::WA_TranslucentBackground); + + //收纳删除按钮图标的大小 + QSize normalIconSize(16, 16); + QSize pressedIconSize(14, 14); + + //单独收纳按钮 + if(false == m_bTakeInFlag){ + QString strIcon = ":/images/box-16-translucent.svg"; + QString strHoverIcon = ":/images/box-16.svg"; + QString strPressIcon = ":/images/box-14-translucent.svg"; + m_pSingleTakeinButton = new ButtonWidget(strIcon, strHoverIcon, strPressIcon, normalIconSize, pressedIconSize); + connect(m_pSingleTakeinButton, SIGNAL(Sig_clicked()), this, SLOT(onTakeIn())); + } else { + QString strIcon = ":/images/exitbox-16-translucent.svg"; + QString strHoverIcon = ":/images/exitbox-16.svg"; + QString strPressIcon = ":/images/exitbox-14-translucent.svg"; + m_pSingleTakeinButton = new ButtonWidget(strIcon, strHoverIcon, strPressIcon, normalIconSize, pressedIconSize); + connect(m_pSingleTakeinButton, SIGNAL(Sig_clicked()), this, SLOT(onRecover())); + } + + //单独删除按钮 + QString strIcon = ":/images/hover-translucent.svg"; + QString strHoverIcon = ":/images/hover.svg"; + + QSize deleteNormalIconSize(14, 14); + QSize deletePressedIconSize(12, 12); + m_pSingleDeleteButton = new ButtonWidget(strIcon, strHoverIcon, strIcon,deleteNormalIconSize,deletePressedIconSize); + connect(m_pSingleDeleteButton, SIGNAL(Sig_clicked()), this, SLOT(onDele())); + m_pStorageDeleteButtonWidget->hide(); + + //设置标签布局 + pTimeLableHLayout->addWidget(m_pTimeLabel, 0, Qt::AlignRight); + pTimeLableHLayout->addItem(new QSpacerItem(13, 10 , QSizePolicy::Fixed, QSizePolicy::Fixed)); + pTimeLableHLayout->setContentsMargins(0, 0, 0, 0); + pTimeLableHLayout->setSpacing(0); + m_pTimeLabelWidget->setLayout(pTimeLableHLayout); + m_pTimeLabelWidget->setAttribute(Qt::WA_TranslucentBackground); + + //收纳和删除按钮布局 + pStorageDeleteButtonHLaout->addItem(new QSpacerItem(1, 10, QSizePolicy::Expanding, QSizePolicy::Fixed)); + pStorageDeleteButtonHLaout->addWidget(m_pSingleTakeinButton, 0, Qt::AlignRight); + pStorageDeleteButtonHLaout->addSpacerItem(new QSpacerItem(8, 10, QSizePolicy::Fixed, QSizePolicy::Fixed)); + pStorageDeleteButtonHLaout->addWidget(m_pSingleDeleteButton, 0, Qt::AlignRight); + pStorageDeleteButtonHLaout->addItem(new QSpacerItem(15, 10, QSizePolicy::Fixed, QSizePolicy::Fixed)); + pStorageDeleteButtonHLaout->setContentsMargins(0, 0, 0, 0); + pStorageDeleteButtonHLaout->setSpacing(0); + m_pStorageDeleteButtonWidget->setLayout(pStorageDeleteButtonHLaout); + + m_pIconHLayout->addWidget(pIconToolButton, 0, Qt::AlignLeft); + m_pIconHLayout->addItem(new QSpacerItem(6, 10, QSizePolicy::Fixed, QSizePolicy::Fixed)); + m_pIconHLayout->addWidget(pAppNameLabel, 0, Qt::AlignLeft|Qt::AlignVCenter); + m_pIconHLayout->addItem(pHExpandSpacer); + m_pIconHLayout->addWidget(m_pTimeLabelWidget, 0, Qt::AlignRight ); + m_pIconHLayout->addWidget(m_pStorageDeleteButtonWidget, 0, Qt::AlignRight ); + m_pIconWidget->setLayout(m_pIconHLayout); + pMainVLaout->addWidget(m_pIconWidget, 0); + m_pIconWidget->setAttribute(Qt::WA_TranslucentBackground); + + m_pStorageDeleteButtonWidget->setAttribute(Qt::WA_TranslucentBackground); + + //内容部件,将主题正文以及剩余条数显示装入内容部件 + m_pContextWidget = new QWidget; + + //内容部件的垂直布局器 + QVBoxLayout* pVContextLayout = new QVBoxLayout(); + pVContextLayout->setContentsMargins(40, 0, 26, 0); + pVContextLayout->setSpacing(0); + + //设置通知消息中的主题,采用省略模式 + m_pSummaryLabel = new QLabel(); + m_pSummaryLabel->setFixedWidth(314); + m_pSummaryLabel->setAttribute(Qt::WA_TranslucentBackground); + + //延时1秒设置字体 + QTimer::singleShot(1, m_pSummaryLabel, [=]() { + QFont summaryFont = m_pSummaryLabel->font(); + summaryFont.setPointSizeF(fontSize + 2); +// summaryFont.setFamily("Noto Sans CJK SC"); + summaryFont.setBold(true); + m_pSummaryLabel->setFont(summaryFont);//第二行正文 + }); + + QString formatSummary; + formatSummary.append("

").append(m_strSummary).append("

"); + QFontMetrics fontMetrics(m_pSummaryLabel->font()); + int nFontSize = fontMetrics.width(formatSummary); + QString strformatSummary = formatSummary; + if(nFontSize > (m_pSummaryLabel->width() + 239)) + { + strformatSummary = fontMetrics.elidedText(formatSummary, Qt::ElideRight, m_pSummaryLabel->width() + 210); + } + + m_pSummaryLabel->setText(strformatSummary); + pVContextLayout->addWidget(m_pSummaryLabel, 0, Qt::AlignLeft); + + //设置通知消息中的正文QLabel,行高24px,采用自动换行模式 + if(false == m_strBody.isEmpty()) + { + QString strLineHeight24Body; + strLineHeight24Body.append("

").append(m_strBody).append("

"); + m_pBodyLabel = new QLabel(); + m_pBodyLabel->setFixedWidth(315); + m_pBodyLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); + m_pBodyLabel->adjustSize(); + m_pBodyLabel->setAttribute(Qt::WA_TranslucentBackground); + + + QFontMetrics fontMetrics(m_pBodyLabel->font()); + int fontSize = fontMetrics.width(strLineHeight24Body); + QString formatBody = strLineHeight24Body; + + m_pBodyLabel->setWordWrap(false); + if(fontSize > (m_pBodyLabel->width() + 209)) + { + formatBody = fontMetrics.elidedText(strLineHeight24Body, Qt::ElideRight, m_pBodyLabel->width() + 180); + } + m_pBodyLabel->setText(formatBody); + pVContextLayout->addWidget(m_pBodyLabel, 0, Qt::AlignLeft); + } + + //显示该应用未展开部件 + m_pShowLeftWidget = new QWidget; + QVBoxLayout* pVShowLeftLayout = new QVBoxLayout(); + pVShowLeftLayout->setContentsMargins(0,6,0,14); + m_pShowLeftWidget->setAttribute(Qt::WA_TranslucentBackground); + m_pShowLeftItemLabel = new QLabel; + m_pShowLeftItemLabel->setObjectName("ShowLeftItem"); + m_pShowLeftItemLabel->setVisible(false); + pVShowLeftLayout->addWidget(m_pShowLeftItemLabel, 0, Qt::AlignLeft); + m_pShowLeftWidget->setLayout(pVShowLeftLayout); + pVContextLayout->addWidget(m_pShowLeftWidget, 0, Qt::AlignLeft); + m_pContextWidget->setLayout(pVContextLayout); + pMainVLaout->addWidget(m_pContextWidget); + m_pContextWidget->setAttribute(Qt::WA_TranslucentBackground); + m_pSingleWidget->setLayout(pMainVLaout); + m_pAppVLaout->addWidget(m_pSingleWidget); + this->setLayout(m_pAppVLaout); + m_pSetDeleDelayTimer = new QTimer(this); + m_pSetJumpDelayTimer = new QTimer(this); + return; +} + +void SingleMsg::initTimeFormatGsetting() +{ + const QByteArray id(CONTROL_CENTER_TIME_FORMAT_GSETTING); + QGSettings * fontSetting = new QGSettings(id); + QString timeFormat = fontSetting->get(CONTROL_TINE_FORMAT_GSETTING_VALUE).toString(); + if (timeFormat == TIME_FORMAT) { + m_bTimeFormat = false; + } else { + m_bTimeFormat = true; + } + connect(fontSetting, &QGSettings::changed, this, [=](QString key) { + if (key == CONTROL_TINE_FORMAT_GSETTING_VALUE) { + QString value = fontSetting->get(CONTROL_TINE_FORMAT_GSETTING_VALUE).toString(); + if (value == TIME_FORMAT) { + m_bTimeFormat = false; + } else { + m_bTimeFormat = true; + } + } + }); +} + +void SingleMsg::listenTimeZone() +{ + m_datetimeInterface = new QDBusInterface("org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + QDBusConnection::systemBus(), this); + + QDBusConnection::systemBus().connect(QString("org.freedesktop.timedate1"), + QString("/org/freedesktop/timedate1"), + QString("org.freedesktop.DBus.Properties"), + QString("PropertiesChanged"), this, SLOT(listenTimeZoneSlots())); + +} + +void SingleMsg::listenTimeZoneSlots() +{ + QDateTime currentDateTime(QDateTime::currentDateTime()); + m_uNotifyTime = currentDateTime.toTime_t() - m_uTimeDifference; + m_dateTime = QDateTime::fromTime_t(m_uNotifyTime); + updatePushTime(); +} + +void SingleMsg::slotChangeFonts(const QString &key) +{ + QFont ft; + int fontSize = 12; + ft.setPointSize(20); + if(QGSettings::isSchemaInstalled(STYLE_FONT_SCHEMA)){ + fontSize = stylesettings->get("system-font-size").toInt(); + ft.setPointSize(fontSize); + } + //主题显示 + QString formatSummary; + formatSummary.append("

").append(m_strSummary).append("

"); + QFontMetrics fontMetrics(m_pSummaryLabel->font()); + int nFontSize = fontMetrics.width(formatSummary); + QString strformatSummary = formatSummary; + if(nFontSize > (m_pSummaryLabel->width() + 239)) + { + strformatSummary = fontMetrics.elidedText(formatSummary, Qt::ElideRight, m_pSummaryLabel->width() + 210); + } + + QTimer::singleShot(1, m_pSummaryLabel, [=]() { + QFont summaryFont = m_pSummaryLabel->font(); + summaryFont.setPointSizeF(fontSize+3); +// summaryFont.setFamily("Noto Sans CJK SC"); + summaryFont.setBold(true); + m_pSummaryLabel->setFont(summaryFont); + }); + + m_pSummaryLabel->setText(strformatSummary); + + //正文显示 + QString strLineHeight24Body; + strLineHeight24Body.append("

").append(m_strBody).append("

"); + QFontMetrics fontMetrics1(m_pBodyLabel->font()); + QString formatBody = strLineHeight24Body; + if(fontSize > (m_pBodyLabel->width() + 209)) + { + formatBody = fontMetrics1.elidedText(strLineHeight24Body, Qt::ElideRight, m_pBodyLabel->width() + 180); + } + m_pBodyLabel->setFont(ft); + m_pBodyLabel->setText(formatBody); + +} + +void SingleMsg::initGsettingValue() +{ + const QByteArray id(STYLE_FONT_SCHEMA); + if (QGSettings::isSchemaInstalled(id)) + m_pStyleGsetting = new QGSettings(id); +} + +void SingleMsg::jumpAction() +{ + //若没有跳转信息传入,则不跳转,不删除消息,直接返回 + if (m_strUrl.isEmpty() && m_strAction.isEmpty()) { + return; + } + //关闭该条通知 + jumpFlag = true; + onDele(); + //跳转动作 + m_pSetJumpDelayTimer->setSingleShot(true); //延迟30毫秒,等待删除完成后跳转 + connect(m_pSetJumpDelayTimer, &QTimer::timeout, this, [=](){ + if(!m_strUrl.isEmpty()){ + QString cmd = QString("xdg-open ") + m_strUrl; + qInfo()<<"Jump Url:"<start(m_strAction); + emit Sig_onDeleSingleMsg(this); + } + else{ + emit Sig_onDeleSingleMsg(this); + } + }); + connect(this,&SingleMsg::Sig_jumpAction,this,[=](){ + m_pSetJumpDelayTimer->start(30); + }); + + return; +} + +void SingleMsg::paintEvent(QPaintEvent *e) +{ + + QPainter p(this); + QRect rect = this->rect(); + rect.setWidth(rect.width() - 1); + rect.setHeight(rect.height() - 1); + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + QString m_style = "ukui-light"; + + const QByteArray id(STYLE_FONT_SCHEMA); + if (QGSettings::isSchemaInstalled(id)) + m_style = m_pStyleGsetting->get("style-name").toString(); + + if (m_style=="ukui-light") { + p.setBrush(QBrush(QColor(255, 255, 255,255))); + p.setPen(Qt::transparent); + p.drawRoundedRect(rect,6,6); + switch (status) { + case NORMAL: { + p.setBrush(QBrush(QColor(255, 255, 255,0))); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect,6,6); + break; + } + case HOVER: { + p.setBrush(QBrush(QColor(255, 255, 255, 255))); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect,6,6); + this->update(); + break; + } + case PRESS: { + p.setBrush(QBrush(QColor(255, 255, 255, 255))); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect,6,6); + this->update(); + break; + } + } + } else { + p.setBrush(QBrush(QColor(255, 255, 255, 20))); + p.setPen(Qt::transparent); + p.drawRoundedRect(rect,6,6); + switch (status) { + case NORMAL: { + p.setBrush(QBrush(QColor(255, 255, 255, 0))); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect,6,6); + break; + } + case HOVER: { + p.setBrush(QBrush(QColor(255, 255, 255, 40))); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect,6,6); + break; + } + case PRESS: { + p.setBrush(QBrush(QColor(255, 255, 255, 0))); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect,6,6); + break; + } + } + } + + QWidget::paintEvent(e); + +} +void SingleMsg::updatePushTime() +{ + QDateTime currentDateTime(QDateTime::currentDateTime()); + + m_uTimeDifference = currentDateTime.toTime_t() - m_uNotifyTime; + + if (currentDateTime.toTime_t() < (m_uNotifyTime + 60)) { + return; + } + QString strPushDate; + if (m_dateTime.date() == currentDateTime.date()) { + if(true == m_bTimeFormat) { + strPushDate = m_dateTime.toString("hh:mm"); //24小时制 + } else { + strPushDate = m_dateTime.toString("AP h:mm"); //12小时制 + } + m_pTimeLabel->setText(strPushDate); + return; + } + + if (1 == (currentDateTime.date().toJulianDay() - m_dateTime.date().toJulianDay())) { + strPushDate = tr("Yesterday "); + if(true == m_bTimeFormat) { + strPushDate = strPushDate + m_dateTime.toString("hh:mm"); //24小时制 + } else { + strPushDate = strPushDate + m_dateTime.toString("AP h:mm"); //12小时制 + } + m_pTimeLabel->setText(strPushDate); + return; + } + + //一周以内 + if((currentDateTime.date().toJulianDay() - m_dateTime.date().toJulianDay()) < 7) + { + if(true == m_bTimeFormat) + { + strPushDate = m_dateTime.toString("ddd hh:mm"); //24小时制 + } + else + { + strPushDate = m_dateTime.toString("ddd AP h:mm"); //12小时制 + } + m_pTimeLabel->setText(strPushDate); + } else { + //一周以外 + if (QGSettings::isSchemaInstalled( "org.ukui.control-center.panel.plugins")) { + QGSettings *m_pFontGsetting = new QGSettings( "org.ukui.control-center.panel.plugins"); + if (m_pFontGsetting != nullptr) { + if (m_pFontGsetting->get("date").toString() == "cn"){ + strPushDate = m_dateTime.toString("yyyy/MM/dd"); + } else { + strPushDate = m_dateTime.toString("yyyy-MM-dd"); + } + } + } + m_pTimeLabel->setText(strPushDate); + } + + return; +} + +void SingleMsg::setBodyLabelWordWrap(bool bFlag) +{ + if(true == m_strBody.isEmpty()) + { + return; + } + + m_pBodyLabel->setWordWrap(bFlag); + QFont font14; + font14.setPixelSize(14); +// m_pBodyLabel->setFont(font14); + QFontMetrics fontMetrics(m_pBodyLabel->font()); + QString strLineHeight24Body; + strLineHeight24Body.append("

").append(m_strBody).append("

"); + int fontSize = fontMetrics.width(strLineHeight24Body); + QString formatBody = strLineHeight24Body; + + if(true == bFlag) + { + // //如果展开,就超过四行末尾显示省略号 + + // { + // formatBody = fontMetrics.elidedText(strLineHeight24Body, Qt::ElideRight, m_pBodyLabel->width() * 4 + 152); + // } + //处理要显示的字符串,在换行处加入空格,防止因为QLabel换行机制导致显示不完整 + QString strDisplay; + uint j=1; + int labelWidth = m_pBodyLabel->width(); + for(int i=0;i (j*(labelWidth-8))){ +// strDisplay+=" "; + j++; + } + } + QString strTmp; + strTmp.append("

").append(strDisplay).append("

"); + //如果展开,超过四行末尾显示省略号 + formatBody = fontMetrics.elidedText(strTmp, Qt::ElideRight, m_pBodyLabel->width() * 4 + 152); + } + else + { + //如果不展开,就超过一行末尾显示省略号 + if(fontSize > (m_pBodyLabel->width() + 209)) + { + formatBody = fontMetrics.elidedText(strLineHeight24Body, Qt::ElideRight, m_pBodyLabel->width() + 180); + } + } + m_pBodyLabel->setText(formatBody); + + return; +} + +//将应用的总的剩余条数设置剩余标签显示内容,根据具体情况显示,该函数只有顶部消息才执行 +void SingleMsg::setLeftItem(int nShowLeftCount) +{ + m_nShowLeftCount = nShowLeftCount; + QString strShowLeft = tr("In addition ") + QString::number(nShowLeftCount) + tr(" notification"); + m_pShowLeftItemLabel->setText(strShowLeft); + m_pShowLeftItemLabel->setAttribute(Qt::WA_TranslucentBackground); + + //当剩余条数大于0, 且是折叠状态则显示剩余标签 + if((true == m_bAppFold) && (m_nShowLeftCount > 0)) + { + m_pAppVLaout->setContentsMargins(0,0,0,0); //假如折叠,剩余条目显示将可见,则SingleMsg的内容均无空隙 + m_pShowLeftItemLabel->setVisible(true); + } + else + { + m_pAppVLaout->setContentsMargins(0,0,0,6); //假如展开,剩余条目显示不可见,则SingleMsg的内容空白恢复正常,即底部多出6个px的空隙 + m_pShowLeftItemLabel->setVisible(false); + } +} + +void SingleMsg::setShowLeftItemFlag(bool bFlag) +{ + m_pShowLeftItemLabel->setVisible(bFlag); +} + +void SingleMsg::setSingleMsgContentsMargins(int left, int top, int right, int bottom) +{ + m_pAppVLaout->setContentsMargins(left, top, right, bottom); +} + +void SingleMsg::enterEvent(QEvent *event) +{ + Q_UNUSED(event); + status = HOVER; + m_pStorageDeleteButtonWidget->show(); + m_pTimeLabelWidget->hide(); + m_pIconHLayout->setContentsMargins(10, 11, 0, 0); + + if((true == m_bMain) && (true == m_bAppFold) && (m_nShowLeftCount > 0)) + { + emit Sig_onMainEnter(); + } + this->update(); + return; +} + +void SingleMsg::leaveEvent(QEvent *event) +{ + Q_UNUSED(event); + + status =NORMAL; + m_pTimeLabelWidget->show(); + m_pStorageDeleteButtonWidget->hide(); + m_pIconHLayout->setContentsMargins(10, 11, 0, 0); + if((true == m_bMain) && (true == m_bAppFold) && (m_nShowLeftCount > 0)) + { + emit Sig_onMainLeave(); + } + this->update(); + return; +} + +//鼠标点击事件:1、折叠状态下展开消息 2、展开状态下执行跳转动作 +void SingleMsg::mousePressEvent(QMouseEvent *event) +{ + status =PRESS; + if (event->buttons() == Qt::LeftButton) + { + if (m_pParent->getFoldFlag()) { //折叠状态 + if (true == m_bMain) { + if (m_pParent->getSingleMsgCount()<=1) { + if (m_bFold) { + //折叠状态下展开单条消息 + setBodyLabelWordWrap(true); + setFoldFlag(false); + + } else { + //已经展开的消息执行跳转 + jumpAction(); + } + } else { + //展开整个app消息 + if(true == m_bAppFold){ + m_bAppFold = false; //置为false,表示展开 + m_pShowLeftItemLabel->setVisible(false); //展开时,剩余条目设置为不可见 + emit Sig_setAppFoldFlag(m_bAppFold); //展开设置,即开始展开动画 + } + } + } + } else { + //执行跳转动作 + jumpAction(); + } + this->update(); + } + return; +} + +void SingleMsg::mainMsgSetFold() +{ + //当消息为主窗口时,由主消息设置折叠 + if(true == m_bMain) + { + //置为true,表示折叠 + m_bAppFold = true; + setFoldFlag(true); + setBodyLabelWordWrap(false); + + //当剩余条数大于0, 且是折叠状态则显示剩余标签 + if(m_nShowLeftCount > 0) + { + m_pAppVLaout->setContentsMargins(0,0,0,0); //假如折叠,剩余条目显示将可见,则SingleMsg的内容均无空隙 + m_pShowLeftItemLabel->setVisible(true); + } + emit Sig_setAppFoldFlag(true); + + } +} + +//开启多消息展开时动画 +void SingleMsg::startAnimationUnfold() +{ + int width = this->width(); + int height = this->height(); + + if(true == m_strBody.isEmpty()) { + height = 87; + } else { + height = 111; + } + + m_pAppVLaout->removeWidget(m_pSingleWidget); + m_pAnimationBaseMapWidget->setFixedSize(width, 0); + m_pAnimationBaseMapWidget->setVisible(true); + m_pAppVLaout->addWidget(m_pAnimationBaseMapWidget, 0, Qt::AlignHCenter); + this->setVisible(true); + + //设置show动画 + QPropertyAnimation* pAnimation = new QPropertyAnimation(m_pSingleWidget, "geometry"); + pAnimation->setDuration(50); + connect(pAnimation, &QPropertyAnimation::valueChanged, this, &SingleMsg::updateUnfoldMove); + connect(pAnimation, SIGNAL(finished()), this, SLOT(onUnfoldFinish())); + + pAnimation->setStartValue(QRect(0, 0, width, height)); + pAnimation->setEndValue(QRect(0, height, width, height)); + pAnimation->start(QAbstractAnimation::DeleteWhenStopped); +} + +//开启多消息折叠时动画 +void SingleMsg::startAnimationFold() +{ + int width = this->width(); + int height = this->height(); + + m_pAnimationBaseMapWidget->setFixedSize(380, (height - 6)); + m_pAnimationBaseMapWidget->setVisible(true); + m_pAppVLaout->removeWidget(m_pSingleWidget); + m_pAppVLaout->addWidget(m_pAnimationBaseMapWidget, 0, Qt::AlignHCenter); + + //设置show动画 + QPropertyAnimation* pAnimation = new QPropertyAnimation(m_pSingleWidget, "geometry"); + pAnimation->setDuration(50); + connect(pAnimation, &QPropertyAnimation::valueChanged, this, &SingleMsg::updateFoldMove); + connect(pAnimation, SIGNAL(finished()), this, SLOT(onFoldFinish())); + + pAnimation->setStartValue(QRect(0, 0, width, height)); + pAnimation->setEndValue(QRect(0, height, width, height)); + pAnimation->start(QAbstractAnimation::DeleteWhenStopped); +} + +//开启删除左移动画 +void SingleMsg::startAnimationDeleLeftMove() +{ + int nWidth = this->width(); + int nHeight = this->height(); + QDateTime currentDateTime(QDateTime::currentDateTime()); + QString strCurrentTime = currentDateTime.toString("hh:mm:ss.zzz"); + + nHeight = nHeight - 6; //减去底部6px的空白区域,得出动画框体偏移高度 + + m_pAppVLaout->removeWidget(m_pSingleWidget); + m_pAnimationBaseMapWidget->setFixedSize(nWidth, nHeight); + m_pAnimationBaseMapWidget->setVisible(true); + m_pAppVLaout->addWidget(m_pAnimationBaseMapWidget, 0, Qt::AlignHCenter); + + //设置show动画 + QPropertyAnimation* pAnimation = new QPropertyAnimation(m_pSingleWidget, "geometry"); + pAnimation->setDuration(150); + connect(pAnimation, &QPropertyAnimation::valueChanged, this, &SingleMsg::updateDeleLeftMove); + connect(pAnimation, SIGNAL(finished()), this, SLOT(onDeleLeftMoveFinish())); + + pAnimation->setStartValue(QRect(0, 0, nWidth, nHeight)); + pAnimation->setEndValue(QRect(0 - nWidth, 0, nWidth, nHeight)); + pAnimation->start(QAbstractAnimation::DeleteWhenStopped); + +} + +//开启删除上移动画 +void SingleMsg::startAnimationDeleUpperMove() +{ + int width = this->width(); + int height = this->height(); + + //设置show动画 + QPropertyAnimation* pAnimation = new QPropertyAnimation(m_pAnimationBaseMapWidget, "geometry"); + pAnimation->setDuration(150); + connect(pAnimation, &QPropertyAnimation::valueChanged, this, &SingleMsg::updateDeleUpperMove); + connect(pAnimation, SIGNAL(finished()), this, SLOT(onDeleUpperMoveFinish())); + + pAnimation->setStartValue(QRect(0, 0, width, height)); + pAnimation->setEndValue(QRect(0, 0 - height, width, height)); + pAnimation->start(QAbstractAnimation::DeleteWhenStopped); +} + +//通知中心或者收纳盒中的删除 +void SingleMsg::onDele() +{ + if((true == m_bMain) && (true == m_bAppFold) && (m_nShowLeftCount > 0)) + { + m_pAppVLaout->setContentsMargins(0,0,0,6); + emit Sig_notifyAppHideBaseMap(); //通知隐藏应用的底图部件,但保留显示底部6px的空白 + } + + + m_pSetDeleDelayTimer->setSingleShot(true); //设置一个单次定时器,只为延迟2毫秒执行删除 + connect(m_pSetDeleDelayTimer, SIGNAL(timeout()), this, SLOT(startAnimationDeleLeftMove())); + m_pSetDeleDelayTimer->start(2); + + return; +} + +//通知中心消息收纳至收纳盒 +void SingleMsg::onTakeIn() +{ + if((true == m_bMain) && (true == m_bAppFold) && (m_nShowLeftCount > 0)) + { + emit Sig_onTakeinWholeApp(); + } + else + { + emit Sig_onTakeInSingleMsg(this); + } + + return; +} + +//收纳盒消息恢复至通知中心 +void SingleMsg::onRecover() +{ + if((true == m_bMain) && (true == m_bAppFold) && (m_nShowLeftCount > 0)) + { + emit Sig_onRecoverWholeApp(); + } + else + { + emit Sig_onRecoverSingleMsg(this); + } + + return; +} + +//更新展开的移动数据 +void SingleMsg::updateUnfoldMove(const QVariant &value) +{ + QRect Rect = value.value(); + int x1, y1, x2, y2; + Rect.getRect(&x1, &y1, &x2, &y2); + + QDateTime currentDateTime(QDateTime::currentDateTime()); + QString strCurrentTime = currentDateTime.toString("hh:mm:ss.zzz"); +// qDebug()< +#include +#include + +TakeInBoxToolButton::TakeInBoxToolButton() +{ + m_bEnterTakeInBox = false; + setAutoRaise(true); + setProperty("isWindowButton",0x1); +} + +void TakeInBoxToolButton::enterEvent(QEvent *event) +{ + Q_UNUSED(event); + setIconSize(QSize(24,24)); + //设置边框, 边框色, 背景色, 字体色, 字号 + if (false == m_bEnterTakeInBox) { + setIcon(QIcon(":/images/box-24-hover.svg")); + this->setToolTip((tr("Enter unimportant news"))); + + } else { + setIcon(QIcon(":/images/exitbox-24-hover.svg")); + } + return; +} + +void TakeInBoxToolButton::leaveEvent(QEvent *event) +{ + Q_UNUSED(event); + if (false == m_bEnterTakeInBox) { + setIcon(QIcon(":/images/box-24.svg")); + } else { + setIcon(QIcon(":/images/exitbox-24.svg")); + } + + return; +} + +//鼠标点击事件 +void TakeInBoxToolButton::mousePressEvent(QMouseEvent *event) +{ + + if (event->buttons() == Qt::LeftButton) { + setIconSize(QSize(20,20)); + if (false == m_bEnterTakeInBox) { + setIcon(QIcon(":/images/box-24-hover.svg")); + } else { + setIcon(QIcon(":/images/exitbox-24-hover.svg")); + } + } + + return; +} + +void TakeInBoxToolButton::mouseReleaseEvent(QMouseEvent *event) +{ + setIconSize(QSize(24,24)); + //设置边框, 边框色, 背景色, 字体色, 字号 + if (false == m_bEnterTakeInBox) { + setIcon(QIcon(":/images/box-24.svg")); + this->setToolTip((tr("Quit unimportant news"))); + } else { + setIcon(QIcon(":/images/exitbox-24.svg")); + this->setToolTip((tr("Enter unimportant news"))); + } + + int x = event->x(); + int y = event->y(); + //假如在QRect(0, 0, 24, 24));这个区域里,就发出信号 + if (x >= 0 && x <= 29 && y >= 0 && y<=29) { + emit Sig_clicked(); + } + return; +} + + diff --git a/src/plugins/ukui-sidebar-notification/takeinboxtoolbutton.h b/src/plugins/ukui-sidebar-notification/takeinboxtoolbutton.h new file mode 100644 index 0000000..2cb6652 --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/takeinboxtoolbutton.h @@ -0,0 +1,48 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include + +class TakeInBoxToolButton : public QToolButton +{ + Q_OBJECT +public: + explicit TakeInBoxToolButton(); + void setEnterFlags(bool bFlags) {m_bEnterTakeInBox = bFlags;} + +protected: + virtual void enterEvent(QEvent *event) override; + virtual void leaveEvent(QEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; + +private: + bool m_bEnterTakeInBox; + +signals: + void Sig_clicked(); + +}; + +#endif // TAKEINBOXTOOLBUTTON_H diff --git a/src/plugins/ukui-sidebar-notification/ukui-sidebar-notification.pro b/src/plugins/ukui-sidebar-notification/ukui-sidebar-notification.pro new file mode 100644 index 0000000..75de3cf --- /dev/null +++ b/src/plugins/ukui-sidebar-notification/ukui-sidebar-notification.pro @@ -0,0 +1,64 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2020-01-08T16:23:49 +# +#------------------------------------------------- + +QT += core gui widgets svg dbus + +TARGET = notification_plugin +TEMPLATE = lib +CONFIG += plugin \ + link_pkgconfig + +include(../../env.pri) + +PKGCONFIG += gsettings-qt \ + glib-2.0 +LIBS += -L$$[QT_INSTALL_LIBS] -ldconf + +DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + notificationDbus.cpp \ + notificationPlugin.cpp \ + appmsg.cpp \ + scrollareawidget.cpp \ + takeinboxtoolbutton.cpp \ + monitorthread.cpp \ + singlemsg.cpp \ + buttonwidget.cpp \ + customstylePushbutton2.cpp \ + picturetowhite.cpp \ + +INCLUDEPATH += ../../plugin-interface \ + /usr/include/dconf +HEADERS += \ + notificationDbus.h \ + notificationPlugin.h \ + appmsg.h \ + scrollareawidget.h \ + takeinboxtoolbutton.h \ + monitorthread.h \ + singlemsg.h \ + buttonwidget.h \ + customstylePushbutton2.h \ + picturetowhite.h \ + +DISTFILES += notificationPlugin.json + +unix { + target.path = $${PLUGIN_INSTALL_DIRS} + INSTALLS += target + + translation.path = /usr/share/ukui-sidebar/ukui-sidebar-notification + translation.files += ../../../translations/ukui-sidebar-notification/*.qm + INSTALLS += translation +} + +TRANSLATIONS += ../../../translations/ukui-sidebar-notification/ukui-sidebar-notification_zh_CN.ts \ + ../../../translations/ukui-sidebar-notification/ukui-sidebar-notification_bo_CN.ts \ + ../../../translations/ukui-sidebar-notification/ukui-sidebar-notification_tr.ts + +RESOURCES += \ + notificationPlugin.qrc diff --git a/src/pluginstoolbutton.cpp b/src/pluginstoolbutton.cpp new file mode 100644 index 0000000..244bd8a --- /dev/null +++ b/src/pluginstoolbutton.cpp @@ -0,0 +1,69 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +PluginsToolButton::PluginsToolButton(QWidget *parent) +{ + status = NORMAL; +} + +void PluginsToolButton::enterEvent(QEvent *e) +{ + status = HOVER; +} + +void PluginsToolButton::leaveEvent(QEvent *e) +{ + status = NORMAL; +} + +void PluginsToolButton::mousePressEvent(QMouseEvent *e) +{ + status = PRESS; +} + +void PluginsToolButton::paintEvent(QPaintEvent *e) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + switch (status) { + case NORMAL: { + p.setBrush(QBrush(QColor(opt.palette.color(QPalette::WindowText)))); + p.setOpacity(0.12); + p.setPen(Qt::NoPen); + break; + } + case HOVER: { + p.setBrush(QBrush(QColor(opt.palette.color(QPalette::WindowText)))); + p.setOpacity(0.2); + p.setPen(Qt::NoPen); + break; + } + case PRESS: { + p.setBrush(QBrush(QColor(opt.palette.color(QPalette::WindowText)))); + p.setOpacity(0.08); + p.setPen(Qt::NoPen); + break; + } + } + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.drawRoundedRect(opt.rect,4,4); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} diff --git a/src/pluginstoolbutton.h b/src/pluginstoolbutton.h new file mode 100644 index 0000000..1f9f572 --- /dev/null +++ b/src/pluginstoolbutton.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +class PluginsToolButton : public QToolButton +{ +public: + explicit PluginsToolButton(QWidget *parent = nullptr); + enum SidebarButtonStatus{NORMAL, HOVER, PRESS}; + SidebarButtonStatus status; +protected: + void enterEvent(QEvent *e); //鼠标进入事件 + void leaveEvent(QEvent *e); //鼠标离开事件 + void mousePressEvent(QMouseEvent *e); //按钮点击事件 + void paintEvent(QPaintEvent *e); +}; + +#endif // PLUGINSTOOLBUTTON_H diff --git a/src/qtlocalpeer.cpp b/src/qtlocalpeer.cpp new file mode 100644 index 0000000..c7ce527 --- /dev/null +++ b/src/qtlocalpeer.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qtlocalpeer.h" +#include +#include +#include + +#if defined(Q_OS_WIN) +#include +#include +typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); +static PProcessIdToSessionId pProcessIdToSessionId = 0; +#endif +#if defined(Q_OS_UNIX) +#include +#include +#include +#endif + +namespace QtLP_Private { +#include "qtlockedfile.cpp" +#if defined(Q_OS_WIN) +#include "qtlockedfile_win.cpp" +#else +#include "qtlockedfile_unix.cpp" +#endif +} + +const char* QtLocalPeer::ack = "ack"; + +QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) + : QObject(parent), id(appId) +{ + QString prefix = id; + if (id.isEmpty()) { + id = QCoreApplication::applicationFilePath(); +#if defined(Q_OS_WIN) + id = id.toLower(); +#endif + prefix = id.section(QLatin1Char('/'), -1); + } + prefix.remove(QRegExp("[^a-zA-Z]")); + prefix.truncate(6); + + QByteArray idc = id.toUtf8(); + quint16 idNum = qChecksum(idc.constData(), idc.size()); + socketName = QLatin1String("qtsingleapp-") + prefix + + QLatin1Char('-') + QString::number(idNum, 16); + +#if defined(Q_OS_WIN) + if (!pProcessIdToSessionId) { + QLibrary lib("kernel32"); + pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); + } + if (pProcessIdToSessionId) { + DWORD sessionId = 0; + pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); + socketName += QLatin1Char('-') + QString::number(sessionId, 16); + } +#else + socketName += QLatin1Char('-') + QString::number(::getuid(), 16); +#endif + + server = new QLocalServer(this); + QString lockName = QDir(QDir::tempPath()).absolutePath() + + QLatin1Char('/') + socketName + + QLatin1String("-lockfile"); + lockFile.setFileName(lockName); + lockFile.open(QIODevice::ReadWrite); +} + + + +bool QtLocalPeer::isClient() +{ + if (lockFile.isLocked()) + return false; + + if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) + return true; + + bool res = server->listen(socketName); +#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) + // ### Workaround + if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { + QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName); + res = server->listen(socketName); + } +#endif + if (!res) + qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); + QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection())); + return false; +} + + +bool QtLocalPeer::sendMessage(const QString &message, int timeout) +{ + if (!isClient()) + return false; + + QLocalSocket socket; + bool connOk = false; + for(int i = 0; i < 2; i++) { + // Try twice, in case the other instance is just starting up + socket.connectToServer(socketName); + connOk = socket.waitForConnected(timeout/2); + if (connOk || i) + break; + int ms = 250; +#if defined(Q_OS_WIN) + Sleep(DWORD(ms)); +#else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, NULL); +#endif + } + if (!connOk) + return false; + + QByteArray uMsg(message.toUtf8()); + QDataStream ds(&socket); + ds.writeBytes(uMsg.constData(), uMsg.size()); + bool res = socket.waitForBytesWritten(timeout); + if (res) { + res &= socket.waitForReadyRead(timeout); // wait for ack + if (res) + res &= (socket.read(qstrlen(ack)) == ack); + } + return res; +} + + +void QtLocalPeer::receiveConnection() +{ + QLocalSocket* socket = server->nextPendingConnection(); + if (!socket) + return; + + while (socket->bytesAvailable() < (int)sizeof(quint32)) + socket->waitForReadyRead(); + QDataStream ds(socket); + QByteArray uMsg; + quint32 remaining; + ds >> remaining; + uMsg.resize(remaining); + int got = 0; + char* uMsgBuf = uMsg.data(); + do { + got = ds.readRawData(uMsgBuf, remaining); + remaining -= got; + uMsgBuf += got; + } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); + if (got < 0) { + qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); + delete socket; + return; + } + QString message(QString::fromUtf8(uMsg)); + socket->write(ack, qstrlen(ack)); + socket->waitForBytesWritten(1000); + socket->waitForDisconnected(1000); // make sure client reads ack + delete socket; + emit messageReceived(message); //### (might take a long time to return) +} diff --git a/src/qtlocalpeer.h b/src/qtlocalpeer.h new file mode 100644 index 0000000..1b533b1 --- /dev/null +++ b/src/qtlocalpeer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTLOCALPEER_H +#define QTLOCALPEER_H + +#include +#include +#include + +#include "qtlockedfile.h" + +class QtLocalPeer : public QObject +{ + Q_OBJECT + +public: + QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); + bool isClient(); + bool sendMessage(const QString &message, int timeout); + QString applicationId() const + { return id; } + +Q_SIGNALS: + void messageReceived(const QString &message); + +protected Q_SLOTS: + void receiveConnection(); + +protected: + QString id; + QString socketName; + QLocalServer* server; + QtLP_Private::QtLockedFile lockFile; + +private: + static const char* ack; +}; + +#endif // QTLOCALPEER_H diff --git a/src/qtlockedfile.cpp b/src/qtlockedfile.cpp new file mode 100644 index 0000000..c142a86 --- /dev/null +++ b/src/qtlockedfile.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtlockedfile.h" + +/*! + \class QtLockedFile + + \brief The QtLockedFile class extends QFile with advisory locking + functions. + + A file may be locked in read or write mode. Multiple instances of + \e QtLockedFile, created in multiple processes running on the same + machine, may have a file locked in read mode. Exactly one instance + may have it locked in write mode. A read and a write lock cannot + exist simultaneously on the same file. + + The file locks are advisory. This means that nothing prevents + another process from manipulating a locked file using QFile or + file system functions offered by the OS. Serialization is only + guaranteed if all processes that access the file use + QLockedFile. Also, while holding a lock on a file, a process + must not open the same file again (through any API), or locks + can be unexpectedly lost. + + The lock provided by an instance of \e QtLockedFile is released + whenever the program terminates. This is true even when the + program crashes and no destructors are called. +*/ + +/*! \enum QtLockedFile::LockMode + + This enum describes the available lock modes. + + \value ReadLock A read lock. + \value WriteLock A write lock. + \value NoLock Neither a read lock nor a write lock. +*/ + +/*! + Constructs an unlocked \e QtLockedFile object. This constructor + behaves in the same way as \e QFile::QFile(). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile() + : QFile() +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Constructs an unlocked QtLockedFile object with file \a name. This + constructor behaves in the same way as \e QFile::QFile(const + QString&). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile(const QString &name) + : QFile(name) +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Opens the file in OpenMode \a mode. + + This is identical to QFile::open(), with the one exception that the + Truncate mode flag is disallowed. Truncation would conflict with the + advisory file locking, since the file would be modified before the + write lock is obtained. If truncation is required, use resize(0) + after obtaining the write lock. + + Returns true if successful; otherwise false. + + \sa QFile::open(), QFile::resize() +*/ +bool QtLockedFile::open(OpenMode mode) +{ + if (mode & QIODevice::Truncate) { + qWarning("QtLockedFile::open(): Truncate mode not allowed."); + return false; + } + return QFile::open(mode); +} + +/*! + Returns \e true if this object has a in read or write lock; + otherwise returns \e false. + + \sa lockMode() +*/ +bool QtLockedFile::isLocked() const +{ + return m_lock_mode != NoLock; +} + +/*! + Returns the type of lock currently held by this object, or \e + QtLockedFile::NoLock. + + \sa isLocked() +*/ +QtLockedFile::LockMode QtLockedFile::lockMode() const +{ + return m_lock_mode; +} + +/*! + \fn bool QtLockedFile::lock(LockMode mode, bool block = true) + + Obtains a lock of type \a mode. The file must be opened before it + can be locked. + + If \a block is true, this function will block until the lock is + aquired. If \a block is false, this function returns \e false + immediately if the lock cannot be aquired. + + If this object already has a lock of type \a mode, this function + returns \e true immediately. If this object has a lock of a + different type than \a mode, the lock is first released and then a + new lock is obtained. + + This function returns \e true if, after it executes, the file is + locked by this object, and \e false otherwise. + + \sa unlock(), isLocked(), lockMode() +*/ + +/*! + \fn bool QtLockedFile::unlock() + + Releases a lock. + + If the object has no lock, this function returns immediately. + + This function returns \e true if, after it executes, the file is + not locked by this object, and \e false otherwise. + + \sa lock(), isLocked(), lockMode() +*/ + +/*! + \fn QtLockedFile::~QtLockedFile() + + Destroys the \e QtLockedFile object. If any locks were held, they + are released. +*/ diff --git a/src/qtlockedfile.h b/src/qtlockedfile.h new file mode 100644 index 0000000..84c18e5 --- /dev/null +++ b/src/qtlockedfile.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTLOCKEDFILE_H +#define QTLOCKEDFILE_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#if defined(Q_OS_WIN) +# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) +# define QT_QTLOCKEDFILE_EXPORT +# elif defined(QT_QTLOCKEDFILE_IMPORT) +# if defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# endif +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) +# elif defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTLOCKEDFILE_EXPORT +#endif + +namespace QtLP_Private { + +class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile +{ +public: + enum LockMode { NoLock = 0, ReadLock, WriteLock }; + + QtLockedFile(); + QtLockedFile(const QString &name); + ~QtLockedFile(); + + bool open(OpenMode mode); + + bool lock(LockMode mode, bool block = true); + bool unlock(); + bool isLocked() const; + LockMode lockMode() const; + +private: +#ifdef Q_OS_WIN + Qt::HANDLE wmutex; + Qt::HANDLE rmutex; + QVector rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; +} +#endif diff --git a/src/qtlockedfile_unix.cpp b/src/qtlockedfile_unix.cpp new file mode 100644 index 0000000..976c1b9 --- /dev/null +++ b/src/qtlockedfile_unix.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qtlockedfile.h" + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; + int cmd = block ? F_SETLKW : F_SETLK; + int ret = fcntl(handle(), cmd, &fl); + + if (ret == -1) { + if (errno != EINTR && errno != EAGAIN) + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + + m_lock_mode = mode; + return true; +} + + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_UNLCK; + int ret = fcntl(handle(), F_SETLKW, &fl); + + if (ret == -1) { + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + m_lock_mode = NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); +} + diff --git a/src/qtsingleapplication.cpp b/src/qtsingleapplication.cpp new file mode 100644 index 0000000..d0fb15d --- /dev/null +++ b/src/qtsingleapplication.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qtsingleapplication.h" +#include "qtlocalpeer.h" +#include + + +/*! + \class QtSingleApplication qtsingleapplication.h + \brief The QtSingleApplication class provides an API to detect and + communicate with running instances of an application. + + This class allows you to create applications where only one + instance should be running at a time. I.e., if the user tries to + launch another instance, the already running instance will be + activated instead. Another usecase is a client-server system, + where the first started instance will assume the role of server, + and the later instances will act as clients of that server. + + By default, the full path of the executable file is used to + determine whether two processes are instances of the same + application. You can also provide an explicit identifier string + that will be compared instead. + + The application should create the QtSingleApplication object early + in the startup phase, and call isRunning() to find out if another + instance of this application is already running. If isRunning() + returns false, it means that no other instance is running, and + this instance has assumed the role as the running instance. In + this case, the application should continue with the initialization + of the application user interface before entering the event loop + with exec(), as normal. + + The messageReceived() signal will be emitted when the running + application receives messages from another instance of the same + application. When a message is received it might be helpful to the + user to raise the application so that it becomes visible. To + facilitate this, QtSingleApplication provides the + setActivationWindow() function and the activateWindow() slot. + + If isRunning() returns true, another instance is already + running. It may be alerted to the fact that another instance has + started by using the sendMessage() function. Also data such as + startup parameters (e.g. the name of the file the user wanted this + new instance to open) can be passed to the running instance with + this function. Then, the application should terminate (or enter + client mode). + + If isRunning() returns true, but sendMessage() fails, that is an + indication that the running instance is frozen. + + Here's an example that shows how to convert an existing + application to use QtSingleApplication. It is very simple and does + not make use of all QtSingleApplication's functionality (see the + examples for that). + + \code + // Original + int main(int argc, char **argv) + { + QApplication app(argc, argv); + + MyMainWidget mmw; + mmw.show(); + return app.exec(); + } + + // Single instance + int main(int argc, char **argv) + { + QtSingleApplication app(argc, argv); + + if (app.isRunning()) + return !app.sendMessage(someDataString); + + MyMainWidget mmw; + app.setActivationWindow(&mmw); + mmw.show(); + return app.exec(); + } + \endcode + + Once this QtSingleApplication instance is destroyed (normally when + the process exits or crashes), when the user next attempts to run the + application this instance will not, of course, be encountered. The + next instance to call isRunning() or sendMessage() will assume the + role as the new running instance. + + For console (non-GUI) applications, QtSingleCoreApplication may be + used instead of this class, to avoid the dependency on the QtGui + library. + + \sa QtSingleCoreApplication +*/ + + +void QtSingleApplication::sysInit(const QString &appId) +{ + actWin = 0; + peer = new QtLocalPeer(this, appId); + connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); +} + + +/*! + Creates a QtSingleApplication object. The application identifier + will be QCoreApplication::applicationFilePath(). \a argc, \a + argv, and \a GUIenabled are passed on to the QAppliation constructor. + + If you are creating a console application (i.e. setting \a + GUIenabled to false), you may consider using + QtSingleCoreApplication instead. +*/ + +QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) + : QApplication(argc, argv, GUIenabled) +{ + sysInit(); +} + + +/*! + Creates a QtSingleApplication object with the application + identifier \a appId. \a argc and \a argv are passed on to the + QAppliation constructor. +*/ + +QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) + : QApplication(argc, argv) +{ + sysInit(appId); +} + +#if QT_VERSION < 0x050000 + +/*! + Creates a QtSingleApplication object. The application identifier + will be QCoreApplication::applicationFilePath(). \a argc, \a + argv, and \a type are passed on to the QAppliation constructor. +*/ +QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type) + : QApplication(argc, argv, type) +{ + sysInit(); +} + + +# if defined(Q_WS_X11) +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be QCoreApplication::applicationFilePath(). \a dpy, \a visual, + and \a cmap are passed on to the QApplication constructor. +*/ +QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, visual, cmap) +{ + sysInit(); +} + +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a + argv, \a visual, and \a cmap are passed on to the QApplication + constructor. +*/ +QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, argc, argv, visual, cmap) +{ + sysInit(); +} + +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be \a appId. \a dpy, \a argc, \a + argv, \a visual, and \a cmap are passed on to the QApplication + constructor. +*/ +QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, argc, argv, visual, cmap) +{ + sysInit(appId); +} +# endif // Q_WS_X11 +#endif // QT_VERSION < 0x050000 + + +/*! + Returns true if another instance of this application is running; + otherwise false. + + This function does not find instances of this application that are + being run by a different user (on Windows: that are running in + another session). + + \sa sendMessage() +*/ + +bool QtSingleApplication::isRunning() +{ + return peer->isClient(); +} + + +/*! + Tries to send the text \a message to the currently running + instance. The QtSingleApplication object in the running instance + will emit the messageReceived() signal when it receives the + message. + + This function returns true if the message has been sent to, and + processed by, the current instance. If there is no instance + currently running, or if the running instance fails to process the + message within \a timeout milliseconds, this function return false. + + \sa isRunning(), messageReceived() +*/ +bool QtSingleApplication::sendMessage(const QString &message, int timeout) +{ + return peer->sendMessage(message, timeout); +} + + +/*! + Returns the application identifier. Two processes with the same + identifier will be regarded as instances of the same application. +*/ +QString QtSingleApplication::id() const +{ + return peer->applicationId(); +} + + +/*! + Sets the activation window of this application to \a aw. The + activation window is the widget that will be activated by + activateWindow(). This is typically the application's main window. + + If \a activateOnMessage is true (the default), the window will be + activated automatically every time a message is received, just prior + to the messageReceived() signal being emitted. + + \sa activateWindow(), messageReceived() +*/ + +void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) +{ + actWin = aw; + if (activateOnMessage) + connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); + else + disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); +} + + +/*! + Returns the applications activation window if one has been set by + calling setActivationWindow(), otherwise returns 0. + + \sa setActivationWindow() +*/ +QWidget* QtSingleApplication::activationWindow() const +{ + return actWin; +} + + +/*! + De-minimizes, raises, and activates this application's activation window. + This function does nothing if no activation window has been set. + + This is a convenience function to show the user that this + application instance has been activated when he has tried to start + another instance. + + This function should typically be called in response to the + messageReceived() signal. By default, that will happen + automatically, if an activation window has been set. + + \sa setActivationWindow(), messageReceived(), initialize() +*/ +void QtSingleApplication::activateWindow() +{ + if (actWin) { + actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); + actWin->raise(); + actWin->activateWindow(); + } +} + + +/*! + \fn void QtSingleApplication::messageReceived(const QString& message) + + This signal is emitted when the current instance receives a \a + message from another instance of this application. + + \sa sendMessage(), setActivationWindow(), activateWindow() +*/ + + +/*! + \fn void QtSingleApplication::initialize(bool dummy = true) + + \obsolete +*/ diff --git a/src/qtsingleapplication.h b/src/qtsingleapplication.h new file mode 100644 index 0000000..049406f --- /dev/null +++ b/src/qtsingleapplication.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTSINGLEAPPLICATION_H +#define QTSINGLEAPPLICATION_H + +#include + +class QtLocalPeer; + +#if defined(Q_OS_WIN) +# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT) +# define QT_QTSINGLEAPPLICATION_EXPORT +# elif defined(QT_QTSINGLEAPPLICATION_IMPORT) +# if defined(QT_QTSINGLEAPPLICATION_EXPORT) +# undef QT_QTSINGLEAPPLICATION_EXPORT +# endif +# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport) +# elif defined(QT_QTSINGLEAPPLICATION_EXPORT) +# undef QT_QTSINGLEAPPLICATION_EXPORT +# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTSINGLEAPPLICATION_EXPORT +#endif + +class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication +{ + Q_OBJECT + +public: + QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); + QtSingleApplication(const QString &id, int &argc, char **argv); +#if QT_VERSION < 0x050000 + QtSingleApplication(int &argc, char **argv, Type type); +# if defined(Q_WS_X11) + QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); + QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0); + QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); +# endif // Q_WS_X11 +#endif // QT_VERSION < 0x050000 + + bool isRunning(); + QString id() const; + + void setActivationWindow(QWidget* aw, bool activateOnMessage = true); + QWidget* activationWindow() const; + + // Obsolete: + void initialize(bool dummy = true) + { isRunning(); Q_UNUSED(dummy) } + +public Q_SLOTS: + bool sendMessage(const QString &message, int timeout = 5000); + void activateWindow(); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + void sysInit(const QString &appId = QString()); + QtLocalPeer *peer; + QWidget *actWin; +}; + +#endif // QTSINGLEAPPLICATION_H diff --git a/src/sidebar.qrc b/src/sidebar.qrc new file mode 100644 index 0000000..3dfafe8 --- /dev/null +++ b/src/sidebar.qrc @@ -0,0 +1,13 @@ + + + data/qss/psblack.css + data/qss/SidebarSmallPlugins.css + data/images/kylin-tool-box.svg + data/images/kylin-tool-box-null.svg + data/images/kylin-alarm-clock.svg + data/images/kylin-notebook.svg + data/images/kylin-feedback.png + data/images/application-menu.svg + data/org.ukui.log4qt.ukui-sidebar.gschema.xml + + diff --git a/src/sidebarAppLog.cpp b/src/sidebarAppLog.cpp new file mode 100644 index 0000000..2825878 --- /dev/null +++ b/src/sidebarAppLog.cpp @@ -0,0 +1,96 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +static int s_logLevel = QtDebugMsg; + +void setLogPath(const QString & path) +{ + s_logPath = path; + qDebug() << "path ::::" << s_logPath; +} + +void setLogLevel(int level) +{ + s_logLevel = level; +} + +bool static ensureDirExist(const QString &dirPath) +{ + QDir dir(dirPath); + if (dir.exists()) + { + return true; + } + + return dir.mkpath(dirPath); +} + +void customLogMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + Q_UNUSED(context); + if (type < s_logLevel) + { + return; + } + + QString logInfo; + QString logTime = QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"); + switch (type) + { + case QtDebugMsg: + logInfo = QString("%1 [Debug] %2 %3 %4 %5").arg(logTime, context.file, QString::number(context.line), context.function, msg); + break; + + case QtWarningMsg: + logInfo = QString("%1 [Warning] %2 %3 %4 %5").arg(logTime, context.file, QString::number(context.line), context.function, msg); + break; + + case QtCriticalMsg: + logInfo = QString("%1 [Critical] %2 %3 %4 %5").arg(logTime, context.file, QString::number(context.line), context.function, msg); + break; + + case QtFatalMsg: + logInfo = QString("%1 [Fatal] %2 %3 %4 %5").arg(logTime, context.file, QString::number(context.line), context.function, msg); + abort(); + case QtInfoMsg: + logInfo = QString("%1 [Info] %2 %3 %4 %5").arg(logTime, context.file, QString::number(context.line), context.function, msg); + break; + } + + s_logMutex.lock(); + QFile outFile(s_logPath); + QFileInfo fileInfo(outFile); + if (!ensureDirExist(fileInfo.absoluteDir().absolutePath())) + return; + + if (!outFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) + return; + + QTextStream ts(&outFile); + ts << logInfo.toUtf8() << endl; + outFile.close(); + s_logMutex.unlock(); +} diff --git a/src/sidebarAppLog.h b/src/sidebarAppLog.h new file mode 100644 index 0000000..77a1ad6 --- /dev/null +++ b/src/sidebarAppLog.h @@ -0,0 +1,31 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include + +#define LOG_FILE_NAME QString("/.config/ukui/ukui-sidebar-Log/") + QDateTime::currentDateTime().toString("yyyy-MM-dd") + QString(".log") + + +static QMutex s_logMutex; +static QString s_logPath; + +void setLogPath(const QString &path); +void setLogLevel(int level); +void customLogMessageHandler(QtMsgType type, const QMessageLogContext& ctx, const QString& msg); diff --git a/src/sidebarDbusService.cpp b/src/sidebarDbusService.cpp new file mode 100644 index 0000000..4691aeb --- /dev/null +++ b/src/sidebarDbusService.cpp @@ -0,0 +1,30 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +SidebarDbusService::SidebarDbusService(QWidget *parent) +{ + m_parent = parent; +} + +int SidebarDbusService::getWidth() +{ + return m_sidebarWidth; +} diff --git a/src/sidebarDbusService.h b/src/sidebarDbusService.h new file mode 100644 index 0000000..e5d1a25 --- /dev/null +++ b/src/sidebarDbusService.h @@ -0,0 +1,44 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include + +class SidebarDbusService: public QObject +{ + Q_OBJECT + //申明该类有D-BUS服务接口 + Q_CLASSINFO("D-Bus Interface", "org.ukui.Sidebar") +public: + SidebarDbusService(QWidget *parent = nullptr); + int m_sidebarWidth; // 侧边栏宽度 + bool sidebarState; //展开中/展开完成-true; + +private: + QWidget *m_parent; +public slots: + int getWidth(); //获取侧边栏当前位置 +signals: + void animationAction(const uint time, const int distance); +}; + +#endif // SIDEBARDBUSSERVICE_H diff --git a/src/sidebarpluginswidgets.cpp b/src/sidebarpluginswidgets.cpp new file mode 100644 index 0000000..8e72852 --- /dev/null +++ b/src/sidebarpluginswidgets.cpp @@ -0,0 +1,641 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include + +extern double tranSparency; + +static sidebarPluginsWidgets *global_Plugin_Widgets_instance = nullptr; + +m_ToolButton::m_ToolButton() +{ + +} + +void m_ToolButton::enterEvent(QEvent *event) +{ + char* charname ; + QByteArray ba = pluginname.toLocal8Bit(); + charname =ba.data(); + this->setToolTip((tr(charname))); + return; +} + +sidebarPluginsWidgets::sidebarPluginsWidgets(QWidget *parent) : QWidget(parent) +{ + Q_UNUSED(parent); + + this->setContentsMargins(0,0,0,0); + this->setFixedSize(400,300); + this->setStyleSheet("QWidget{background:rgba(255, 255, 0, 0);}"); + + m_pWidgetOutVLayout = new QVBoxLayout(); + m_pWidgetOutVLayout->setContentsMargins(0,0,0,0); + + /* 上半部分 剪贴板 小插件 俩按钮 groupBox初始化布局 */ + initUpGroupBoxButton(); + + /* 下半部分 显示插件的界面 */ + initUnGroupBox(); + + initLableBackgroundAnimation(); + initSmallPluginsAnimation(); //初始化小插件动画类 + + /* 初始化desktop文件名称放入链表中 */ + addDesktopFileName(); + + /* 将闹钟、用户反馈等图标加入到界面 */ + parsingDesktopFile(); + + QFile file(KYLIN_SIDEBAR_SMALL_PLUGINS); + if (file.open(QFile::ReadOnly)) { + QString strQss = QLatin1String(file.readAll()); + this->setStyleSheet(strQss); + file.close(); + } +} + +sidebarPluginsWidgets::~sidebarPluginsWidgets() +{ + +} + +/* 返回全局的Widget指针 */ +sidebarPluginsWidgets* sidebarPluginsWidgets::getInstancePluinsWidgets() +{ + if (global_Plugin_Widgets_instance == nullptr) { + global_Plugin_Widgets_instance = new sidebarPluginsWidgets(); + } + return global_Plugin_Widgets_instance; +} + +/* 初始化sidebarPluginsWidgets类 */ +void sidebarPluginsWidgets::initPluginsWidgets() +{ + getInstancePluinsWidgets(); + return; +} + +/* 上半部分 剪贴板 小插件 俩按钮 groupBox初始化布局 */ +void sidebarPluginsWidgets::initUpGroupBoxButton() +{ + m_pButtonWidget = new QWidget(this); + m_pButtonWidget->setContentsMargins(0,0,0,0); + m_pButtonWidget->setFixedSize(400, 60); + + m_pGrouBoxUpButtonHLayout = new QHBoxLayout; + m_pGrouBoxUpButtonHLayout->setContentsMargins(0,5,0,0); + + //剪贴板按钮 + m_pClipboardButton = new SmallPluginsButton(); + m_pClipboardButton->setText(tr("Clipboard")); + m_pClipboardButton->setObjectName("ClipboardButton"); + m_pClipboardButton->setMinimumWidth(110); + m_pClipboardButton->setFixedHeight(34); + connect(m_pClipboardButton, &SmallPluginsButton::clicked, this, &sidebarPluginsWidgets::m_ClipboardButtonSlots); + + //小插件按钮 + m_pSidebarPluginButton = new SmallPluginsButton(); + m_pSidebarPluginButton->setText(tr("Plugins")); + m_pSidebarPluginButton->setObjectName("SidebarPluginButton"); + m_pSidebarPluginButton->setFixedSize(110,34); + connect(m_pSidebarPluginButton, &SmallPluginsButton::clicked, this, &sidebarPluginsWidgets::m_SidebarPluginButtonSlots); + + setClipboardButtonBackgroundIsBlue(); + setSmallPluginsButtonBackgroudIsBlank(); + + m_pFoldButton = new QPushButton(QObject::tr("折叠")); + m_pFoldButton->setFixedSize(90, 34); + m_pSpreadButton = new QPushButton(QObject::tr("展开")); + m_pSpreadButton->setFixedSize(90, 34); + m_pSpreadButton->setVisible(false); + + connect(m_pFoldButton, &QPushButton::clicked, this, &sidebarPluginsWidgets::m_pFoldButtonSlots); + connect(m_pSpreadButton, &QPushButton::clicked, this, &sidebarPluginsWidgets::m_pSpreadButtonSlots); + + //蓝色背景块按钮 + m_pBlueBackgroundButton = new QPushButton(); + m_pBlueBackgroundButton->setFixedSize(110, 34); + m_pBlueBackgroundButton->setObjectName("BlueBackgroundButton"); + m_pBlueBackgroundButton->setChecked(false); + + m_pBlueBackgroundButton->setVisible(false); + + m_pGrouBoxUpButtonHLayout->addItem(new QSpacerItem(10, 20)); + m_pGrouBoxUpButtonHLayout->addWidget(m_pClipboardButton); + m_pGrouBoxUpButtonHLayout->addItem(new QSpacerItem(10, 20)); + m_pGrouBoxUpButtonHLayout->addWidget(m_pSidebarPluginButton); + m_pGrouBoxUpButtonHLayout->addItem(new QSpacerItem(0, 20)); + m_pGrouBoxUpButtonHLayout->addWidget(m_pBlueBackgroundButton); + m_pGrouBoxUpButtonHLayout->addItem(new QSpacerItem(200, 20, QSizePolicy::Expanding)); + m_pButtonWidget->setLayout(m_pGrouBoxUpButtonHLayout); + m_pGrouBoxUpButtonHLayout->setSpacing(0); + return; +} + +/* 显示插件的界面下半部分 */ +void sidebarPluginsWidgets::initUnGroupBox() +{ + /* 小插件GroupBox指针 */ + m_pPluginsButtonWidget = new QWidget(); + m_pPluginsButtonWidget->setFixedSize(400, 250); + m_pPluginsButtonWidget->setContentsMargins(0,0,0,0); + + /* 设置按钮图表 */ + m_pGroupBoxUnSmallPluginsGLayout = new QGridLayout(); + m_pPluginsButtonWidget->setLayout(m_pGroupBoxUnSmallPluginsGLayout); + m_pGroupBoxUnSmallPluginsGLayout->setSpacing(0); + return; +} + + +/* 最后将所有空间加入到Widget中 */ +void sidebarPluginsWidgets::AddPluginWidgetInterface() +{ + m_pstackWidget = new QStackedWidget(); + m_pstackWidget->setContentsMargins(0, 0, 0, 0); + m_pstackWidget->addWidget(m_pClipboardWidget); //剪贴板Widget + m_pstackWidget->addWidget(m_pPluginsButtonWidget); //显示小插件的Widget + m_pWidgetOutVLayout->addWidget(m_pButtonWidget); //加载俩个按钮界面 + m_pWidgetOutVLayout->addWidget(m_pstackWidget); + m_pWidgetOutVLayout->setSpacing(0); + this->setLayout(m_pWidgetOutVLayout); + return; +} + +/* 移动到剪贴板按钮需要修改的界面 */ +void sidebarPluginsWidgets::m_pClipBoardStateSlots() +{ + m_pBlueBackgroundButton->setVisible(false); + setClipboardButtonBackgroundIsBlue(); + setSmallPluginsButtonBackgroudIsBlank(); + return; +} + +/* 移动到小插件界面按钮需要做的界面修改 */ +void sidebarPluginsWidgets::m_pSmallPluginsStateSlots() +{ + m_pBlueBackgroundButton->setVisible(false); + setClipboardButtonBackgroundIsBlank(); + setSmallPluginsButtonBackgroudIsBlue(); + return; +} + +/* 剪贴板按钮槽函数 */ +void sidebarPluginsWidgets::m_ClipboardButtonSlots() +{ + if (!ClipBoardBool) { + setSmallPluginsButtonBackgroudIsBlank(); + m_pstackWidget->setCurrentIndex(0); + m_pAnimationClipbarod->start(); + m_pBlueBackgroundButton->setVisible(true); + m_pAnimationRightLeft->start(); + SmallPluginsBool = false; + ClipBoardBool = true; + } + return; +} + +/* 小插件按钮槽函数 */ +void sidebarPluginsWidgets::m_SidebarPluginButtonSlots() +{ + if (!SmallPluginsBool) { + setClipboardButtonBackgroundIsBlank(); + m_pstackWidget->setCurrentIndex(1); + m_pAnimationSmallWidget->start(); + m_pBlueBackgroundButton->setVisible(true); + m_pAnimationLeftRight->start(); + ClipBoardBool = false; + SmallPluginsBool = true; + } + return; +} + +/* 折叠按钮槽函数 */ +void sidebarPluginsWidgets::m_pFoldButtonSlots() +{ + m_pstackWidget->hide(); + this->setFixedSize(400, 60); + m_pSpreadButton->setVisible(true); + m_pFoldButton->setVisible(false); + return; +} + +/* 展开按钮槽函数 */ +void sidebarPluginsWidgets::m_pSpreadButtonSlots() +{ + m_pstackWidget->show(); + this->setFixedSize(400, m_cliboardHight); + m_pSpreadButton->setVisible(false); + m_pFoldButton->setVisible(true); + return; +} + +/* 新建Lable的动画类 */ +void sidebarPluginsWidgets::initLableBackgroundAnimation() +{ + m_pAnimationLeftRight = new QPropertyAnimation(m_pBlueBackgroundButton, "geometry"); + m_pAnimationLeftRight->setDuration(200); + m_pAnimationLeftRight->setStartValue(QRect(10, 15, 90, 34)); + m_pAnimationLeftRight->setEndValue(QRect(108, 15, 90, 34)); + m_pAnimationRightLeft = new QPropertyAnimation(m_pBlueBackgroundButton, "geometry"); + m_pAnimationRightLeft->setDuration(200); + m_pAnimationRightLeft->setStartValue(QRect(108, 15, 90, 34)); + m_pAnimationRightLeft->setEndValue(QRect(10, 15, 90, 34)); + connect(m_pAnimationLeftRight, &QPropertyAnimation::finished, this, &sidebarPluginsWidgets::m_pSmallPluginsStateSlots); + connect(m_pAnimationRightLeft, &QPropertyAnimation::finished, this, &sidebarPluginsWidgets::m_pClipBoardStateSlots); + return; +} + +/* 初始化剪贴板动画 */ +void sidebarPluginsWidgets::initCliboardAnimation() +{ + m_pAnimationClipbarod = new QPropertyAnimation(m_pClipboardWidget, "geometry"); + m_pAnimationClipbarod->setDuration(300); + m_pAnimationClipbarod->setStartValue(QRect(400, 0, 400, m_cliboardHight)); + m_pAnimationClipbarod->setEndValue(QRect(0, 0, 400, m_cliboardHight)); + connect(m_pAnimationClipbarod, &QPropertyAnimation::finished, this, &sidebarPluginsWidgets::m_AnimationClipbarodEndSlots); + return; +} + +/* 初始化小插件动画 */ +void sidebarPluginsWidgets::initSmallPluginsAnimation() +{ + m_pAnimationSmallWidget = new QPropertyAnimation(m_pPluginsButtonWidget, "geometry"); + m_pAnimationSmallWidget->setDuration(300); + m_pAnimationSmallWidget->setStartValue(QRect(400, 0, 400, m_cliboardHight)); + m_pAnimationSmallWidget->setEndValue(QRect(0, 0, 400, m_cliboardHight)); + connect(m_pAnimationSmallWidget, &QPropertyAnimation::finished, this, &sidebarPluginsWidgets::m_AnimationSmallWidgetEndSlots); + return; +} + +void sidebarPluginsWidgets::m_AnimationClipbarodEndSlots() +{ +} + +void sidebarPluginsWidgets::m_AnimationSmallWidgetEndSlots() +{ +} + +/* 设置侧边栏的按钮背景色为蓝色 */ +void sidebarPluginsWidgets::setClipboardButtonBackgroundIsBlue() +{ + m_pClipboardButton->setStyleSheet("QPushButton#ClipboardButton{background:rgba(61,107,229,1);padding-left:0px;padding-right:0px;}"); +} + +void sidebarPluginsWidgets::setSmallPluginsButtonBackgroudIsBlue() +{ + m_pSidebarPluginButton->setStyleSheet("QPushButton#SidebarPluginButton{background:rgba(61,107,229,1);padding-left:0px;padding-right:0px;}"); +} + +void sidebarPluginsWidgets::setClipboardButtonBackgroundIsBlank() +{ + m_pClipboardButton->setStyleSheet("QPushButton#ClipboardButton{background:rgba(61,107,229,0);padding-left:0px;padding-right:0px;}"); +} + +void sidebarPluginsWidgets::setSmallPluginsButtonBackgroudIsBlank() +{ + m_pSidebarPluginButton->setStyleSheet("QPushButton#SidebarPluginButton{background:rgba(61,107,229,0);padding-left:0px;padding-right:0px;}"); +} + +/* 设置剪贴板的高度 */ +void sidebarPluginsWidgets::setClipboardWidgetSize(int ClipHight) +{ + m_cliboardHight = ClipHight; + qDebug() << "设置小剪贴板的界面大小---->" << ClipHight; + this->setFixedSize(400, ClipHight); + m_pClipboardWidget->setFixedSize(400, ClipHight - 50); + m_pPluginsButtonWidget->setFixedSize(400, ClipHight - 50); + return; +} + +/* 解析Desktop文件,获取应用的图标 */ +QString sidebarPluginsWidgets::getAppIcon(QString desktopfp) +{ + GError** error=nullptr; + GKeyFileFlags flags=G_KEY_FILE_NONE; + GKeyFile* keyfile=g_key_file_new (); + + QByteArray fpbyte=desktopfp.toLocal8Bit(); + char* filepath=fpbyte.data(); + g_key_file_load_from_file(keyfile,filepath,flags,error); + char* icon=g_key_file_get_locale_string(keyfile,"Desktop Entry","Icon", nullptr, nullptr); + g_key_file_free(keyfile); + return QString::fromLocal8Bit(icon); +} + +//获取应用命令 +QString sidebarPluginsWidgets::getAppExec(QString desktopfp) +{ + GError** error=nullptr; + GKeyFileFlags flags=G_KEY_FILE_NONE; + GKeyFile* keyfile=g_key_file_new (); + + QByteArray fpbyte=desktopfp.toLocal8Bit(); + char* filepath=fpbyte.data(); + g_key_file_load_from_file(keyfile,filepath,flags,error); + char* exec=g_key_file_get_locale_string(keyfile,"Desktop Entry","Exec", nullptr, nullptr); + g_key_file_free(keyfile); + return QString::fromLocal8Bit(exec); +} + +/* 获取应用名称 */ +QString sidebarPluginsWidgets::getAppName(QString desktopfp) +{ + GError** error=nullptr; + GKeyFileFlags flags=G_KEY_FILE_NONE; + GKeyFile* keyfile=g_key_file_new (); + + QByteArray fpbyte=desktopfp.toLocal8Bit(); + char* filepath=fpbyte.data(); + g_key_file_load_from_file(keyfile,filepath,flags,error); + + char* name=g_key_file_get_locale_string(keyfile,"Desktop Entry","Name", nullptr, nullptr); + QString namestr=QString::fromLocal8Bit(name); + g_key_file_free(keyfile); + return namestr; +} + +/* 将小插件desktop文件名称放入到desktopfpList中 */ +void sidebarPluginsWidgets::addDesktopFileName() +{ + m_desktopfpList.append("ukui-clock.desktop"); + m_desktopfpList.append("ukui-notebook.desktop"); + m_desktopfpList.append("kylin-service-support.desktop"); +// m_desktopfpList.append("ukui-feedback.desktop"); + return; +} + +/* 解析链表中保存desktop文件 */ +void sidebarPluginsWidgets::parsingDesktopFile() +{ + int tmp = m_desktopfpList.size(); + qDebug() << "当前链表中保存了几个desktop文件---->" << tmp << m_desktopfpList; + QSpacerItem *item1 = new QSpacerItem(10, 20); + for (int i = 0; i < tmp; i++) { + QString desktopfp = "/usr/share/applications/" + m_desktopfpList.at(i); +// QString icon = getAppIcon(desktopfp); +// QString name = getAppName(desktopfp); +// QString Exec = getAppExec(desktopfp); + + //使用xdg解析desktop文件 + if(QFile::exists(desktopfp)){ + XdgDesktopFile xdg; + xdg.load(desktopfp); + QString name = xdg.localizedValue("Name").toString(); + QString icon = xdg.localizedValue("Icon").toString(); + QString Exec = xdg.localizedValue("Exec").toString(); + + m_ToolButton *p_button = StructToolButtol(icon, name); + connect(p_button, &QToolButton::clicked, this, [=]() { + QProcess p(0); + p.startDetached(Exec); + p.waitForStarted(); + return; + }); + if (p_button == nullptr) { + continue; + i--; + } + m_pGroupBoxUnSmallPluginsGLayout->addItem(item1, m_add_x, m_add_y - 1); + m_pGroupBoxUnSmallPluginsGLayout->addWidget(p_button, m_add_x, m_add_y); + m_add_y += 2; + if (m_add_y > 8) { + m_add_x++; + m_add_y = 1; + } + qDebug() << "add_y" << m_add_y << "add_x" << m_add_x; + } + + } + return; +} + +/* 构建小插件图标 */ +m_ToolButton* sidebarPluginsWidgets::StructToolButtol(QString icon, QString name) +{ + m_ToolButton *p_ToolButton = new m_ToolButton(); + p_ToolButton->setFixedSize(90,90); + QPixmap pixmap = QIcon::fromTheme(icon).pixmap(QSize(45, 45)); + QLabel *IconLabel = new QLabel(); + IconLabel->setFixedSize(45, 45); + IconLabel->setPixmap(pixmap); + + const QByteArray id(THEME_QT_SCHEMA); + if (QGSettings::isSchemaInstalled(id)) { + QGSettings *styleSettings = new QGSettings(id); + connect(styleSettings,&QGSettings::changed,this,[=](const QString &key){ + QPixmap pixmap = QIcon::fromTheme(icon).pixmap(QSize(45, 45)); + IconLabel->setPixmap(pixmap); + }); + } + + QLabel *textLabel = new QLabel(); + textLabel->setText(SetFormatBody(name, textLabel)); + m_LabelTextMap.insert(textLabel, name); + connect(this, &sidebarPluginsWidgets::FontModifyComplete, this, [=](){ + QString name = m_LabelTextMap.value(textLabel); + QString formatName = SetFormatBody(name, textLabel); + textLabel->setText(formatName); + qDebug() << "收到所有字体修改完成的信号"; + }); + + QVBoxLayout *ToolButtonLaout = new QVBoxLayout(); + ToolButtonLaout->setContentsMargins(0, 0, 0, 0); + ToolButtonLaout->addItem(new QSpacerItem(10, 12, QSizePolicy::Expanding)); + ToolButtonLaout->addWidget(IconLabel, 0, Qt::AlignCenter); + ToolButtonLaout->addItem(new QSpacerItem(10, 9, QSizePolicy::Expanding)); + ToolButtonLaout->addWidget(textLabel, 1, Qt::AlignCenter); + ToolButtonLaout->addSpacerItem(new QSpacerItem(10, 7)); + p_ToolButton->setLayout(ToolButtonLaout); + p_ToolButton->setStyle(new CustomStyle("ukui-default")); + qDebug() << "插件接口名称" << name; + p_ToolButton->pluginname=name; + return p_ToolButton; +} + +/* 设置...字样 */ +QString sidebarPluginsWidgets::SetFormatBody(QString text, QLabel *label) +{ + QFontMetrics fontMetrics(label->font()); + int LableWidth = label->width(); + int fontSize = fontMetrics.width(text); + qDebug() << "内容name---->" << text << "字体宽度---->fontsize" << fontSize; + QString formatBody = text; + if(fontSize > (80)) { + QStringList list = formatBody.split("\n"); + if (list.size() >= 2) { + //当有几行时,只需要截取第一行就行,在第一行后面加... + // 判断第一行是否是空行 + formatBody = judgeBlankLine(list); + formatBody = formatBody + "aa"; + int oneFontSize = fontMetrics.width(formatBody); + if (oneFontSize > (80)) { + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, 80); + return formatBody; + } else { + if (!substringSposition(formatBody, list)) { + int oneFontSize = fontMetrics.width(formatBody); + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, oneFontSize - 1); + return formatBody; + } + } + } else { + //说明只存在一行,在最后面加...就行 + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight,80); + qDebug() << "当前format-----》" << formatBody << "字体宽度---->" << fontSize; + return formatBody; + } + } else { + QStringList list = formatBody.split("\n"); + if (list.size() >= 2) { + //取得当前的有字符串的子串 + formatBody = judgeBlankLine(list); + formatBody = formatBody + "aa"; + if (!substringSposition(formatBody, list)) { + int oneFontSize = fontMetrics.width(formatBody); + formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, oneFontSize - 1); + } + } + } + return formatBody; +} + +/* 去除掉空行,显示有字体的行 */ +QString sidebarPluginsWidgets::judgeBlankLine(QStringList list) +{ + int tmp = list.count(); + for (int i = 0; i < tmp; i++) { + QString dest = list.at(i); + dest = dest.trimmed(); + if (dest.size() != 0) { + return list.at(i); + } + } + return list.at(0); +} + +/* 判断当前子串位置,后面是否还有子串 */ +bool sidebarPluginsWidgets::substringSposition(QString formatBody, QStringList list) +{ + int tmp = list.count(); + for (int i = 0; i < tmp; i++) { + QString dest = list.at(i); + if (dest == formatBody && i == tmp - 1) { + qDebug() << "后面没有字串,返回true"; + return true; + } + } + return false; +} + +void sidebarPluginsWidgets::setButtonFont() +{ + QPalette paletteButton = QApplication::palette(); + paletteButton.setBrush(QPalette::Text,paletteButton.color(QPalette::WindowText)); + qDebug() << "color -->" << paletteButton.color(QPalette::WindowText); + m_pClipboardButton->setPalette(paletteButton); + m_pSidebarPluginButton->setPalette(paletteButton); + return; +} + +//重新绘制背景色 +void sidebarPluginsWidgets::paintEvent(QPaintEvent *) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + /* 获取当前剪贴板中字体的颜色,作为背景色; + * 白字体 --> 黑背景 + * 黑字体 --> 白字体 + */ +// p.setBrush(opt.palette.color(QPalette::Base).lighter(85)); + p.setBrush(opt.palette.color(QPalette::Base)); +// p.setBrush(QBrush(QColor("#161617"))); + p.setOpacity(tranSparency); + p.setPen(Qt::NoPen); + + p.setRenderHint(QPainter::Antialiasing); //反锯齿 + p.drawRoundedRect(opt.rect,0,0); + p.drawRect(opt.rect); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} + +/* 小插件加载 */ +void sidebarPluginsWidgets::loadSmallPlugins() +{ + /* Iterative m_pSmallPluginsHash hash table */ + int pluginsNum = SmallPluginsManage::getInstance()->m_PluginsNum; + int Sequence = 1; + QSpacerItem *item1 = new QSpacerItem(10, 20); + while (pluginsNum) { + QHash ::const_iterator iter1 = SmallPluginsManage::getInstance()->m_pSmallPluginsHash.constBegin(); + while (iter1 != SmallPluginsManage::getInstance()->m_pSmallPluginsHash.constEnd()) { + if (iter1.value()->pluginsLoadingSequence() == Sequence) { + QToolButton *p_ToolButton = new QToolButton(); + p_ToolButton->setFixedSize(90,90); + QPixmap pixmap = iter1.value()->icon().pixmap(QSize(45, 45)); + QLabel *IconLabel = new QLabel(); + IconLabel->setFixedSize(45, 45); + IconLabel->setPixmap(pixmap); + QLabel *textLabel = new QLabel(); + textLabel->setText(iter1.value()->PluginButtonName()); + QVBoxLayout *ToolButtonLaout = new QVBoxLayout(); + ToolButtonLaout->setContentsMargins(0, 0, 0, 0); + ToolButtonLaout->addItem(new QSpacerItem(10, 12, QSizePolicy::Expanding)); + ToolButtonLaout->addWidget(IconLabel, 0, Qt::AlignCenter); + ToolButtonLaout->addItem(new QSpacerItem(10, 9, QSizePolicy::Expanding)); + ToolButtonLaout->addWidget(textLabel, 0, Qt::AlignCenter); + ToolButtonLaout->addSpacerItem(new QSpacerItem(10, 7)); + p_ToolButton->setLayout(ToolButtonLaout); + p_ToolButton->setStyle(new CustomStyle("ukui-default")); + p_ToolButton->setIconSize(QSize(iter1.value()->PluginIconSize_W(), iter1.value()->PluginIconSize_H())); + m_pGroupBoxUnSmallPluginsGLayout->addItem(item1, m_add_x, m_add_y - 1); + m_pGroupBoxUnSmallPluginsGLayout->addWidget(p_ToolButton, m_add_x, m_add_y); + connect(p_ToolButton, &QToolButton::clicked, this, [=]() { + iter1.value()->PluginsShowInterface(); + }); + pluginsNum--; + m_add_y += 2; + if (m_add_y > 8) { + m_add_x++; + m_add_y = 1; + } + break; + } + ++iter1; + } + Sequence++; + if (Sequence > KYLIN_PLUGINS_NUM) { + break; + } + } + qDebug() << "x -->" << m_add_x << "y -->" << m_add_y; + if (m_add_x < 1) { + m_pGroupBoxUnSmallPluginsGLayout->addItem(new QSpacerItem(400 - 100*(m_add_y/2), 0), m_add_x, m_add_y - 1); + m_pGroupBoxUnSmallPluginsGLayout->setContentsMargins(0, 0, 0, 250 - 90*(m_add_x + 1)); + m_pGroupBoxUnSmallPluginsGLayout->setVerticalSpacing(10); + } else { + m_pGroupBoxUnSmallPluginsGLayout->setContentsMargins(0, 0, 0, 30); + } +// m_pGroupBoxUnSmallPluginsGLayout->setVerticalSpacing(0); +// m_pGroupBoxUnSmallPluginsGLayout->setHorizontalSpacing(0); +// m_pGroupBoxUnSmallPluginsGLayout->setSpacing(0); + return; +} diff --git a/src/sidebarpluginswidgets.h b/src/sidebarpluginswidgets.h new file mode 100644 index 0000000..c5bbcbb --- /dev/null +++ b/src/sidebarpluginswidgets.h @@ -0,0 +1,156 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smallpluginsbutton.h" +#include "smallpluginsmanage.h" +#include "mostgrandwidget.h" +#include "pluginstoolbutton.h" +#include "customstyleCleanPushbutton.h" +#include "customstyle.h" + +#define THEME_QT_SCHEMA "org.ukui.style" +#define MODE_QT_KEY "style-name" +#define FONT_SIZE "system-font-size" + + + +class m_ToolButton : public QToolButton +{ + +public: + explicit m_ToolButton(); + QString pluginname; + void enterEvent(QEvent *event); +signals: + +}; + + +class sidebarPluginsWidgets : public QWidget +{ + Q_OBJECT +public: + explicit sidebarPluginsWidgets(QWidget *parent = nullptr); + ~sidebarPluginsWidgets(); + static sidebarPluginsWidgets* getInstancePluinsWidgets(); + static void initPluginsWidgets(); + void AddPluginWidgetInterface(); + void initUpGroupBoxButton(); //上半部分 剪贴板 小插件 俩按钮 groupBox初始化布局 + void initUnGroupBox(); //下半部分 剪贴板的界面 小插件按钮详情界面 初始化 + void initLableBackgroundAnimation(); //初始化动画 + void initCliboardAnimation(); //初始化剪贴板动画类 + void initSmallPluginsAnimation(); //初始化小插件动画类 + void setClipboardButtonBackgroundIsBlue(); //设置侧边栏按钮背景色为蓝色 + void setSmallPluginsButtonBackgroudIsBlue(); //设置小插件按钮背景色为蓝色 + void setClipboardButtonBackgroundIsBlank(); //设置侧边栏按钮背景色为空白 + void setSmallPluginsButtonBackgroudIsBlank(); //设置小插件按钮背景色为空白 + void setClipboardWidgetSize(int ClipHight); //设置此窗口的大小 + void loadSmallPlugins(); //加载小插件,放置到sidebar界面 + void setButtonFont(); + + QString getAppIcon(QString desktopfp); //解析desktop文件,获取插件图标 + QString getAppName(QString desktopfp); //获取插件名称 + QString getAppExec(QString desktopfp); //获取应用可执行文件路径 + void addDesktopFileName(); //将小插件desktop文件名称放入到desktopfpList中 + + void parsingDesktopFile(); //解析desktop文件 + m_ToolButton* StructToolButtol(QString icon, QString name); //构建QToolButton + QStringList m_desktopfpList; //保存当前小插件desktop文件名称 + + QString SetFormatBody(QString text, QLabel *label); //设置... + QString judgeBlankLine(QStringList list); + bool substringSposition(QString formatBody, QStringList list); + + QVBoxLayout *m_pWidgetOutVLayout; //最外层布局 + QHBoxLayout *m_pGrouBoxUpButtonHLayout; //GroupBox中Button中的布局 + QGridLayout *m_pGroupBoxUnSmallPluginsGLayout; //闹钟,便签本布局 + + QStackedWidget *m_pstackWidget; //放置剪贴板和小插件的容器窗口 + QWidget *m_pButtonWidget; //放置按钮Box + QWidget *m_pClipboardWidget; //放置剪贴板的Box + QWidget *m_pPluginsButtonWidget; //放置小插件按钮Box + + QPushButton *m_pFoldButton; //折叠按钮 + QPushButton *m_pSpreadButton; //展开按钮 + QPushButton *m_pBlueBackgroundButton; //蓝色背景块 + SmallPluginsButton *m_pClipboardButton; //剪贴板 界面显示按钮 + SmallPluginsButton *m_pSidebarPluginButton; //插件 界面显示按钮 + QToolButton *m_pNotebookButton; //笔记本 按钮 + QToolButton *m_pAlarmClockButton; //闹钟 按钮 + QToolButton *m_pFeedbackButtom; //用户反馈按钮 + + QPropertyAnimation *m_pAnimationLeftRight; + QPropertyAnimation *m_pAnimationRightLeft; + QPropertyAnimation *m_pAnimationClipbarod; + QPropertyAnimation *m_pAnimationSmallWidget; + + QGSettings *m_pTransparency = nullptr; // 透明度gsetting值 + + //状态机 + bool ClipBoardBool = false; // 剪贴板修改屏幕分辨率bool值 + bool SmallPluginsBool = false; // 插件按钮修改屏幕分辨率bool值 + + int m_add_x = 0; + int m_add_y = 1; + int m_cliboardHight; // 剪贴板和小插件的高度 + QMap m_LabelTextMap; // 保存label原始字符串的Map表 + + +signals: + void FontModifyComplete(); + +private slots: + void m_pClipBoardStateSlots(); + void m_pSmallPluginsStateSlots(); + + void m_ClipboardButtonSlots(); + void m_SidebarPluginButtonSlots(); + + void m_pFoldButtonSlots(); + void m_pSpreadButtonSlots(); + + void m_AnimationClipbarodEndSlots(); + void m_AnimationSmallWidgetEndSlots(); + void getTransparencyValue(const QString key); //获取个gsetting值 +protected: + void paintEvent(QPaintEvent *e); + +}; + +#endif // SIDEBARPLUGINSWIDGETS_H diff --git a/src/smallpluginsbutton.cpp b/src/smallpluginsbutton.cpp new file mode 100644 index 0000000..3f0b0ce --- /dev/null +++ b/src/smallpluginsbutton.cpp @@ -0,0 +1,47 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see + +SmallPluginsButton::SmallPluginsButton(QWidget *parent):QPushButton(parent) +{ + connect(this, &SmallPluginsButton::clicked, this, &SmallPluginsButton::enterButtonSignal); +} + +SmallPluginsButton::~SmallPluginsButton() +{ + +} + +void SmallPluginsButton::enterEvent(QEvent *e) +{ + Q_UNUSED(e); +// emit enterButtonSignal(); +} + +void SmallPluginsButton::leaveEvent(QEvent *e) +{ + Q_UNUSED(e); +} + +void SmallPluginsButton::SendSingal() +{ + emit enterButtonSignal(); +} + + diff --git a/src/smallpluginsbutton.h b/src/smallpluginsbutton.h new file mode 100644 index 0000000..4f69271 --- /dev/null +++ b/src/smallpluginsbutton.h @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include + +class SmallPluginsButton :public QPushButton +{ + Q_OBJECT +public: + explicit SmallPluginsButton(QWidget *parent = nullptr); + ~SmallPluginsButton(); + void SendSingal(); +protected: + void enterEvent(QEvent *e); //鼠标进入事件 + void leaveEvent(QEvent *e);//鼠标离开事件 +signals: + void enterButtonSignal(); +}; + +#endif // SMALLPLUGINSBUTTON_H diff --git a/src/smallpluginsmanage.cpp b/src/smallpluginsmanage.cpp new file mode 100644 index 0000000..85fc54b --- /dev/null +++ b/src/smallpluginsmanage.cpp @@ -0,0 +1,79 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see key PluginInterface =nullptr || SidebarSmallPluginInterface = nullptr"; + return; + } + + if (m_pSmallPluginsHash.value(key)) { + qDebug() << "m_pSmallPluginsHash has key PluginInterface"; + return; + } + m_pSmallPluginsHash.insert(key, value); + m_PluginsNum++; + return; +} + +SidebarSmallPluginInterface* SmallPluginsManage::getSmallplugin(PluginInterface *key) +{ + if (key == nullptr) { + qDebug() << "getSmallplugin --> PluginInterface key = nullptr"; + return nullptr; + } + return m_pSmallPluginsHash.value(key); +} + +void SmallPluginsManage::removeSmallplugin(PluginInterface *key) +{ + if (key == nullptr) { + qDebug() << "removeSmallplugin --> PluginInterface key = nullptr"; + return; + } + m_pSmallPluginsHash.remove(key); + return; +} diff --git a/src/smallpluginsmanage.h b/src/smallpluginsmanage.h new file mode 100644 index 0000000..f61d12f --- /dev/null +++ b/src/smallpluginsmanage.h @@ -0,0 +1,42 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include "sidebarSmallPluginInterface.h" +#include "plugin-iface.h" +class SmallPluginsManage : public QObject +{ + Q_OBJECT +public: + SmallPluginsManage(); + ~SmallPluginsManage(); + + static void SmallPluginsManageInit(); + static SmallPluginsManage *getInstance(); + + QHash m_pSmallPluginsHash; + void registerSmallplugin(PluginInterface *key, SidebarSmallPluginInterface *value); + SidebarSmallPluginInterface* getSmallplugin(PluginInterface *key); + void removeSmallplugin(PluginInterface *key); + int m_PluginsNum; +}; + +#endif // SMALLPLUGINSMANAGE_H diff --git a/src/ukui-sidebar-core.pro b/src/ukui-sidebar-core.pro new file mode 100644 index 0000000..fcf7b8f --- /dev/null +++ b/src/ukui-sidebar-core.pro @@ -0,0 +1,100 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-11-16T14:05:00 +# +#------------------------------------------------- + +QT += core gui dbus widgets network KWindowSystem + +TARGET = ukui-sidebar +TEMPLATE = app +CONFIG += c++11 link_pkgconfig +PKGCONFIG += gsettings-qt + +DEFINES += QT_DEPRECATED_WARNINGS +DEFINES += QT_MESSAGELOGCONTEXT + +include(./plugin-signals/plugin-signals.pri) +include(./plugin-interface/plugin-interface.pri) +include(env.pri) + +DEFINES += PLUGIN_INSTALL_DIRS='\\"$${PLUGIN_INSTALL_DIRS}\\"' + +RESOURCES += sidebar.qrc +SOURCES += \ + main.cpp \ + mostgrandwidget.cpp \ + pluginstoolbutton.cpp \ + sidebarDbusService.cpp \ + sidebarpluginswidgets.cpp \ + smallpluginsbutton.cpp \ + smallpluginsmanage.cpp \ + widget.cpp \ + pluginmanage.cpp \ + sidebarAppLog.cpp \ + customstyle.cpp \ + customstyleCleanPushbutton.cpp \ + qtsingleapplication.cpp \ + qtlocalpeer.cpp \ + qtlockedfile.cpp + + +INCLUDEPATH += ./plugin-interface + +HEADERS += \ + mostgrandwidget.h \ + pluginstoolbutton.h \ + sidebarDbusService.h \ + sidebarpluginswidgets.h \ + smallpluginsbutton.h \ + smallpluginsmanage.h \ + widget.h \ + pluginmanage.h \ + sidebarAppLog.h \ + customstyle.h \ + customstyleCleanPushbutton.h \ + qtsingleapplication.h \ + qtlocalpeer.h \ + qtlockedfile.h + + +INCLUDEPATH +=./plugin-interface ./plugin-sub-manager +TRANSLATIONS += ../translations/ukui-sidebar_bo.ts \ + ../translations/ukui-sidebar_bo_CN.ts \ + ../translations/ukui-sidebar_tr.ts \ + ../translations/ukui-sidebar_zh_CN.ts + +unix { + translation.path = /usr/share/ukui-sidebar/ + translation.files += ../translations/*.qm + INSTALLS += translation +} + +QMAKE_CFLAGS += -D_FORTIFY_SOURCE=2 -O2 + +CONFIG += link_pkgconfig + +PKGCONFIG +=gio-2.0 glib-2.0 gio-unix-2.0 xtst +LIBS += -lX11 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lukui-log4qt -lQt5Xdg + +desktopfile.files = data/ukui-sidebar.desktop +desktopfile.path = /etc/xdg/autostart/ + +schemes.files += data/org.ukui.log4qt.ukui-sidebar.gschema.xml +schemes.path = /usr/share/glib-2.0/schemas/ + +schemes1.files += data/org.ukui.sidebar.gschema.xml +schemes1.path = /usr/share/glib-2.0/schemas/ + +# Default rules for deployment. +target.path = /usr/bin/ +!isEmpty(target.path): INSTALLS += target + +INSTALLS += desktopfile +INSTALLS += schemes +INSTALLS += schemes1 + +DISTFILES += \ + data/org.ukui.sidebar.gschema.xml \ + env.pri\ + diff --git a/src/widget.cpp b/src/widget.cpp new file mode 100644 index 0000000..e364784 --- /dev/null +++ b/src/widget.cpp @@ -0,0 +1,1054 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include "customstyle.h" + +double tranSparency = 0.7; + +Widget::Widget(QWidget *parent) : QWidget (parent) +{ + initTranslation();//国际化 + //先仅注册托盘图标 + initTrayIcon(); +// startBackgroundFunction(); + + //注册Dbus服务 + registerDbusService(); +} + +Widget::~Widget() +{ + +} + +void Widget::initTrayIcon() +{ + createSystray(); + setIcon(QIcon::fromTheme("kylin-tool-box", QIcon(TRAY_ICON))); +} + +void Widget::registerDbusService() +{ + dbusService = new SidebarDbusService(this); + QDBusConnection::sessionBus().unregisterService("org.ukui.Sidebar"); + QDBusConnection::sessionBus().registerService("org.ukui.Sidebar"); + //注册对象路径,导出所有此对象的插槽 + //registerObject参数:路径,interface,对象,options + QDBusConnection::sessionBus().registerObject("/org/ukui/Sidebar",dbusService, + QDBusConnection::ExportAllSlots|QDBusConnection::ExportAllSignals); +} + +void Widget::startBackgroundFunction() +{ + /* 国际化 */ + initTranslation(); + + /* 初始化与任务栏交互的dbus和gsetting */ + initPanelDbusGsetting(); + + /* 初始化屏幕 */ + initDesktopPrimary(); + + /* 初始化主屏的X坐标 */ + InitializeHomeScreenGeometry(); + + /* 获取屏幕可用高度区域 */ +// GetsAvailableAreaScreen(); + + /* 初始化动画 */ + initAimation(); + + /* 主界面显示 */ + m_pMainQVBoxLayout = new QVBoxLayout; + m_pMainQVBoxLayout->setContentsMargins(0, 0, 0, 0); + m_pMainQVBoxLayout->setSpacing(0); + + /* 初始化剪贴板与小插件界面 */ + sidebarPluginsWidgets::initPluginsWidgets(); + sidebarPluginsWidgets::getInstancePluinsWidgets()->loadSmallPlugins(); + + /* 加载通知中心插件 */ + if (false == loadNotificationPlugin()) + qDebug() << "Notification center plug-in failed to load"; + + /* 加载剪贴板插件 */ + if (ListenClipboardSignal()) + qDebug() << "The clipboard plug-in failed to load"; + + this->setLayout(m_pMainQVBoxLayout); + + /* 系统托盘栏显示 */ + createAction(); + + /* 安装事件过滤器 */ + installEventFilter(this); + + /* 监听gsetting,修改所有窗口的字体 */ + setAllWidgetFont(); + + if (QGSettings::isSchemaInstalled(UKUI_TRANSPARENCY_SETTING)) { + m_pTransparency = new QGSettings(UKUI_TRANSPARENCY_SETTING); + connect(m_pTransparency, &QGSettings::changed, this, [=](QString value) { + if (value == "transparency") { + tranSparency = m_pTransparency->get("transparency").toDouble(); + this->update(); + } + }); + } + + //快捷参数 + if (QApplication::arguments().length() > 1) { + bootOptionsFilter(QApplication::arguments().at(1)); + } + + //通过kwin来实现窗口隐藏 + connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this,[&](WId activeWindowId) { + if (activeWindowId != this->window()->winId() ) { + qDebug()<<"触发隐藏功能"; + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + hideAnimation(); + } + }); + this->setWindowFlags(Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); + + qInfo() << "---------------------------主界面加载完毕---------------------------"; +} + +void Widget::XkbEventsPress(const QString &keycode) +{ + QString KeyName; + if (keycode.length() >= 8) { + KeyName = keycode.left(8); + } + + if (KeyName.compare("Super_L+")==0) { + m_winFlag = true; + } + + if (m_winFlag && keycode == "Super_L") { + m_winFlag = false; + return; + } + +} + +void Widget::XkbEventsRelease(const QString &keycode) +{ + QString KeyName; + static bool winFlag=false; + if (keycode.length() >= 8) { + KeyName = keycode.left(8); + } + + if (KeyName.compare("Super_L+")==0) { + winFlag = true; + } + + if (winFlag && keycode == "Super_L") { + winFlag = false; + return; + } else if (m_winFlag && keycode == "Super_L") + return; + + if (keycode == "Super_L+a") { + if(m_bShowFlag) { + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + hideAnimation(); + //this->hide(); + } else { + mostGrandWidget::getInstance()->hide(); + MostGrandWidgetCoordinates(); + mostGrandWidget::getInstance()->show(); + showAnimation(); + m_bShowFlag = true; + setIcon(QIcon::fromTheme("kylin-tool-box", QIcon(TRAY_ICON))); + /* + this->show(); + this->raise(); + this->activateWindow(); + */ + } + } +} + +//加载通知中心插件 +bool Widget::loadNotificationPlugin() +{ + QDir pluginsDir; + static bool installed = (QCoreApplication::applicationDirPath() == QDir(("/usr/bin")).canonicalPath()); + + if (installed) + pluginsDir = QDir(PLUGIN_INSTALL_DIRS); + else + pluginsDir = QDir(qApp->applicationDirPath() + "/plugins/ukui-sidebar-notification"); + + pluginsDir.setFilter(QDir::Files); + QPluginLoader pluginLoader(pluginsDir.absoluteFilePath("libnotification_plugin.so")); + + m_pNotificationPluginObject = pluginLoader.instance(); + if (nullptr == m_pNotificationPluginObject) { + return false; + } + + NotificationInterface* pNotificationPluginObject = qobject_cast(m_pNotificationPluginObject); + if (nullptr == pNotificationPluginObject) { + return false; + } + + connect(m_pNotificationPluginObject, SIGNAL(Sig_onNewNotification()), this, SLOT(onNewNotification())); + m_pMainQVBoxLayout->addWidget(pNotificationPluginObject->centerWidget(), 1); + return true; +} + +//加载剪贴板插件 +int Widget::ListenClipboardSignal() +{ + QDir pluginsDir; + static bool installed = (QCoreApplication::applicationDirPath() == QDir(("/usr/bin")).canonicalPath()); + + if (installed) + pluginsDir = QDir(PLUGIN_INSTALL_DIRS); + else + pluginsDir = QDir(qApp->applicationDirPath() + "/plugins/ukui-sidebar-clipboard"); + + pluginsDir.setFilter(QDir::Files); + QPluginLoader pluginLoader(pluginsDir.absoluteFilePath("libclipboardPlugin.so")); + QObject *pClipPlugin = pluginLoader.instance(); + + m_pSidebarClipboard = dynamic_cast(pClipPlugin); /* 获取剪贴版插件指针; */ + + if (nullptr == m_pSidebarClipboard) { + qWarning() << "剪贴板插件插件加载失败"; + return 1; + } + m_pSidebarSignal = m_pSidebarClipboard->createClipSignal(); /* 获取剪贴板的信号类指针 */ + /* 点击剪贴板空白区域时,隐藏侧边栏 */ + connect(m_pSidebarSignal, &SidebarClipBoardSignal::ClipboardHideSignal, this, [=]() { + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + hideAnimation(); + }); + + connect(m_pSidebarSignal, &SidebarClipBoardSignal::CLipBoardEditConfirmButtonSignal, this, &Widget::ClipboardHideSlots); + + connect(m_pSidebarSignal, &SidebarClipBoardSignal::ClipBoardWidgetEntryEditButtonSignal, this, &Widget::ClipboardShowSlots); + + sidebarPluginsWidgets::getInstancePluinsWidgets()->m_pClipboardWidget = m_pSidebarClipboard->getClipbaordGroupBox(); /* 获取剪贴板的Widget指针; */ + sidebarPluginsWidgets::getInstancePluinsWidgets()->initCliboardAnimation(); /* 初始化剪贴板动画 */ +// int clipboardhight = setClipBoardWidgetScaleFactor(); +// qDebug() << "剪贴板高度" << clipboardhight; + sidebarPluginsWidgets::getInstancePluinsWidgets()->setClipboardWidgetSize(CLIPBOARD_HEIGHT); /* 设定剪贴板高度 */ + sidebarPluginsWidgets::getInstancePluinsWidgets()->AddPluginWidgetInterface(); /* 将下半部分所有控件加入到sidebarPluginsWidgets中 */ + m_pMainQVBoxLayout->addWidget(sidebarPluginsWidgets::getInstancePluinsWidgets(), 0); + return 0; +} + +//创建动作 +void Widget::createAction() +{ + Open = new QAction(QObject::tr("Open"), this); + connect(Open, &QAction::triggered, this, &Widget::OpenSidebarSlots); + + OpenSetUp = new QAction(QIcon::fromTheme("document-page-setup-symbolic", QIcon(SETTING_ICON)), QObject::tr("Set up notification center"), this); + connect(OpenSetUp, &QAction::triggered, this, &Widget::OpenControlCenterSettings); + + trayIconMenu->addAction(Open); + trayIconMenu->addAction(OpenSetUp); + + connect(trayIcon, &QSystemTrayIcon::activated, this, &Widget::iconActivated); +} + +//添加动作和创建 systray实例 +void Widget::createSystray() +{ + trayIconMenu = new QMenu(this); + trayIconMenu->setProperty("iconHighlightEffectMode", 1); + if (trayIconMenu == nullptr) { + qWarning() << "分配空间trayIconMenu失败"; + return ; + } + + trayIcon = new QSystemTrayIcon(this); + if (nullptr == trayIcon) { + qWarning()<< "分配空间trayIcon失败"; + return ; + } + connect(trayIcon, &QSystemTrayIcon::activated, this, &Widget::clickTrayFunction); + + trayIcon->setVisible(true); + trayIcon->setContextMenu(trayIconMenu); +} + +void Widget::clickTrayFunction(QSystemTrayIcon::ActivationReason reason) +{ + if (!oneShotBool){ + disconnect(trayIcon, &QSystemTrayIcon::activated, this, &Widget::clickTrayFunction); + emit startRun(reason); + oneShotBool = true; + } +} + +//设置托盘栏的图标 +void Widget::setIcon(QIcon icon) +{ + trayIcon->setIcon(icon); + setWindowIcon(icon); + trayIcon->setToolTip(tr("Sidebar")); +} + +//设置activated信号 +void Widget::iconActivated(QSystemTrayIcon::ActivationReason reason) +{ + //获取透明度 + if (QGSettings::isSchemaInstalled(UKUI_TRANSPARENCY_SETTING)){ + if (m_pTransparency->keys().contains("transparency")) { + tranSparency = m_pTransparency->get("transparency").toDouble(); + } + } + switch (reason) { + case QSystemTrayIcon::Trigger: { + if (m_bShowFlag) { + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + hideAnimation(); + } else { + mostGrandWidget::getInstance()->hide(); + MostGrandWidgetCoordinates(); + mostGrandWidget::getInstance()->show(); + showAnimation(); + m_bShowFlag = true; + m_bIconActivatedState = false; + setIcon(QIcon::fromTheme("kylin-tool-box", QIcon(TRAY_ICON))); + } + break; + } + case QSystemTrayIcon::Context: + if (m_bShowFlag) { + trayIconMenu->hide(); //先隐藏菜单栏,不让其显示出来, 然后将sidebar隐藏 + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + hideAnimation(); + } + break; + default: + break; + } +} + +/* 初始化屏幕分辨率 */ +void Widget::initDesktopPrimary() +{ + /* 监听屏幕分辨率是否变化 主频是否有变化 初始化屏幕宽高 和主屏起始X坐标值 */ + m_pDeskWgt = QApplication::desktop(); + connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &Widget::onResolutionChanged); + connect(QApplication::primaryScreen(), &QScreen::virtualGeometryChanged, this, &Widget::onResolutionChanged); + connect(m_pDeskWgt, &QDesktopWidget::primaryScreenChanged, this, &Widget::primaryScreenChangedSLot); + connect(m_pDeskWgt, &QDesktopWidget::screenCountChanged, this, &Widget::screenCountChangedSlots); + +} + +void Widget::initPanelDbusGsetting() +{ + /* 链接任务栏Dbus接口,获取任务栏高度和位置 */ + m_pServiceInterface = new QDBusInterface(PANEL_DBUS_SERVICE, PANEL_DBUS_PATH, PANEL_DBUS_INTERFACE, QDBusConnection::sessionBus()); + m_pServiceInterface->setTimeout(2147483647); + + /* 链接任务栏Dbus接口,获取任务栏点击信号 */ + QDBusConnection::sessionBus().connect(QString(), QString("/taskbar/click"), \ + "com.ukui.panel.plugins.taskbar", "sendToUkuiDEApp", this, SLOT(ClickPanelHideSidebarSlots(void))); + + /* 链接任务栏dgsetting接口 */ + if(QGSettings::isSchemaInstalled(UKUI_PANEL_SETTING)) + m_pPanelSetting = new QGSettings(UKUI_PANEL_SETTING); +} + +//链接任务栏dbus获取高度的接口 +int Widget::connectTaskBarDbus() +{ + int panelHeight = 46; + if (m_pPanelSetting != nullptr) { + QStringList keys = m_pPanelSetting->keys(); + if (keys.contains("panelsize")) { + panelHeight = m_pPanelSetting->get("panelsize").toInt(); + } + } else { + QDBusMessage msg = m_pServiceInterface->call("GetPanelSize", QVariant("Hight")); + panelHeight = msg.arguments().at(0).toInt(); + return panelHeight; + } + return panelHeight; +} + +// 初始化华为990dbus接口 +bool Widget::initHuaWeiDbus() +{ + if(!m_pDbusXrandInter) { + m_pDbusXrandInter = new QDBusInterface(DBUS_NAME, + DBUS_PATH, + DBUS_INTERFACE, + QDBusConnection::sessionBus()); + + connect(m_pDbusXrandInter, SIGNAL(screenPrimaryChanged(int,int,int,int)), + this, SLOT(priScreenChanged(int,int,int,int))); + } + m_nScreen_x = getScreenGeometry("x"); + m_nScreen_y = getScreenGeometry("y"); + m_nScreenWidth = getScreenGeometry("width"); + m_nScreenHeight = getScreenGeometry("height"); + qDebug() << "HW--->偏移的x坐标------------------------------>" << m_nScreen_x; + qDebug() << "HW--->偏移的Y坐标------------------------------>" << m_nScreen_y; + if (m_nScreenWidth == 0 || m_nScreenHeight == 0) { + qDebug() << "无dbus可用接口HW"; + return false; + } else { + qDebug() << "有dbus可用接口HW"; + return true; + } +} + +/* get primary screen changed */ +void Widget::priScreenChanged(int x, int y, int width, int height) +{ + qDebug("primary screen changed, geometry is x=%d, y=%d, windth=%d, height=%d", x, y, width, height); + m_nScreen_x = x; + m_nScreen_y = y; + m_nScreenWidth = width; + m_nScreenHeight = height; +} + +int Widget::getScreenGeometry(QString methodName) +{ + int res = 0; + QDBusMessage message = QDBusMessage::createMethodCall(DBUS_NAME, + DBUS_PATH, + DBUS_INTERFACE, + methodName); + QDBusMessage response = QDBusConnection::sessionBus().call(message); + if (response.type() == QDBusMessage::ReplyMessage) { + if(response.arguments().isEmpty() == false) { + int value = response.arguments().takeFirst().toInt(); + res = value; + qDebug() << value; + } + } else { + qDebug()<keys(); + if (keys.contains("panelposition")) { + panelPosition = m_pPanelSetting->get("panelposition").toInt(); + } + } else { + QDBusMessage msg = m_pServiceInterface->call("GetPanelPosition", QVariant("Site")); + panelPosition = msg.arguments().at(0).toInt(); + } + qDebug() << "panel所在的位置" << panelPosition; + return panelPosition; +} + +//获取屏幕的可用区域高度和宽度 +void Widget::GetsAvailableAreaScreen() +{ + //如果取不到任务栏的高度,还是优先获取桌面分辨率,可用区域 + if ((0 == connectTaskBarDbus()) && (0 == getPanelSite())) { + QScreen* pScreen = QGuiApplication::primaryScreen(); + QRect DeskSize = pScreen->availableGeometry(); + m_nScreenWidth = DeskSize.width(); //桌面分辨率的宽 + m_nScreenHeight = DeskSize.height(); //桌面分辨率的高 + } else { + //如果取到任务栏的高度,则取屏幕分辨率的高度 + QRect screenRect = QGuiApplication::primaryScreen()->geometry(); + m_nScreenWidth = screenRect.width(); + m_nScreenHeight = screenRect.height(); + } + qDebug() << "更新主屏Width --> " << m_nScreenWidth; + qDebug() << "更新主屏Height --> " << m_nScreenHeight; +} + +/* 设定剪贴板高度 */ +int Widget::setClipBoardWidgetScaleFactor() +{ + if (m_nScreenHeight >= 600 && m_nScreenHeight <= 768) { + return m_nScreenHeight/2 - connectTaskBarDbus() - 60; + } else if (m_nScreenHeight >= 900 && m_nScreenHeight <= 1080) { + return m_nScreenHeight/3; + } else if (m_nScreenHeight >= 1200 && m_nScreenHeight <= 2160) { + return m_nScreenHeight/4; + } else { + return m_nScreenHeight/2 - connectTaskBarDbus(); + } +} + +void Widget::initTranslation() +{ + m_pTranslator = new QTranslator; + if (m_pTranslator->load(QLocale(), QLatin1String("ukui-sidebar"), QLatin1String("_"), QLatin1String("/usr/share/ukui-sidebar"))) + QApplication::installTranslator(m_pTranslator); + else + qDebug() << "cannot load translator " << QLocale::system().name() << ".qm!"; +} + +void Widget::initAimation() +{ + m_pAnimationShowSidebarWidget = new QPropertyAnimation(this, "geometry"); + m_pAnimationHideSidebarWidget = new QPropertyAnimation(this, "geometry"); + m_pAnimationShowSidebarWidget->start(); + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + connect(m_pAnimationHideSidebarWidget, &QPropertyAnimation::finished, this, &Widget::hideAnimationFinish); + connect(m_pAnimationShowSidebarWidget, &QPropertyAnimation::valueChanged, this, &Widget::showAnimationAction); + connect(m_pAnimationShowSidebarWidget, &QPropertyAnimation::finished, this, &Widget::showAnimationFinish); +} + +//动画展开 +void Widget::showAnimation() +{ + InitializeHomeScreenGeometry(); + MostGrandWidgetCoordinates(); + + qDebug()<<"展开动画开始--------------------------------"; + NotificationInterface* pNotificationPluginObject = qobject_cast(m_pNotificationPluginObject); + if (nullptr != pNotificationPluginObject) + pNotificationPluginObject->showNotification(); //当动画展开时给插件一个通知 + + int AnimaStartSideBarSite[4]; //侧边栏动画开始位置 + int AnimaStopSidebarSite[4]; //侧边栏动画结束位置 +// int clipboardhight = setClipBoardWidgetScaleFactor(); + sidebarPluginsWidgets::getInstancePluinsWidgets()->setClipboardWidgetSize(CLIPBOARD_HEIGHT); //设定剪贴板高度 + m_pPeonySite = getPanelSite(); + switch (m_pPeonySite) + { + case Widget::PanelDown : + { + qDebug()<<"任务栏在底部"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = 400; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + //结束位置坐标 + AnimaStopSidebarSite[0] = 0; + AnimaStopSidebarSite[1] = 0; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + } + break; + case Widget::PanelUp: + { + qDebug()<<"任务栏在顶部"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = 400; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + //结束位置坐标 + AnimaStopSidebarSite[0] = 0; + AnimaStopSidebarSite[1] = 0;; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + } + break; + case Widget::PanelLeft: + { + qDebug()<<"任务栏在左侧"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = -400; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight; + //结束位置坐标 + AnimaStopSidebarSite[0] = 0; + AnimaStopSidebarSite[1] = 0; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight; + } + break; + case Widget::PanelRight: + { + qDebug()<<"任务栏在右侧"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = 400; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight; + //结束位置坐标 + AnimaStopSidebarSite[0] = 0; + AnimaStopSidebarSite[1] = 0; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight; + } + break; + default: + break; + } + //--> 给通知中心发信号,开始左移动画 + QDBusMessage message =QDBusMessage::createSignal("/org/ukui/Sidebar", "org.ukui.Sidebar", + "animationAction"); + uint time = 400; + int distance = 400; + message< " << m_nScreenWidth; + qDebug() << "主屏Height --> " << m_nScreenHeight; + qDebug()<<"setStartValue QRect:"<setDuration(400); + m_pAnimationShowSidebarWidget->setStartValue(QRect(AnimaStartSideBarSite[0], AnimaStartSideBarSite[1], AnimaStartSideBarSite[2], AnimaStartSideBarSite[3])); //前两个参数是坐标,后两个参数是长宽 + m_pAnimationShowSidebarWidget->setEndValue(QRect(AnimaStopSidebarSite[0], AnimaStopSidebarSite[1], AnimaStopSidebarSite[2], AnimaStopSidebarSite[3])); + m_pAnimationShowSidebarWidget->start(); + sidebarState = true; + dbusService->sidebarState = true; + dbusService->m_sidebarWidth = 400; + qDebug()<<"展开动画结束--------------------------------"; +} + +void Widget::showAnimationAction(const QVariant &value) +{ + QRect Rect = value.value(); + int x = Rect.x(); + if (m_pPeonySite == Widget::PanelDown + || m_pPeonySite == Widget::PanelUp) { + mostGrandWidget::getInstance()->setProperty("blurRegion", QRegion(QRect(x, 0, 400, m_nScreenHeight - connectTaskBarDbus()))); + } else { + mostGrandWidget::getInstance()->setProperty("blurRegion", QRegion(QRect(x, 0, 400, m_nScreenHeight))); + } +} + +/* 获取Getting透明度值 */ +void sidebarPluginsWidgets::getTransparencyValue(const QString key) +{ + if (key == "transparency") { + tranSparency = m_pTransparency->get("transparency").toFloat(); + qDebug() << "获取到的值为----->" << tranSparency; + } + return; +} + +//隐藏动画 +void Widget::hideAnimation() +{ + qDebug()<<"隐藏动画开始--------------------------------"; + m_bShowFlag = false; + NotificationInterface* pNotificationPluginObject = qobject_cast(m_pNotificationPluginObject); + if (nullptr != pNotificationPluginObject) + pNotificationPluginObject->hideNotification(); //当动画隐藏时给插件一个通知 + + int AnimaStartSideBarSite[4]; //侧边栏动画开始位置 + int AnimaStopSidebarSite[4]; //侧边栏动画结束位置 + switch (getPanelSite()) { + case Widget::PanelDown : + { + qDebug()<<"任务栏在底部"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = 0; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + //结束位置坐标 + AnimaStopSidebarSite[0] = 450; + AnimaStopSidebarSite[1] = 0; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + } + break; + case Widget::PanelUp: + { + qDebug()<<"任务栏在顶部"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = 0; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + //结束位置坐标 + AnimaStopSidebarSite[0] = 450; + AnimaStopSidebarSite[1] = 0; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight - connectTaskBarDbus(); + } + break; + case Widget::PanelLeft: + { + qDebug()<<"任务栏在左侧"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = 0; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight; + //结束位置坐标 + AnimaStopSidebarSite[0] = -400; + AnimaStopSidebarSite[1] = 0; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight; + } + break; + case Widget::PanelRight: + { + qDebug()<<"任务栏在右侧"; + //起始位置的坐标 + AnimaStartSideBarSite[0] = 0; + AnimaStartSideBarSite[1] = 0; + AnimaStartSideBarSite[2] = 400; + AnimaStartSideBarSite[3] = m_nScreenHeight; + //结束位置坐标 + AnimaStopSidebarSite[0] = 450; + AnimaStopSidebarSite[1] = 0; + AnimaStopSidebarSite[2] = 400; + AnimaStopSidebarSite[3] = m_nScreenHeight; + } + break; + default: + break; + } + //给通知中心发信号,开始左移动画 + QDBusMessage message = QDBusMessage::createSignal("/org/ukui/Sidebar", "org.ukui.Sidebar", + "animationAction"); + uint time = 200; + int distance = -400; + message< " << m_nScreenWidth; + qDebug() << "主屏Height --> " << m_nScreenHeight; + qDebug()<<"setStartValue QRect:"<setDuration(200); + m_pAnimationHideSidebarWidget->setStartValue(QRect(AnimaStartSideBarSite[0], AnimaStartSideBarSite[1], AnimaStartSideBarSite[2], AnimaStartSideBarSite[3])); + m_pAnimationHideSidebarWidget->setEndValue(QRect(AnimaStopSidebarSite[0], AnimaStopSidebarSite[1], AnimaStopSidebarSite[2], AnimaStopSidebarSite[3])); + m_pAnimationHideSidebarWidget->start(); + sidebarState = false; + dbusService->sidebarState = false; + dbusService->m_sidebarWidth = 0; + qDebug()<<"隐藏动画结束--------------------------------"; + return; +} + +void Widget::hideAnimationFinish() +{ + dbusService->m_sidebarWidth = 0; + sidebarState = false; + dbusService->sidebarState = false; + mostGrandWidget::getInstance()->hide(); + return; +} + +void Widget::showAnimationFinish() +{ + dbusService->m_sidebarWidth = 400; + sidebarState = true; + dbusService->sidebarState = true; + return; +} + +//当改变屏幕分辨率时重新获取屏幕分辨率 +void Widget::onResolutionChanged(const QRect argc) +{ + Q_UNUSED(argc); + qDebug() << "屏幕分辨率发生变化"; + InitializeHomeScreenGeometry(); + ModifyScreenNeeds(); //修改屏幕分辨率或者主屏需要做的事情 + return; +} + +/* 主屏发生变化槽函数 */ +void Widget::primaryScreenChangedSLot() +{ + qDebug() << "主屏发生变化"; + InitializeHomeScreenGeometry(); + ModifyScreenNeeds(); + return; +} + +/* 屏幕数量改变时对应槽函数 */ +void Widget::screenCountChangedSlots(int count) +{ + Q_UNUSED(count); + qDebug() << "屏幕数量发生变化"; + InitializeHomeScreenGeometry(); + ModifyScreenNeeds(); + return; +} + +/* 接受剪贴板信号,将bool值m_bClipboardFlag置为false; */ +void Widget::ClipboardShowSlots() +{ + m_bClipboardFlag = false; + return; +} + +/* 接受剪贴板信号,将bool值m_bClipboardFlag置为true; */ +void Widget::ClipboardHideSlots() +{ + m_bClipboardFlag = true; + return; +} + +/* 接受任务栏点击信号,当任务栏点击左键时,关闭任务栏 */ +void Widget::ClickPanelHideSidebarSlots() +{ + if (m_bClipboardFlag) { + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + if(sidebarState) //展开状态下执行隐藏动画 + hideAnimation(); + } + return; +} + +/* 右键菜单打开侧边栏槽函数 */ +void Widget::OpenSidebarSlots() +{ + mostGrandWidget::getInstance()->hide(); + MostGrandWidgetCoordinates(); + mostGrandWidget::getInstance()->show(); + showAnimation(); + m_bShowFlag = true; + setIcon(QIcon::fromTheme("kylin-tool-box", QIcon(TRAY_ICON))); + return; +} + +/* 打开控制中心的通知中心 */ +void Widget::OpenControlCenterSettings() +{ + QProcess p(0); + p.startDetached("ukui-control-center -m Notice"); + p.waitForStarted(); + return; +} + +/* 修改屏幕分辨率或者主屏需要做的事情 */ +void Widget::ModifyScreenNeeds() +{ +// int clipboardhight = setClipBoardWidgetScaleFactor(); + sidebarPluginsWidgets::getInstancePluinsWidgets()->setClipboardWidgetSize(CLIPBOARD_HEIGHT); //设定剪贴板高度 + return; +} + +void Widget::initOsSiteXY() +{ + if (QGuiApplication::primaryScreen()) { + m_nScreen_x = QGuiApplication::primaryScreen()->geometry().x(); + m_nScreen_y = QGuiApplication::primaryScreen()->geometry().y(); + } else { + QList screen = QGuiApplication::screens(); + int count = m_pDeskWgt->screenCount(); + if (count > 1) { + m_nScreen_x = screen[0]->geometry().x(); + m_nScreen_y = screen[0]->geometry().y(); + + } else { + m_nScreen_x = 0; + m_nScreen_y = 0; + } + } +} + +/* 初始化主屏的X坐标 */ +void Widget::InitializeHomeScreenGeometry() +{ + QString ArchDiff = qgetenv(ENV_XDG_SESSION_TYPE); + if (ArchDiff == ENV_WAYLAND) { + if (!initHuaWeiDbus()) { + initOsSiteXY(); + GetsAvailableAreaScreen(); + qDebug() << "HW--->偏移的x坐标,初始化坐标错误------------------------------>" << m_nScreen_x; + qDebug() << "HW--->偏移的Y坐标,初始化坐标错误------------------------------>" << m_nScreen_y; + return; + } + } else if (ArchDiff == ENV_X11) { + initOsSiteXY(); + GetsAvailableAreaScreen(); + qDebug() << "偏移的x坐标------------------------------>" << m_nScreen_x; + qDebug() << "偏移的Y坐标------------------------------>" << m_nScreen_y; + } + return; +} + +/* 监听gsetting,修改所有的字体 */ +void Widget::setAllWidgetFont() +{ + const QByteArray id("org.ukui.style"); + QGSettings * fontSetting = new QGSettings(id); + connect(fontSetting, &QGSettings::changed,[=](QString key){ + if ("systemFont" == key || "systemFontSize" ==key) { + QFont font = this->font(); + for (auto widget : qApp->allWidgets()) { + widget->setFont(font); + } + emit sidebarPluginsWidgets::getInstancePluinsWidgets()->FontModifyComplete(); + } + }); +} + +/* 根据任务栏位置调整侧边栏位置 */ +void Widget::MostGrandWidgetCoordinates() +{ + switch (getPanelSite()) { + case Widget::PanelDown : + { + mostGrandWidget::getInstance()->setMostGrandwidgetSize(400, m_nScreenHeight - connectTaskBarDbus()); + mostGrandWidget::getInstance()->setMostGrandwidgetCoordinates(m_nScreen_x + m_nScreenWidth - 400, m_nScreen_y); + emit m_pSidebarSignal->ClipboardPreviewSignal(400, m_nScreenHeight, m_nScreen_x + m_nScreenWidth - 400, m_nScreen_y, connectTaskBarDbus()); + } + break; + case Widget::PanelUp: + { + mostGrandWidget::getInstance()->setMostGrandwidgetSize(400, m_nScreenHeight - connectTaskBarDbus()); + mostGrandWidget::getInstance()->setMostGrandwidgetCoordinates(m_nScreen_x + m_nScreenWidth - 400, connectTaskBarDbus() + m_nScreen_y); + emit m_pSidebarSignal->ClipboardPreviewSignal(400, m_nScreenHeight, m_nScreen_x + m_nScreenWidth - 400, connectTaskBarDbus() + m_nScreen_y, connectTaskBarDbus()); + } + break; + case Widget::PanelLeft: + { + mostGrandWidget::getInstance()->setMostGrandwidgetSize(400, m_nScreenHeight); + mostGrandWidget::getInstance()->setMostGrandwidgetCoordinates(m_nScreen_x + connectTaskBarDbus(), m_nScreen_y); + emit m_pSidebarSignal->ClipboardPreviewSignal(400, m_nScreenHeight, m_nScreen_x + connectTaskBarDbus() + 400 + 260, m_nScreen_y, 0); + } + break; + case Widget::PanelRight: + { + mostGrandWidget::getInstance()->setMostGrandwidgetSize(400, m_nScreenHeight); + mostGrandWidget::getInstance()->setMostGrandwidgetCoordinates(m_nScreen_x + m_nScreenWidth - 400 - connectTaskBarDbus(), m_nScreen_y); + emit m_pSidebarSignal->ClipboardPreviewSignal(400, m_nScreenHeight, m_nScreen_x + m_nScreenWidth - 400 - connectTaskBarDbus(), m_nScreen_y, 0); + } + break; + default: + break; + } +} + +//当没展开时,来了新通知才提示 +void Widget::onNewNotification() +{ + if (false == m_bShowFlag) { + setIcon(QIcon::fromTheme("kylin-tool-box-null", QIcon(TRAY_NULL_ICON))); + } + return; +} + +/* 切换主题时,定时器槽函数 */ +void Widget::updateSmallPluginsClipboardWidget() +{ + ModifyScreenNeeds(); +} + +/* 过滤终端命令 */ +void Widget::bootOptionsFilter(QString opt) +{ + if (oneShotBool){ + if (opt == "-state" ) { + if (m_bShowFlag) { + hideSidebar(); + } else { + showSidebar(); + } + } else if (opt == "-h" || opt == "-hide") { + if(m_bShowFlag) { + hideSidebar(); + } + } else if (opt == "-s" || opt == "-show") { + if(!m_bShowFlag) { + showSidebar(); + } + } + } else { + qDebug()<<"未启动完全"; + } +} + +void Widget::hideSidebar() +{ + qDebug()<<"隐藏侧边栏"; + mostGrandWidget::getInstance()->topLevelWidget()->setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1))); + hideAnimation(); +} + + +void Widget::showSidebar() +{ + qDebug()<<"展示侧边栏"; + mostGrandWidget::getInstance()->hide(); + MostGrandWidgetCoordinates(); + mostGrandWidget::getInstance()->show(); + showAnimation(); + m_bShowFlag = true; + setIcon(QIcon::fromTheme("kylin-tool-box", QIcon(TRAY_ICON))); +} + +/* 事件过滤器 */ +bool Widget::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == this) { + if (event->type() == QEvent::WindowDeactivate \ + && true == m_bShowFlag && true == m_bClipboardFlag) { + m_bShowFlag = false; + return true; + } else if (event->type() == QEvent::StyleChange) { + sidebarPluginsWidgets::getInstancePluinsWidgets()->setButtonFont(); + return true; + } + } + return false; +} + +void Widget::paintEvent(QPaintEvent *event) +{ + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + QPainterPath rectPath; + rectPath.addRoundedRect(this->rect().adjusted(0, 0, -0, -0), 0, 02); + + QPixmap pixmap(this->rect().size()); + pixmap.fill(Qt::transparent); + QPainter pixmapPainter(&pixmap); + pixmapPainter.setRenderHint(QPainter::Antialiasing); + pixmapPainter.setPen(Qt::transparent); + pixmapPainter.setBrush(Qt::black); + pixmapPainter.drawPath(rectPath); + pixmapPainter.end(); + + QImage img = pixmap.toImage(); + qt_blurImage(img, 8, false, false); + + pixmap = QPixmap::fromImage(img); + QPainter pixmapPainter2(&pixmap); + pixmapPainter2.setRenderHint(QPainter::Antialiasing); + pixmapPainter2.setCompositionMode(QPainter::CompositionMode_Clear); + pixmapPainter2.setPen(Qt::transparent); + pixmapPainter2.setBrush(Qt::transparent); + pixmapPainter2.drawPath(rectPath); + + p.drawPixmap(this->rect(), pixmap, pixmap.rect()); + p.save(); + QColor color = qApp->palette().color(QPalette::Base); + color.setAlphaF(tranSparency); + p.fillPath(rectPath, color); + p.restore(); + QWidget::paintEvent(event); +} diff --git a/src/widget.h b/src/widget.h new file mode 100644 index 0000000..26a9363 --- /dev/null +++ b/src/widget.h @@ -0,0 +1,185 @@ +/* +* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include "clipboardpluginiface.h" +#include "sidebarSmallPluginInterface.h" +#include "mostgrandwidget.h" +#include "sidebarDbusService.h" + +#define TRAY_ICON ":/data/images/kylin-tool-box.svg" +#define TRAY_NULL_ICON ":/data/images/kylin-tool-box-null.svg" +#define SETTING_ICON ":/res/x/setup.png" + +#define PANEL_DBUS_SERVICE "com.ukui.panel.desktop" +#define PANEL_DBUS_PATH "/" +#define PANEL_DBUS_INTERFACE "com.ukui.panel.desktop" +#define UKUI_TRANSPARENCY_SETTING "org.ukui.control-center.personalise" +#define UKUI_PANEL_SETTING "org.ukui.panel.settings" + +#define ENV_X11 "x11" +#define ENV_WAYLAND "wayland" +#define ENV_XDG_SESSION_TYPE "XDG_SESSION_TYPE" + +#define DBUS_NAME "org.ukui.SettingsDaemon" +#define DBUS_PATH "/org/ukui/SettingsDaemon/wayland" +#define DBUS_INTERFACE "org.ukui.SettingsDaemon.wayland" + +#define CLIPBOARD_HEIGHT 385 + +extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); + +class QGroupBox; +class QGridLayout; +class QVBoxLayout; + +class Widget : public QWidget +{ + Q_OBJECT + + //申明该类有D-BUS服务接口 + Q_CLASSINFO("D-Bus Interface", "com.ukui.panel.sidebar.value") + +public: + explicit Widget(QWidget *parent = nullptr); + + ~Widget(); + enum PanelStatePosition + { + PanelDown = 0, + PanelUp, + PanelLeft, + PanelRight + }; + //主界面 + void initTrayIcon(); // 初始化托盘显示 + void registerDbusService(); // 注册Dbus服务 + void startBackgroundFunction(); // 初始化功能 + void clickTrayFunction(QSystemTrayIcon::ActivationReason reason); // 托盘点击处理事件 + void initTranslation(); // 初始化翻译 + void initAimation(); // 初始化动画 + void initOsSiteXY(); // 初始化使用qt接口初始化接口 + void showAnimation(); // show动作 + void hideAnimation(); // hide动作 + void initDesktopPrimary(); // 初始化分辨率和信号连接 + void initPanelDbusGsetting(); // 初始化与任务栏gsetting和dbus + int ListenClipboardSignal(); // 监听剪贴板发送的信号 + int connectTaskBarDbus(); // 连接任务栏dbus接口,获取任务栏高度 + bool initHuaWeiDbus(); // 初始化华为990专用dbus + int getScreenGeometry(QString methodName); // 华为990获取屏幕高度 + int getPanelSite(); // 获取任务栏位置 + int setClipBoardWidgetScaleFactor(); // 获取通知中心下半部分高度比例系数 + + + //系统托盘 + void createAction(); // 连接信号和槽函数,设置其动作; + void createSystray(); // 设置menu界面、添加动作 和 创建sysytray实例 + void setIcon(QIcon icon); // 设置图标和提示信息; + void iconActivated(QSystemTrayIcon::ActivationReason reason); // 获取点击事件 + bool loadNotificationPlugin(); // 加载通知中心插件 + void ModifyScreenNeeds(); // 修改屏幕分辨率或者主屏需要做的事情 + void GetsAvailableAreaScreen(); // 获取屏幕可用区域高度 + void MostGrandWidgetCoordinates(); // 根据任务栏位置调整侧边栏位置 + void InitializeHomeScreenGeometry(); // 初始化主屏的X坐标 + void setAllWidgetFont(); // 监听gsetting,修改所有窗口的字体 + bool oneShotBool = false ; + bool sidebarState = false; // 展开状态:true-展开 + +protected: + bool eventFilter(QObject *obj, QEvent *event); // 设置过滤事件 + void paintEvent(QPaintEvent *event); // 设置主题窗口背景颜色 + +private: + //主界面 + QVBoxLayout* m_pMainQVBoxLayout; // 主界面垂直布局器 + QDBusInterface* m_pServiceInterface; // 获取任务栏的高度 + QDBusInterface* m_pDbusXrandInter=nullptr; // 华为990dbus接口 + bool m_bHWdbusExit; // 华为dbus接口是否存在 + bool m_bShowFlag = false; // 控制托盘栏点击事件的标志位 + bool m_bClipboardFlag = true; // 剪贴板编辑框打开和关闭时控制侧边栏是否关闭 + bool m_winFlag = false; + int m_nScreenWidth; // 屏幕分辨率的宽 + int m_nScreenHeight; // 屏幕分辨率的高 + int m_nScreen_x; // 主屏的起始坐标X + int m_nScreen_y; // 主屏的起始坐标Y + int m_pPeonySite; // 任务栏位置 + + bool m_bIconActivatedState = true; //记录托盘启动方式 + + QObject* m_pNotificationPluginObject; // 通知中心插件对象 + + QTranslator *m_pTranslator; + QPropertyAnimation *m_pAnimationShowSidebarWidget; + QPropertyAnimation *m_pAnimationHideSidebarWidget; + QDesktopWidget *m_pDeskWgt; // 桌面问题 + QGSettings *m_pPanelSetting = nullptr; + + //快捷操作面板 + ClipboardInterface* m_pSidebarClipboard; // 侧边栏剪贴板指针 + SidebarClipBoardSignal* m_pSidebarSignal; // 剪贴板通信类 + + //系统托盘 + QSystemTrayIcon* trayIcon; + QMenu* trayIconMenu; + QAction* Open; + QAction* OpenSetUp; + + QGSettings *m_pTransparency; // 插件的界面的透明度 + + SidebarDbusService* dbusService; + + void hideSidebar(); + void showSidebar(); + +private slots : + void onResolutionChanged(const QRect argc); // 当改变屏幕分辨率时重新获取屏幕分辨率 + void onNewNotification(); // 当没展开时,来了新通知才提示 + void hideAnimationFinish(); // 隐藏动画完成 + void showAnimationFinish(); // 展开动画完成 + void showAnimationAction(const QVariant &value); // 展开动画开始 + void primaryScreenChangedSLot(); // 主屏发生变化 + void ClipboardShowSlots(); // 接受剪贴板信号,将boll值m_bClipboardFlag置为false; + void ClipboardHideSlots(); // 接受剪贴板信号,将boll值m_bClipboardFlag置为true; + void screenCountChangedSlots(int count); // 屏幕数量改变时对应槽函数 + void OpenSidebarSlots(); // 打开侧边栏 + void OpenControlCenterSettings(); // 打开控制中心的通知中心 + void ClickPanelHideSidebarSlots(); // 左键点击任务栏时隐藏侧边栏 + void updateSmallPluginsClipboardWidget(); // 切换主题时,定时器槽函数 + void bootOptionsFilter(QString opt); // 过滤当前的终端命令 + void XkbEventsPress(const QString &keycode); // 键盘按键按下事件 + void XkbEventsRelease(const QString &keycode); // 键盘按键弹出事件 + void priScreenChanged(int x, int y, int width, int height); // hw990屏幕分辨率变化后 + +signals: + void startRun(QSystemTrayIcon::ActivationReason reason); + void animationAction(const uint time, const int distance); +}; + +#endif // WIDGET_H diff --git a/translations/clean-translated-resources.sh b/translations/clean-translated-resources.sh new file mode 100755 index 0000000..09e834f --- /dev/null +++ b/translations/clean-translated-resources.sh @@ -0,0 +1,7 @@ +echo "clean qm files..." +for file in $(dirname $0)/*/*.qm +do + echo "delete $file" + rm -f ${file} +done +echo "done" diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo.qm b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo.qm new file mode 100644 index 0000000..434a1be Binary files /dev/null and b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo.qm differ diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo.ts b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo.ts new file mode 100644 index 0000000..f3915db --- /dev/null +++ b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo.ts @@ -0,0 +1,133 @@ + + + + + QObject + + + Are you sure empty your clipboard history? + + + + + Don't ask + + + + + + Confirm + + + + + + Cancel + + + + + Pop + + + + + EditButton + + + + + Remove + + + + + Cancel the fixed + + + + + edit box + + + + + Edit + + + + + ClipBoard + + + + + Show the folder children as icons. + + + + + QWidgetTextControl + + &Undo + ཕྱིར་འཐེན། + ཕྱིར་འཐེན། + + + &Redo + སླར་གསོ། + སླར་གསོ། + + + Cu&t + དྲས་སྦྱར་ + དྲས་སྦྱར་ + + + &Copy + འདྲ་བཟོ་ + འདྲ་བཟོ་ + + + Copy &Link Location + འདྲ་ཕབ་འབྲེལ་མཐུད། + འདྲ་ཕབ་འབྲེལ་མཐུད། + + + &Paste + སྦྱར་བ་ + སྦྱར་བ་ + + + Delete + སུབ་པ་ + སུབ་པ་ + + + Select All + ཡོངས་འདེམས་ + ཡོངས་འདེམས་ + + + + SearchWidgetItemContent + + + Clear + + + + + search... + + + + + SidebarClipboardPlugin + + + No clip content + + + + diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo_CN.qm b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo_CN.qm new file mode 100644 index 0000000..df014c2 Binary files /dev/null and b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo_CN.qm differ diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo_CN.ts b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo_CN.ts new file mode 100644 index 0000000..e03d165 --- /dev/null +++ b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_bo_CN.ts @@ -0,0 +1,73 @@ + + + + + QObject + + Pop + དར་ཁྱབ་ + + + Edit + རྩོམ་སྒྲིག + + + Don't ask + འདྲི་ཞིབ་མི་བྱེད་པ། + + + Cancel + མེད་པར་བཟོ་བ + + + Remove + བསུབ་པ། + + + EditButton + རྩོམ་སྒྲིག + + + Confirm + གཏན་འཁེལ། + + + edit box + རྩོམ་སྒྲིག་སྒྲོམ། + + + Are you sure empty your clipboard history? + དྲས་སྦྱར་པང་གི་ལོ་རྒྱུས་གཙང་སེལ་བཟོའམ། + + + Cancel the fixed + གཏན་འཁེལ་མི་བྱེད་པ། + + + ClipBoard + + + + Show the folder children as icons. + + + + + SearchWidgetItemContent + + Clear + གཙང་སེལ། + + + search... + འཚོལ་བཤེར། ... + + + + SidebarClipboardPlugin + + No clip content + དྲས་སྦྱར་ནང་དོན་མི་འདུག + + + diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_fr.ts b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_fr.ts new file mode 100644 index 0000000..5f7dde0 --- /dev/null +++ b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_fr.ts @@ -0,0 +1,136 @@ + + + + + QObject + + + Are you sure empty your clipboard history? + Êtes-vous sûr de vider l'historique de votre presse-papiers ? + + + + Don't ask + Ne pas demander + + + + + Confirm + Confirmer + + + + + Cancel + Annuler + + + + Pop + Pop + + + + EditButton + Modifier bouton + + + + Remove + Retirer + + + + Cancel the fixed + Annuler le fixe + + + + Edit + Éditer + + + + ClipBoard + Presse-papier + + + + Show the folder children as icons. + Afficher les enfants du dossier sous forme d'icônes. + + + + SearchWidgetItemContent + + + Clear + Effacer + + + + search... + chercher... + + + + SidebarClipboardPlugin + + + No clip content + Aucun contenu dans le presse-papiers + + + + QWidgetTextControl + + + &Undo + ཕྱིར་འཐེན། + &Annuler + + + + &Redo + སླར་གསོ། + &Rétablir + + + + Cu&t + དྲས་སྦྱར་ + Cou&per + + + + &Copy + འདྲ་བཟོ་ + &Copier + + + + Copy &Link Location + འདྲ་ཕབ་འབྲེལ་མཐུད། + Copier l'emplacement du &lien + + + + &Paste + སྦྱར་བ་ + &Coller + + + + Delete + སུབ་པ་ + Effacer + + + + Select All + ཡོངས་འདེམས་ + Tout sélectionner + + + diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_tr.qm b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_tr.qm new file mode 100644 index 0000000..919c05b Binary files /dev/null and b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_tr.qm differ diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_tr.ts b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_tr.ts new file mode 100644 index 0000000..d86d3a2 --- /dev/null +++ b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_tr.ts @@ -0,0 +1,133 @@ + + + + + QObject + + + Are you sure empty your clipboard history? + Pano geçmişinizi boşalttığınızdan emin misiniz? + + + + Don't ask + Sorma + + + + + Confirm + Onayla + + + + + Cancel + İptal + + + + Pop + + + + + EditButton + + + + + Remove + Çıkar + + + + Cancel the fixed + Düzeltmeyi iptal et + + + + edit box + + + + + Edit + Düzenle + + + + ClipBoard + + + + + Show the folder children as icons. + Klasörleri simgeler olarak gösterin. + + + + QWidgetTextControl + + &Undo + İptal Et + İptal Et + + + &Redo + onarmak + onarmak + + + Cu&t + Kes ve yapıştır + Kes ve yapıştır + + + &Copy + İ kopyala + İ kopyala + + + Copy &Link Location + Bağlantıyı kopyala + Bağlantıyı kopyala + + + &Paste + Yapıştırmak + Yapıştırmak + + + Delete + silmek + silmek + + + Select All + hepsini seç + hepsini seç + + + + SearchWidgetItemContent + + + Clear + Temizle + + + + search... + Ara... + + + + SidebarClipboardPlugin + + + No clip content + Klip içeriği yok + + + diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_zh_CN.qm b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_zh_CN.qm new file mode 100644 index 0000000..fbdbc41 Binary files /dev/null and b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_zh_CN.qm differ diff --git a/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_zh_CN.ts b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_zh_CN.ts new file mode 100644 index 0000000..d20b3ee --- /dev/null +++ b/translations/ukui-sidebar-clipboard/ukui-sidebar-clipboard_zh_CN.ts @@ -0,0 +1,133 @@ + + + + + QObject + + + Are you sure empty your clipboard history? + 确认要清空剪贴板历史吗? + + + + Don't ask + 不再询问 + + + + + Confirm + 确认 + + + + + Cancel + 取消 + + + + Pop + 固定 + + + + EditButton + 编辑 + + + + Remove + 删除 + + + + Cancel the fixed + 取消固定 + + + + edit box + 编辑框 + + + + Edit + 编辑 + + + + ClipBoard + + + + + Show the folder children as icons. + + + + + QWidgetTextControl + + &Undo + 撤消 + 撤消 + + + &Redo + 恢复 + 恢复 + + + Cu&t + 剪贴 + 剪贴 + + + &Copy + 复制 + 复制 + + + Copy &Link Location + 复制链接 + 复制链接 + + + &Paste + 粘贴 + 粘贴 + + + Delete + 删除 + 删除 + + + Select All + 全选 + 全选 + + + + SearchWidgetItemContent + + + Clear + 清除 + + + + search... + 搜索... + + + + SidebarClipboardPlugin + + + No clip content + 无剪贴内容 + + + diff --git a/translations/ukui-sidebar-notification/ukui-sidebar-notification_bo_CN.qm b/translations/ukui-sidebar-notification/ukui-sidebar-notification_bo_CN.qm new file mode 100644 index 0000000..20ae571 Binary files /dev/null and b/translations/ukui-sidebar-notification/ukui-sidebar-notification_bo_CN.qm differ diff --git a/translations/ukui-sidebar-notification/ukui-sidebar-notification_bo_CN.ts b/translations/ukui-sidebar-notification/ukui-sidebar-notification_bo_CN.ts new file mode 100644 index 0000000..aada212 --- /dev/null +++ b/translations/ukui-sidebar-notification/ukui-sidebar-notification_bo_CN.ts @@ -0,0 +1,69 @@ + + + + + QObject + + Important notice + གལ་ཆེའི་བརྡ་འཕྲིན། + + + Clean up + གཙང་བཤེར། + + + Set up + སྒྲིག་འགོད། + + + Unimportant notice + གལ་མི་ཆེ་བའི་བརྡ་འཕྲིན། + + + No unimportant notice + གལ་མི་ཆེ་བའི་བརྡ་འཕྲིན་མེད། + + + Notification center + བརྡ་འཕྲིན་ལྟེ་གནས། + + + No new notifications + བརྡ་འཕྲིན་གསར་བ་མེད། + + + fold + + + + + SingleMsg + + now + ད་ལྟ། + + + In addition + ད་དུང་ཡོད། + + + notification + བརྡ་ཐོ་འཆར་བ།:(_N) + + + Yesterday + ཁ་སང་། + + + + TakeInBoxToolButton + + Quit unimportant news + གལ་མི་ཆེ་བའི་བརྡ་འཕྲིན་སྒོ་གཏན་པ། + + + Enter unimportant news + གལ་མི་ཆེ་བའི་བརྡ་འཕྲིན་ལ་གཟིགས་པ། + + + diff --git a/translations/ukui-sidebar-notification/ukui-sidebar-notification_fr.ts b/translations/ukui-sidebar-notification/ukui-sidebar-notification_fr.ts new file mode 100644 index 0000000..39abc9a --- /dev/null +++ b/translations/ukui-sidebar-notification/ukui-sidebar-notification_fr.ts @@ -0,0 +1,83 @@ + + + + + QObject + + + Notification center + Centre de notification + + + + + Important notice + Avis important + + + + Clean up + Nettoyer + + + + Set up + Installer + + + + No new notifications + pas de nouvelles notifications + + + + No unimportant notice + Aucun avis sans importance + + + + Unimportant notice + Avis sans importance + + + + SingleMsg + + + now + maintenant + + + + Yesterday + Hier + + + + In addition + En outre + + + + notification + notification + + + In addition + Tür + + + + TakeInBoxToolButton + + + Enter unimportant news + Entrer des nouvelles sans importance + + + + Quit unimportant news + Quitter les nouvelles sans importance + + + diff --git a/translations/ukui-sidebar-notification/ukui-sidebar-notification_tr.qm b/translations/ukui-sidebar-notification/ukui-sidebar-notification_tr.qm new file mode 100644 index 0000000..373cdc1 Binary files /dev/null and b/translations/ukui-sidebar-notification/ukui-sidebar-notification_tr.qm differ diff --git a/translations/ukui-sidebar-notification/ukui-sidebar-notification_tr.ts b/translations/ukui-sidebar-notification/ukui-sidebar-notification_tr.ts new file mode 100644 index 0000000..6e66817 --- /dev/null +++ b/translations/ukui-sidebar-notification/ukui-sidebar-notification_tr.ts @@ -0,0 +1,88 @@ + + + + + QObject + + + Notification center + Bildirim Merkezi + + + + + Important notice + Önemli Uyarı + + + + Clean up + Temizle + + + + Set up + Kur + + + + No new notifications + Yeni bildirim yok + + + + No unimportant notice + Önemsiz bildirim yok + + + + Unimportant notice + Önemsiz Bildirim + + + + fold + + + + + SingleMsg + + + now + Şimdi + + + + Yesterday + Dün + + + + In addition + Ek olarak + + + + notification + Bildirim + + + In addition + Tür + + + + TakeInBoxToolButton + + + Enter unimportant news + Önemsiz haberlere gir + + + + Quit unimportant news + Önemsiz haberlerden çık + + + diff --git a/translations/ukui-sidebar-notification/ukui-sidebar-notification_zh_CN.qm b/translations/ukui-sidebar-notification/ukui-sidebar-notification_zh_CN.qm new file mode 100644 index 0000000..2fabd33 Binary files /dev/null and b/translations/ukui-sidebar-notification/ukui-sidebar-notification_zh_CN.qm differ diff --git a/translations/ukui-sidebar-notification/ukui-sidebar-notification_zh_CN.ts b/translations/ukui-sidebar-notification/ukui-sidebar-notification_zh_CN.ts new file mode 100644 index 0000000..36ecbd2 --- /dev/null +++ b/translations/ukui-sidebar-notification/ukui-sidebar-notification_zh_CN.ts @@ -0,0 +1,88 @@ + + + + + QObject + + + Notification center + 通知中心 + + + + + Important notice + 重要的通知 + + + + Clean up + 清空 + + + + Set up + 设置 + + + + No new notifications + 没有新通知 + + + + No unimportant notice + 没有不重要的通知 + + + + Unimportant notice + 不重要的通知 + + + + fold + 折叠 + + + + SingleMsg + + + now + 现在 + + + + Yesterday + 昨天 + + + + In addition + 还有 + + + + notification + 则通知 + + + In addition + 还有 + + + + TakeInBoxToolButton + + + Enter unimportant news + 进入不重要通知 + + + + Quit unimportant news + 退出不重要通知 + + + diff --git a/translations/ukui-sidebar_bo.qm b/translations/ukui-sidebar_bo.qm new file mode 100644 index 0000000..be651ee --- /dev/null +++ b/translations/ukui-sidebar_bo.qm @@ -0,0 +1 @@ + + + + + QObject + + + ukui-sidebar is already running! + + + + + Display debug information + + + + + show sidebar widget + + + + + 折叠 + + + + + 展开 + + + + + Open + + + + + Set up notification center + + + + + Widget + + + Sidebar + + + + + sidebarPluginsWidgets + + + Clipboard + + + + + Plugins + + + + diff --git a/translations/ukui-sidebar_bo_CN.qm b/translations/ukui-sidebar_bo_CN.qm new file mode 100644 index 0000000..7bcc9b5 Binary files /dev/null and b/translations/ukui-sidebar_bo_CN.qm differ diff --git a/translations/ukui-sidebar_bo_CN.ts b/translations/ukui-sidebar_bo_CN.ts new file mode 100644 index 0000000..50b147c --- /dev/null +++ b/translations/ukui-sidebar_bo_CN.ts @@ -0,0 +1,53 @@ + + + + + QObject + + Open + ཁ་འབྱེད། + + + Display debug information + བསྒྱུར་བཅོས་ཆ་འཕྲིན་མངོན་དུ་བཅུག་པ། + + + Set up notification center + བརྡ་གཏོང་ལྟེ་གནས་ཀྱི་སྒྲིག་འགོད། + + + 折叠 + + + + ukui-sidebar is already running! + + + + show sidebar widget + + + + 展开 + + + + + Widget + + Sidebar + ཟུར་གྱི་མཐའ་བྱང་། + + + + sidebarPluginsWidgets + + Clipboard + དྲས་སྦྱར་ངོས་པང། + + + Plugins + བསྒར་ལྷུ། + + + diff --git a/translations/ukui-sidebar_fr.ts b/translations/ukui-sidebar_fr.ts new file mode 100644 index 0000000..554c55f --- /dev/null +++ b/translations/ukui-sidebar_fr.ts @@ -0,0 +1,53 @@ + + + + + QObject + + + Display debug information + Afficher les informations de débogage + + + + Open + Ouvrir + + + + Set up notification center + Configurer le centre de notification + + + + 折叠 + Plier + + + + 展开 + Se dérouler + + + + Widget + + + Sidebar + Barre latérale + + + + sidebarPluginsWidgets + + + Clipboard + Presse-papiers + + + + Plugins + Plugins + + + diff --git a/translations/ukui-sidebar_tr.qm b/translations/ukui-sidebar_tr.qm new file mode 100644 index 0000000..cef10d0 Binary files /dev/null and b/translations/ukui-sidebar_tr.qm differ diff --git a/translations/ukui-sidebar_tr.ts b/translations/ukui-sidebar_tr.ts new file mode 100644 index 0000000..df3d878 --- /dev/null +++ b/translations/ukui-sidebar_tr.ts @@ -0,0 +1,79 @@ + + + + + QObject + + + ukui-sidebar is already running! + + + + + Display debug information + Hata Bildirimlerini Göster + + + + show sidebar widget + + + + + Open + + + + + Set up notification center + Bildirim Merkezini Ayarla + + + + 折叠 + Ayarla + + + + 展开 + Sil + + + + Widget + + ClipBoard + Pano + + + + Sidebar + Yan Panel + + + + sidebarPluginsWidgets + + + Clipboard + Pano + + + + Plugins + Eklentiler + + + Notebook + Not Defteri + + + Alarm clock + Çalar Saat + + + Feedback + Geri Bildirim + + + diff --git a/translations/ukui-sidebar_zh_CN.qm b/translations/ukui-sidebar_zh_CN.qm new file mode 100644 index 0000000..4eea44d Binary files /dev/null and b/translations/ukui-sidebar_zh_CN.qm differ diff --git a/translations/ukui-sidebar_zh_CN.ts b/translations/ukui-sidebar_zh_CN.ts new file mode 100644 index 0000000..398230a --- /dev/null +++ b/translations/ukui-sidebar_zh_CN.ts @@ -0,0 +1,79 @@ + + + + + QObject + + + ukui-sidebar is already running! + + + + + Display debug information + + + + + show sidebar widget + + + + + Open + 打开 + + + + Set up notification center + 设置通知中心 + + + + 折叠 + + + + + 展开 + + + + + Widget + + ClipBoard + 剪贴板 + + + + Sidebar + 侧边栏 + + + + sidebarPluginsWidgets + + + Clipboard + 剪贴板 + + + + Plugins + 小插件 + + + Notebook + 笔记本 + + + Alarm clock + 闹钟 + + + Feedback + 用户反馈 + + + diff --git a/translations/update-translations.sh b/translations/update-translations.sh new file mode 100755 index 0000000..c4dafce --- /dev/null +++ b/translations/update-translations.sh @@ -0,0 +1,14 @@ +echo "update translations..." +lupdate ./src/plugins/notification_plugin/notification_plugin.pro + +echo "generate new translate resources files" +for file in $(dirname $0)/*/*.ts +do + ts="*.ts" + qm="*.qm" + target=${file%.*}.qm + echo ${target} + echo "release $file $target" + lrelease $file $target +done +echo "done" diff --git a/ukui-sidebar.pro b/ukui-sidebar.pro new file mode 100644 index 0000000..1b28665 --- /dev/null +++ b/ukui-sidebar.pro @@ -0,0 +1,6 @@ +#! [0] +DEFINES += PLATFORM_TYPE +TEMPLATE = subdirs +SUBDIRS = ./src/ukui-sidebar-core.pro \ + ./src/plugins/ukui-sidebar-notification/ukui-sidebar-notification.pro \ + ./src/plugins/ukui-sidebar-clipboard/ukui-sidebar-clipboard.pro \